Thursday 20 April 2017

Campaign Management Process


To all the folks who want to know what a campaign is at a high level and how salesforce 
supports campaigns. Below screen shots are for you.












































































































































































































Above information is collected from below link.

Lead and Campaign Management in a NutShell

Lead Management Process


To all folks who need a summary of Lead management process and benefits of designing lead management system. Please go through below points.

There are two main aspects for Lead Management Process

1) Quality of Leads ( % of Leads accepted and working vs % of Leads rejected and disqualified)
2) Conversion of Leads ( What % of Leads are converted and what was the time frame)

Lead Management - Life Cycle :

There are two main components to determine Lead Management Life Cycle

Lead Status : Open/Contacted/Working, Closed/Converted, Nurture, Dead

Lead Source : Where did the lead come from? Web / Trade Show, Word of Mouth, Advertising, Webinar


Lead Stage  - Custom Field

Lead stage defines where the Lead is in the Lead life cycle

  • Marketing Qualified - Did marketing consider this a Lead good enough for sales to work on?
  • Sales Rejected - Did sales decide this lead was not a good lead to work on and send back to marketing for nurture or consider it dead
  • Sales Accepted - Did sales agree to work on this lead
  • Sales Qualified - Sales has worked this lead and considers it qualified enough to develop an opportunity
  • Sales Disqualify a lead saying there is no opportunity of this lead
Lead Management Different Stages













































Lead Score - Custom Field

Defines the priority a lead should be given

Below are the parameters based on which lead score can be given

  • Quality - How complete is the data in the lead record?
  • Aging - Is the lead more then 30 days?
  • BANT - Is there a Budget, Need, Authority and a Timeframe to purchase


Lead Scoring

Quality - Score 5-1

If all the information related to lead is filled out then it is a quality lead and higher score can be given

Aging - Score 5-1

New leads are always given higher score than once which are sitting on the bench for long

BANT Cumulative Score

Budget - 5-1
If some one doesn't have the budget then such a lead will be given low score. But its not a bad lead.

Authority = 1- Yes 0 - No
Sales person suspecting the prospect customer whether he will be able to generate business or not.

Need = 1 - yes 0 - No

Time Frame =

4 - Less then 3 months
3 - 3 monts - 6 months
2 - 6 months - 1 year
1 - More than 1 year























From the above screen based on the score given to a lead the Sales can either qualify or disqualify a lead.























By following Lead management process, We will be able to address below points.
  • Monitor quality of leads
  • Gauge velocity of leads
  • Identify bottlenecks in the process
  • Have an opportunity to make improvements and increase lead conversion
  • How many days each lead has been in each stage?
  • How long it takes to move a lead from Marketing qualified to Sales accepted Lead?
  • This will also allow to measure the performance of the sales rep to understand how much time the sales rep is taking to  move the lead into different stages








Wednesday 12 April 2017

jQuery ajax call to node.js service



Below is the complete html code with jQuery ajax call to consume node.js service


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Forecasting - Bottoms Up(T&M)</title>
<link rel="stylesheet" type="text/css" href="css/easyui.css">
<link rel="stylesheet" type="text/css" href="css/icon.css">
<link rel="stylesheet" type="text/css" href="css/demo.css">
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.easyui.min.js"></script>
<style>
a {
display: inline-block;
color: white;
text-align: center;
padding: 4px 4px;
text-decoration: none;
background-color: #2c64b2;
}
a:hover {
color: white;
background-color: #827f7b;
}
</style>
</head>
<body>
<script type="text/javascript">
var editIndex = undefined;
function endEditing(){
if (editIndex == undefined){return true}
if ($('#dg').datagrid('validateRow', editIndex)){
$('#dg').datagrid('endEdit', editIndex);
editIndex = undefined;
return true;
} else {
return false;
}
}
function onClickCell(index, field){
if (editIndex != index){
if (endEditing()){
$('#dg').datagrid('selectRow', index)
.datagrid('beginEdit', index);
var ed = $('#dg').datagrid('getEditor', {index:index,field:field});
if (ed){
($(ed.target).data('textbox') ? $(ed.target).textbox('textbox') : $(ed.target)).focus();
}
editIndex = index;
} else {
setTimeout(function(){
$('#dg').datagrid('selectRow', editIndex);
},0);
}
}
}
function onEndEdit(index, row){
var ed = $(this).datagrid('getEditor', {
index: index,
field: 'ID'
});
row.JanTotalBilling = row.Rate * row.JanActualHours;
row.FebTotalBilling = row.Rate * row.FebActualHours;
row.MarTotalBilling = row.Rate * row.MarActualHours;
row.AprTotalBilling = row.Rate * row.AprActualHours;
row.MayTotalBilling = row.Rate * row.MayActualHours;
row.JunTotalBilling = row.Rate * row.JunActualHours;
row.JulTotalBilling = row.Rate * row.JulActualHours;
row.AugTotalBilling = row.Rate * row.AugActualHours;
row.SepTotalBilling = row.Rate * row.SepActualHours;
row.OctTotalBilling = row.Rate * row.OctActualHours;
row.NovTotalBilling = row.Rate * row.NovActualHours;
row.DecTotalBilling = row.Rate * row.DecActualHours;
}
        function actionApplyFilters(){

$('#dg').datagrid({
url:'http://samplesite.com:8182/BottomsUpBTMFiltered?parentCustomer='+$( "#parentCustomerId option:selected" ).text()+'&verticalShortname='+$( "#verticalShortnameId option:selected" ).text()
});

        }
function actionClearAllFilters(){
$.messager.alert('Clear All Filters');
        }
        function actionSubmit(){

var rows = $('#dg').datagrid('getChanges');

if(!jQuery.isEmptyObject(rows)){
json = JSON.stringify(rows);
console.log('json before submit' + json);
$.ajax
({
type: "POST",
url: "http://samplesite.com:8182/BottomsUpBTM_save",
crossDomain:true,
dataType: 'json',
contentType: 'application/json',
data:json
}).done(function (data) {

console.log('inside done method ' + typeof data);
console.log('inside done method ' + JSON.stringify(data));

if(!jQuery.isEmptyObject(data)){

if(data.status == "SUCCESS"){
console.log("successfully saved");
$.messager.alert('SUCCESS','<p style="color:green;font-weight:bold;text-align:center">Data Saved !!!<p>');


}
}
});

}else{
$.messager.alert('ERROR','<p style="color:red;font-weight:bold">Modify rows and step off to save...<p>');
}


        }

$(document).ready(function(){


$.urlParam = function(name){
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
if (results==null){
return null;
}
else{
return results[1] || 0;
}
}
var loginid = $.urlParam('loginid');
$.ajax
({
url: "http://samplesite.com:8182/PicklistValuesFiltered?loginid="+loginid,
crossDomain:true,
dataType: 'json',
contentType: 'application/json'
}).done(function (data) {
var pcArray = data;
$.each(pcArray,function(index,value){
$('#parentCustomerId').append($('<option>', {
value: value.parentcustomer,
text : value.parentcustomer
}));
});

   });

$("#parentCustomerId").change(function(){
$.ajax
({
url: "http://samplesite.com:8182/PickVerticalShortName?parentcustomer="+$( "#parentCustomerId option:selected" ).text(),
crossDomain:true,
dataType: 'json',
contentType: 'application/json'
}).done(function (data){
var vsArray = data;
$('#verticalShortnameId').find('option').remove().end();
$.each(vsArray,function(index,value){
$('#verticalShortnameId').append($('<option>',{
value: value.Verticalshortname,
text : value.Verticalshortname
}));
});
  });

   });

   });
</script>
<table width="100%"> <tr>
<td align="left"><h2>Forecasting - Bottoms Up(T&M)</h2></td>
<td align="right"><img src="images/Cognizant_Logo.png" alt="logo View"></td>
</tr>
</table>
<table align="center">
<tr>
<td><a href="BottomsUpBTM.html">T&M Adjustments</a></td>
<td><a href="BottomsUpBTMView.html">T&M View</a></td>
<td><a href="BottomsUpBFB.html">Fixed Bid Adjustments</a></td>
<td><a href="BottomsUpBFBView.html">Fixed BidView</a></td>
<td><a href="BottomsUpVSCForecast.html">Bottoms Up vs CForecast</a></td>
<td><a href="WorkingDays.html">Working Days</a></td>
<td><a href="CustomerAccess.html">Customer Access</a></td>
</tr>
</table>
<hr/>
<table width="100%">
<tr>
<td>
<label>Parent Customer:</Label>
<select id="parentCustomerId">
</select>
&nbsp;&nbsp;&nbsp;
<label>Vertical Short Name:</Label>
<select id="verticalShortnameId">
</select>
&nbsp;&nbsp;&nbsp;
<a href="#" class="easyui-linkbutton" onclick="actionApplyFilters()">Apply Filters</a> &nbsp;&nbsp;&nbsp;
<a href="#" class="easyui-linkbutton" onclick="actionClearAllFilters()">Clear All Filters</a>
&nbsp;&nbsp;&nbsp;
<label>Forecasting Month: <B>Mar-2017</B></Label>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<label id="selectRowsMsg"></label>
</td>
</tr>
</table>
<br/>
<table id="dg" class="easyui-datagrid" iconCls="icon-save" title="Utilization Data for Adjustments" style="width:99%;height:450px" sortName="AssociateID" remoteSort="false" sortOrder="asc"
data-options="
iconCls:'icon-edit',
singleSelect:true,
toolbar:'#tb',
method:'get',
onClickCell:onClickCell,
onEndEdit:onEndEdit">
        <thead data-options="frozen:true">
            <tr>
<th data-options="field:'AssociateID',sortable:true">AssociateID</th>
<th data-options="field:'ID',formatter:function(value,row){return row.AssociateName;}">Associate Name</th>
<th data-options="field:'ProjectId'">Project ID</th>
<th data-options="field:'ProjectName',align:'left',sortable:true">Project Name</th>
            </tr>
        </thead>
<thead>
<tr>
<th data-options="field:'Utilizationlocation',align:'left'">Utilization Location</th>
<th data-options="field:'Isonsite',align:'left'">Is Onsite</th>
<th data-options="field:'Projectbillability',align:'left'">Project Billability</th>
<th data-options="field:'CustomerID',align:'left'">Customer Id</th>
<th data-options="field:'Customername',align:'left',sortable:true">Customer Name</th>
<th data-options="field:'HorizontalShortName',align:'left'">HorizontalShortName</th>
<th data-options="field:'ManagerID',align:'right'">ManagerID</th>
<th data-options="field:'ManagerName',align:'right'">ManagerName</th>
<th data-options="field:'AllocationPrecentage',align:'right'">AllocationPrecentage</th>
<th data-options="field:'Status',align:'left'">Status</th>
<th data-options="field:'BU',align:'right'">BU</th>
<th data-options="field:'AllocationStartDate',align:'left'">Allocation Start Date</th>
<th data-options="field:'AllocationEndDate',align:'left'">Allocation End Date</th>
<th data-options="field:'ActualAllocationStartDate',align:'left',editor:{type:'datebox'}">Actual Allocation Start Date</th>
<th data-options="field:'ActualAllocationEndDate',align:'left',editor:{type:'datebox'}">Actual Allocation end Date</th>
<th data-options="field:'Rate',align:'right',editor:{type:'numberbox',options:{precision:1}}">Rate</th>
<th data-options="field:'JanActualHours',align:'right',editor:{type:'numberbox',options:{precision:1}}">Jan hours</th>
<th data-options="field:'JanTotalBilling'">Jan Amount</th>
<th data-options="field:'FebActualHours',align:'right',editor:{type:'numberbox',options:{precision:1}}">Feb hours</th>
<th data-options="field:'FebTotalBilling'">Feb Amount</th>
<th data-options="field:'MarActualHours',align:'right',editor:{type:'numberbox',options:{precision:1}}">Mar hours</th>
<th data-options="field:'MarTotalBilling'">Mar Amount</th>
<th data-options="field:'AprActualHours',align:'right',editor:{type:'numberbox',options:{precision:1}}">Apr hours</th>
<th data-options="field:'AprTotalBilling'">Apr Amount</th>
<th data-options="field:'MayActualHours',align:'right',editor:{type:'numberbox',options:{precision:1}}">May hours</th>
<th data-options="field:'MayTotalBilling'">May Amount</th>
<th data-options="field:'JunActualHours',align:'right',editor:{type:'numberbox',options:{precision:1}}">Jun hours</th>
<th data-options="field:'JunTotalBilling'">Jun Amount</th>
<th data-options="field:'JulActualHours',align:'right',editor:{type:'numberbox',options:{precision:1}}">Jul hours</th>
<th data-options="field:'JulTotalBilling'">Jul Amount</th>
<th data-options="field:'AugActualHours',align:'right',editor:{type:'numberbox',options:{precision:1}}">Aug hours</th>
<th data-options="field:'AugTotalBilling'">Aug Amount</th>
<th data-options="field:'SepActualHours',align:'right',editor:{type:'numberbox',options:{precision:1}}">Sep hours</th>
<th data-options="field:'SepTotalBilling'">Sep Amount</th>
<th data-options="field:'OctActualHours',align:'right',editor:{type:'numberbox',options:{precision:1}}">Oct hours</th>
<th data-options="field:'OctTotalBilling'">Oct Amount</th>
<th data-options="field:'NovActualHours',align:'right',editor:{type:'numberbox',options:{precision:1}}">Nov hours</th>
<th data-options="field:'NovTotalBilling'">Nov Amount</th>
<th data-options="field:'DecActualHours',align:'right',editor:{type:'numberbox',options:{precision:1}}">Dec hours</th>
<th data-options="field:'DecTotalBilling'">Dec Amount</th>
<th data-options="field:'Comments',align:'right',editor:{type:'textbox',options:{precision:1}}">Comments</th>
</tr>
</thead>
</table>
</table>
<table style="width:100%">
<tr>
<td align="center">
<div style="margin:10px;">
<a href="#" class="easyui-linkbutton" onclick="actionSubmit()">Save</a>
</div>
</td>
</tr>
</table>
</body>
</html>

Salesforce Streaming API



Use Streaming API to receive notifications for changes to Salesforce data that match a SOQL query you define, in a secure and scalable way.

These events can be received by:

• Pages in the Salesforce application.
• Application servers outside of Salesforce.
• Clients outside the Salesforce application.

The sequence of events when using Streaming API is as follows:
1. Create a PushTopic based on a SOQL query. This defines the channel.
2. Clients subscribe to the channel.
3. A record is created, updated, deleted, or undeleted (an event occurs). The changes to that record
are evaluated.
4. If the record changes match the criteria of the PushTopic query, a notification is generated by the
server and received by the subscribed clients.

Streaming API is useful when you want notifications to be pushed from the server to the client based
on criteria that you define. Consider the following applications for Streaming API:

Applications that poll frequently
Applications that have constant polling action against the Salesforce infrastructure, consuming
unnecessary API calls and processing time, would benefit from Streaming API which reduces the
number of requests that return no data.

General notification
Use Streaming API for applications that require general notification of data changes in an organization. This enables you to reduce the number of API calls and improve performance.

Note: You can use Streaming API with any organization as long as you enable the API. This includes
both Salesforce and Database.com organizations.

Push Technology

Push technology, also called the publish/subscribe model, transfers information that is initiated from a server to the client. This type of communication is the opposite of pull technology in which a request for information is made from a client to the server.

The information sent by the server is typically specified in advance. When using Streaming API, you specify the information that the client receives by creating a PushTopic. The client then subscribes to the PushTopic channel and is notified of events that match thePushTopic criteria.

In push technology, the server pushes out information to the client after the client has subscribed to a channel of information. For the client to receive the information, the client must maintain a connection to the server. Streaming API uses the Bayeux protocol and CometD, so the client to server connection is maintained through long polling.


Bayeux Protocol, CometD, and Long Polling

Streaming API uses the Bayeux protocol and CometD for long polling.

• Bayeux is a protocol for transporting asynchronous messages, primarily over HTTP.

• CometD is a scalable HTTP-based event routing bus that uses an AJAX push technology pattern known as Comet. It implements the Bayeux protocol. The Salesforce servers use version 2.0 of CometD.

• Long polling, also called Comet programming, allows emulation of an information push from a server to a client. Similar to a normal poll, the client connects and requests information from the server. However, instead of sending an empty response if information isn't available, the server holds the request and waits until information is available (an event occurs). The server then sends a complete response to the client. The client then immediately re-requests information. The client continually maintains a connection to the server, so it’s always waiting to receive a response. In the case of server timeouts, the client connects again and starts over.

Streaming API supports the following CometD methods:

Method Description:

Connect :  The client connects to the server.
Disconnect :  The client disconnects from the server.
Handshake :  The client performs a handshake with the server and establishes a long polling connection.
Subscribe : The client subscribes to a channel defined by a PushTopic. After the client subscribes, it can receive
messages from that channel. You must successfully call the handshake method before you can
subscribe to a channel.
Unsubscribe :  The client unsubscribes from a channel.


Streaming API Terms


Event : The creation, update, delete, or undelete of a record. Each event might trigger a notification.
Notification : A message in response to an event. The notification is sent to a channel to which one or more clients are subscribed.
PushTopic : A record that you create. The essential element of a PushTopic is the SOQL query. The PushTopic defines a Streaming API channel.

How the Client Connects

Streaming API uses the HTTP/1.1 request-response model and the Bayeux protocol (CometD implementation). A Bayeux client connects
to Streaming API in multiple stages.

1. Sends a handshake request.
2. Sends a subscription request to a channel.
3. Connects using long polling.

The maximum size of the HTTP request post body that the server can accept from the client is 32,768 bytes, for example, when you call
the CometD subscribe or connect methods. If the request message exceeds this size, the following error is returned in the response: 413 Maximum Request Size Exceeded. To keep requests within the size limit, avoid sending multiple messages in a single
request.

The client receives events from the server while it maintains a long-lived connection.

• If the client receives events, it should reconnect immediately to receive the next set of events. If the reconnection doesn't occur within 40 seconds, the server expires the subscription and the connection closes. The client must start over with a handshake and subscribe again.

• If no events are generated and the client is waiting and the server closes the connection, after two minutes the client should reconnect immediately.

If a long-lived connection is lost due to unexpected network disruption, CometD will automatically attempt to reconnect. If this reconnection is successful, clients must re-subscribe, since this new connection has gone through a re-handshake that removes previous subscribers. Clients can listen to the meta/handshake meta channel to receive notifications when a connection is lost and re-established.


Message Reliability

In API version 37.0 and later, Streaming API stores events for 24 hours, enabling you to replay past events. With durable streaming, messages aren’t lost when a client is disconnected or isn’t subscribed. When the client subscribes again, it can fetch past events that are within the 24-hour retention period. The ability to replay past events provides reliable message delivery.


Message Delivery Considerations

Multiple Notifications Within the Same Apex Transaction

In API version 36.0 and earlier, if multiple PushTopic notifications are sent for the same record within the same Apex transaction, only the last notification is sent. The earlier notifications are suppressed. For example, suppose a PushTopic is set up for insertions and updates of contact records, and the PushTopic query selects fieldA. If a contact is inserted and then an Apex trigger updates
fieldA, only the notification for the update is sent. No notification is sent for the contact creation. In API version 37.0 and later, all notifications for the same record in a single transaction are sent, and no notification is suppressed.

Message Durability

Salesforce stores events for 24 hours, so you can retrieve stored events during that retention window. The Streaming API event framework decouples event producers from event consumers. A subscriber can retrieve events at any time and isn’t restricted to listening to events at the time they’re sent.


Pre-Requisites for Streaming API

• The “API Enabled” permission must be enabled for your Developer Edition organization. This permission is enabled by default, but may have been changed by an administrator.

• The “Streaming API” permission must be enabled.

The logged-in user must have “Read” permission on the PushTopic standard object to receive notifications.

• The logged-in user must have “Create” permission on the PushTopic standard object to create and manage PushTopic records.

• The logged-in user must have “Author Apex” permissions to create a PushTopic by using the Developer Console.


Steps for creating push topic

Open the developer console

Click debug  - > Open Execute Anonymous Window.

Paste the following code and click execute

PushTopic pushTopic = new PushTopic();
pushTopic.Name = 'InvoiceStatementUpdates';
pushTopic.Query = 'SELECT Id,Name,Status__c,Description__c from Invoice_Statement__c';
pushTopic.ApiVersion= 38.0;
pushTopic.NotifyForOperationCreate = true;
pushTopic.NotifyForOperationUpdate = true;
pushTopic.NotifyForOperationUndelete = true;
pushTopic.NotifyForOperationDelete = true;
pushTopic.NotifyForFields = 'Referenced';

insert pushTopic;

Because NotifyForOperationCreate, NotifyForOperationUpdate, NotifyForOperationDelete and
NotifyForOperationUndelete are set to true, Streaming API evaluates records that are created, updated, deleted, or undeleted and generates a notification if the record matches the PushTopic query. Because NotifyForFields is set to Referenced, Streaming API will use fields in both the SELECT clause and the WHERE clause to generate a notification. Whenever the fields Name, Status__c, or Description__c are updated, a notification will be generated on this channel.


Example: Interactive Visualforce Page

Step 1: Create an Object

Step 2: Create a PushTopic

1. Open the Developer Console.
2. Click Debug > Open Execute Anonymous Window.


3. In the Enter Apex Code window, paste in the following Apex code, and click Execute.

PushTopic pushTopic = new PushTopic();
pushTopic.Name = 'InvoiceStatementUpdates';
pushTopic.Query = 'SELECT Id, Name, Status__c, Description__c FROM Invoice_Statement__c';
pushTopic.ApiVersion = 38.0;
pushTopic.NotifyForOperationCreate = true;
pushTopic.NotifyForOperationUpdate = true;
pushTopic.NotifyForOperationUndelete = true;
pushTopic.NotifyForOperationDelete = true;
pushTopic.NotifyForFields = 'Referenced';
insert pushTopic;


Step 3: Create the Static Resources


1) Download this static resource .zip file: streaming_api_interactive_visualforce_demo-v25.zip

2) From Setup, enter Static Resources in the Quick Find box, then select Static Resources to add the extracted files with the following names:

cometd.zip : cometd
demo.css : demo_css
demo.js : demo_js
json2.js : json2_js


Step 4: Create a Visualforce Page


<apex:page >

    <apex:includeScript value="{!$Resource.json2_js}" />
    <apex:includeScript value="{!URLFOR($Resource.cometd,'dojo/dojo.js')}" />
    <apex:includeScript value="{!$Resource.demo_js}" />
    <apex:stylesheet value="{!$Resource.demo_css}" />
    
        <script> var token = '{!$Api.Session_ID}';</script>
        
            <div id="demo">
            
                <div id="datastream"></div>
                
                <div id="input">
                
                    <div id="join">
                    
                        <table>
                        
                            <tbody>
                            
                                <tr>
                                    
                                    <td>&nbsp;</td>
                                    
                                    <td> Enter Topic Name </td>
                                    
                                    <td>
                                    
                                        <input id="topic" type="text" />
                                        
                                    </td>
                                    
                                    <td>
                                    
                                        <button id="subscribeButton" class="button">Subscribe</button>
                                        
                                    </td>
                                    
                                    
                                </tr>
                                
                             </tbody>
                          
                        </table>

                    </div>    
                          
                    <div id="joined">

                        <table>
                        
                            <tbody>
                            
                                <tr>
                                
                                    <td>
                                    
                                        <button id="leaveButton" clas="button"> Unsubscribe </button>
                                        
                                    </td>
                                    
                                </tr>
                                
                            </tbody>
                            
                        </table>
                        
                    </div>
                    
                </div>
                
            </div>
            
</apex:page>


Step 5: Test the PushTopic Channel


  1. Load the Visualforce page that you created in a Web browser
  2. In the text box, enter the channel name: /topic/InvoiceStatementUpdates.
  3. Click Subscribe to subscribe to the channel.
  4. Create or modify an InvoiceStatement in a different browser. You should see the event notification appear on the Visualforce page. The output should resemble the following:

{ "event": { "type": "created", "createdDate": "2016-11-30T13:37:52.000+0000" }, "sobject": { "Description__c": "test", "Id": "a002800000rNSJrAAO", "Status__c": "Open", "Name": "INV-0004" } }



Example: Visualforce Page


Step 1: Create an Object

Step 2: Create a PushTopic


1. Open the Developer Console.
2. Click Debug > Open Execute Anonymous Window.


3. In the Enter Apex Code window, paste in the following Apex code, and click Execute.

PushTopic pushTopic = new PushTopic();
pushTopic.Name = 'InvoiceStatementUpdates';
pushTopic.Query = 'SELECT Id, Name, Status__c, Description__c FROM Invoice_Statement__c';
pushTopic.ApiVersion = 38.0;
pushTopic.NotifyForOperationCreate = true;
pushTopic.NotifyForOperationUpdate = true;
pushTopic.NotifyForOperationUndelete = true;
pushTopic.NotifyForOperationDelete = true;
pushTopic.NotifyForFields = 'Referenced';
insert pushTopic;



Step 3: Create the Static Resources

1) Download this static resource .zip file: streaming_api_interactive_visualforce_demo-v25.zip

2) From Setup, enter Static Resources in the Quick Find box, then select Static Resources to add the extracted files with the following names:

cometd.zip : cometd
demo.css : demo_css
demo.js : demo_js
json2.js : json2_js



Step4 : Create a Visualforce Page



<apex:page >

    <apex:includeScript value="{!$Resource.cometd}" />
    <apex:includeScript value="{!$Resource.jquery}" />
    <apex:includeScript value="{!$Resource.json2}" />
    <apex:includeScript value="{!$Resource.jquery_cometd}" />
    
    <script type="text/javascript">
    
    (function($){
    
        $(document).ready(function(){
        
            // Connect to the CometD endpoint
        
            $.cometd.init({
            
                url: window.location.protocol+'//'+window.location.hostname+'/cometd/24.0/',
                requestHeaders:{Authorization: 'OAuth {!$Api.Session_ID}'}
                            
            });
            
            //Subscribe to a topic. JSON-encoded update will be returned
            //in the callback
            
            $.cometd.subscribe('/topic/InvoiceStatementUpdates',function(message){
            
                $('#content').append('<p>Notification: '+
                
                                    'Channel: '+ JSON.stringify(message.channel) + '<br>'+
                                    'Record Name: '+ JSON.stringify(message.data.sobject.Name) + 
                                    '<br>' + 'ID: ' + JSON.stringify(message.data.sobject.Id) + 
                                    '<br>' + 'Event type: ' + JSON.stringify(message.data.event.type) +
                                    '<br>' + 'Created: '+JSON.stringify(message.data.event.createdDate)
                
                                    +'</p>');
            
            });
        
        
        });
    
    
    
    
    
    })(jQuery)
    
    
    function disconnect(){
    
        $.cometd.disconnect();
    
    }
    
    window.onbeforeunload = disconnect;
    
    </script>
    
    
    <body>
    
        <div id="content">
        
            <h1> Streaming API Test Page </h1>
            
            <p> This is a demonstration page for Streaming API. Notifications from the InvoiceStatementUpdates channel will appear here...</p>
        
        
        </div>
    
    
    </body>
    
    </apex:page>

/topic/InvoiceStatementUpdates is the push topic created in step2.


Step 5: Test the PushTopic Channel

1. Load the Visualforce page in a Web browser by using the following URL:

https://myinstance.salesforce.com/apex/StreamingPage where myinstance is the name of your
Salesforce instance, such as na1.


2. Create or modify an InvoiceStatement in a different browser. You should see the event notification appear on the Visualforce page.




Example: Lightning APP


Step 1: Create an Object

Step 2: Create a PushTopic


1. Open the Developer Console.
2. Click Debug > Open Execute Anonymous Window.


3. In the Enter Apex Code window, paste in the following Apex code, and click Execute.

PushTopic pushTopic = new PushTopic();
pushTopic.Name = 'InvoiceStatementUpdates';
pushTopic.Query = 'SELECT Id, Name, Status__c, Description__c FROM Invoice_Statement__c';
pushTopic.ApiVersion = 38.0;
pushTopic.NotifyForOperationCreate = true;
pushTopic.NotifyForOperationUpdate = true;
pushTopic.NotifyForOperationUndelete = true;
pushTopic.NotifyForOperationDelete = true;
pushTopic.NotifyForFields = 'Referenced';
insert pushTopic;



Step 3: Create the Static Resources

1) Download this static resource .zip file: streaming_api_interactive_visualforce_demo-v25.zip

2) From Setup, enter Static Resources in the Quick Find box, then select Static Resources to add the extracted files with the following names:

cometd.zip : cometd
demo.css : demo_css
demo.js : demo_js
json2.js : json2_js



Step4 : Create a Lightning Component

StreamingComp.cmp

<aura:component controller="usersession">
    
<ltng:require scripts="{!join(',',$Resource.cometd,$Resource.jquery,$Resource.json2,$Resource.jquery_cometd)}" afterScriptsLoaded="{!c.doInit}" />

    
    
<lightning:buttonIcon iconName="utility:close" variant="bare" onclick="{! c.handleClick }" alternativeText="Close window." />

    <br />
    <br />
    <div id="content">
        
            <h1> Streaming API Test Page </h1>
            
            <p> This is a demonstration page for Streaming API. Notifications from the InvoiceStatementUpdates channel will appear here...</p>
        
        
    </div>
        
</aura:component>




StreamingComp.js

({

    doInit : function(component, event, helper) {
        
      //j$ = jQuery.noConflict();
     
        
        $(document).ready(function(){         
        
                        
         var sessionaction = component.get("c.getsessionid");
         var usersessionid;
        
        alert('before session call out');
        
        sessionaction.setCallback(this,function(response){
            
           var status = response.getState();
            
            if(status==="SUCCESS"){
                
                console.log(JSON.stringify(response.getReturnValue()));
                
                usersessionid = response.getReturnValue();
                
                console.log('usersessionid : ' +'OAuth '+usersessionid);
                $.cometd.init({
            
                url: window.location.protocol+'//'+window.location.hostname+'/cometd/24.0/',
                requestHeaders:{Authorization: 'OAuth '+usersessionid}
                            
            });
                
                //console.log('window location' + window.location.hostname);
            
            //Subscribe to a topic. JSON-encoded update will be returned
            //in the callback
            
            $.cometd.subscribe('/topic/InvoiceStatementUpdates',function(message){
            
                //console.log('json mesage data sobject name' +JSON.stringify(message.data.sobject.Name));
                
                $('#content').append('<p>Notification: '+
                                     
                                    'Channel: '+ JSON.stringify(message.channel) + '<br>'+
                                    'Record Name: '+ JSON.stringify(message.data.sobject.Name) + 
                                    '<br>' + 'ID: ' + JSON.stringify(message.data.sobject.Id) + 
                                    '<br>' + 'Event type: ' + JSON.stringify(message.data.event.type) +
                                    '<br>' + 'Created: '+JSON.stringify(message.data.event.createdDate)
                
                                    +'</p>');
            
            });
                
            }
            
        });
        
        
        $A.enqueueAction(sessionaction);             

            
        });
        
    },
    
    handleClick : function(component, event, helper) {

            alert('Daniel');
        
}
    
})


/topic/InvoiceStatementUpdates is the push topic created in step2.


UserSession Class

public class usersession{

    @AuraEnabled
    public static string getsessionid(){
    
        system.debug('User Session ID : ' + UserInfo.getSessionID());
        
        return UserInfo.getSessionID();
    
    }


}

Step 5: Test the PushTopic Channel

1. Test the lightning component using the lightning app

2. Create or modify an InvoiceStatement in a different browser. You should see the event notification appear on the lightning app page.



Sunday 19 February 2017

jQuery code to convert table data into JSON format


Below code converts table data into JSON format.


        function actionSubmit(){
//.messager.alert('Data Saved');

$(document).ready(function(){

  ResUtilObj = {rows: []};

  $('.datagrid-btable').find('tr').each(function() {

rowObj = {};

$(this).find('td').each(function() {

rowObj[$(this).attr("Field")] = $(this).text();

});

ResUtilObj.rows.push(rowObj);

});

console.log(JSON.stringify(ResUtilObj));
});

        }


Main points on the above code

$('.datagrid-btable').find('tr').each(function() { });  - This will loop through each record in the tr tag

$(this).find('td').each(function() {}); - This will loop through each td element in the td tag

ResUtilObj represents in the main table object, it is initialized with rows array object.

rowObj = {}; represents the each field and value in the row.

ResUtilObj.rows.push(rowObj); pushes each row into rows array object

$(this).attr("Field") -  is used to read each field attribute value in the <td field=""> markup

Finally, JSON.stringify(ResUtilObj) is used to convert the array object into JSON string.



Wednesday 15 February 2017

Debug in Lightning


Enable Debug Mode for Lightning Components

Enable debug mode to make it easier to debug JavaScript code in your Lightning components.

There are two modes: production and debug. By default, the Lightning Component framework
runs in production mode. This mode is optimized for performance. It uses the Google Closure
Compiler to optimize and minimize the size of the JavaScript code. The method names and code
are heavily obfuscated.

When you enable debug mode, the framework doesn't use Google Closure Compiler so the JavaScript
code isn't minimized and is easier to read and debug.

To enable debug mode for your org:
1. From Setup, enter Lightning Components in the Quick Find box, then select
    Lightning Components.
2. Select the Enable Debug Mode checkbox.
3. Click Save.

Salesforce Lightning Inspector Chrome Extension

The Salesforce Lightning Inspector is a Google Chrome DevTools extension that enables you to navigate the component tree, inspect component attributes, and profile component performance. The extension also helps you to understand the sequence of event firing and handling.

The extension helps you to:
• Navigate the component tree in your app, inspect components and their associated DOM elements.
• Identify performance bottlenecks by looking at a graph of component creation time.
• Debug server interactions faster by monitoring and modifying responses.
• Test the fault tolerance of your app by simulating error conditions or dropped action responses.
• Track the sequence of event firing and handling for one or more actions.

Install Salesforce Lightning Inspector

Install the Google Chrome DevTools extension to help you debug and profile component performance.

1. In Google Chrome, navigate to the Salesforce Lightning Inspector extension page on the Chrome Web Store.
2. Click the Add to Chrome button.


Get a Reference to a Component in the Console
Click a component reference anywhere in the Inspector to generate a $auraTemp variable that points at that component. You can explore the component further by referring to $auraTemp in the Console tab.

These commands are useful to explore the component contents using the $auraTemp variable.

$auraTemp+""
Returns the component descriptor.

$auraTemp.get("v.attributeName")
Returns the value for the attributeName attribute.

$auraTemp.getElement()
Returns the corresponding DOM element.

inspect($auraTemp.getElement())
Opens the Elements tab and inspects the DOM element for the component.

Salesforce componentRenderer.js important notes


If you want to modify DOM elements created by the framework for a component, modify the DOM elements in the component's renderer. Otherwise, the framework will override your changes when the component is re-rendered

The lightning framework will automatically render the component so you dont have to know anything about the rendering unless you want to customize the default rendering behavior,

the base component in the framework is aura:component. Every component extends this base component.

the renderer for aura:component has 4 phases of rendering and rerendering cycles

1) render()
2) rerender()
3) afterRender()
4) unrender()

the framework calls these functions as part of rendering and rerendering lifecycles.


Rendering Lifecycle

The rendering lifecycle happens once in the lifetime of a component unless the component gets explicitly unrendered. When you create a component:

1. The framework fires an init event, enabling you to update a component or fire an event after component construction but before rendering.

2. The render() method is called to render the component’s body.

3. The afterRender() method is called to enable you to interact with the DOM tree after the framework’s rendering service has inserted DOM elements.


Rerendering Lifecycle

The rerendering lifecycle automatically handles rerendering of components whenever the underlying data changes. Here is a typical sequence.

1. A browser event triggers one or more Lightning events.

2. Each Lightning event triggers one or more actions that can update data. The updated data can fire more events.

3. The rendering service tracks the stack of events that are fired.

4. When all the data updates from the events are processed, the framework rerenders all the components that own modified data by calling each component’s rerender() method.

The component rerendering lifecycle repeats whenever the underlying data changes as long as the component is valid and not explicitly unrendered.

Create a Renderer

You don't normally have to write a custom renderer, but it’s useful when you want to interact with the DOM tree after the framework’s rendering service has inserted DOM elements. If you want to customize rendering behavior and you can’t do it in markup or by using the init event, you can create a client-side renderer.

These guidelines are important when you customize rendering.

• Only modify DOM elements that are part of the component. Never break component encapsulation by reaching in to another component and changing its DOM elements, even if you are reaching in from the parent component.

• Never fire an event as it can trigger new rendering cycles. An alternative is to use an init event instead.

• Don’t set attribute values on other components as these changes can trigger new rendering cycles.
• Move as much of the UI concerns, including positioning, to CSS.

Customize Component Rendering

Customize rendering by creating a render() function in your component's renderer to override the base render() function, which updates the DOM.

The render() function returns a DOM node, an array of DOM nodes, or nothing. The base HTML component expects DOM nodes when it renders a component.

You generally want to extend default rendering by calling superRender() from your render() function before you add your custom rendering code. Calling superRender() creates the DOM nodes specified in the markup.


render:function(cmp,helper){

var ret = this.superRender();
//do custom rendering here

return ret;

}

Rerender Components

If you update data in a component, the framework automatically calls rerender().

rerender : function(cmp,helper){

this.superRerender();

}

Access the DOM After Rendering

The afterRender() function enables you to interact with the DOM tree after the framework’s rendering service has inserted DOM elements. It's not necessarily the final call in the rendering lifecycle; it's simply called after render() and it doesn't return a value.

afterRender: function(component,helper){

this.superAfterRender();

}


Unrender Components

The base unrender() function deletes all the DOM nodes rendered by a component's render() function. It is called by the framework when a component is being destroyed. Customize this behavior by overriding unrender() in your component's renderer. This method can be useful when you are working with third-party libraries that are not native to the framework.

unrender: function(){

this.superUnrender();

}






Salesforce Lightning Components Important Points


Component Bundle

A component bundle contains component or an app and all its related resources. All resources in the component bundle  follow the naming convention  and are auto-wired. for example, a controller <componentName>Controller.js is auto-wired to its component, which means that you can use the controller within the scope of that component.


Using Expressions

expression is a placeholder for the expression.

Anything inside the {! } delimiters is evaluated and dynamically replaced when the component is rendered or when the value is used by the component. Whitespace is ignored.

The resulting value can be a primitive, such as an integer, string, or boolean. It can also be a JavaScript object, a component or collection, a controller method such as an action method, and other useful results.


Global Value Providers

globalID : 

The globalId global value provider returns the global ID for a component. Every component has a unique globalId, which is the generated runtime-unique ID of the component instance.

$Browser:

The $Browser global value provider returns information about the hardware and operating system of the browser accessing the application.

$Label:

The $Label global value provider enables you to access labels stored outside your code.

$Locale:

The $Locale global value provider returns information about the current user’s preferred locale.

$Resource:

The $Resource global value provider lets you reference images, style sheets, and JavaScript code you’ve uploaded in static resources.

Lightning Component Considerations


We recommend that you don't depend on the markup of a Lightning component as its internals can change in the future. For example, using cmp.get("v.body") and examining the DOM elements can wreak havoc should the component markup change down the road. With LockerService enforced, you won't be able to traverse the DOM for components you don't own. Instead of accessing the DOM tree, you can rely on the component tree and take advantage of value binding with component attributes. For example, you'll go far with cmp.find("myInput").get("v.name") instead of cmp.find("myInput").getElement().name.


Important Points

Add the force:appHostable interface to a Lightning component to allow it to be used as a custom tab in Lightning Experience or Salesforce1.


Configure Components for Custom Actions

Add the force:lightningQuickAction or force:lightningQuickActionWithoutHeader interface to a Lightning component to enable it to be used as a custom action in Lightning Experience or Salesforce1. You can use components that implement one of these interfaces as object-specific actions in both Lightning Experience and Salesforce1. You can use them as global actions only in Salesforce1.

Configure Components for Record-Specific Actions

Add the force:addRecordId to a lightning component to enable the component to be assigned with the Id of the currently displaying record.

force:addRecordId interface when used it adds the recordId attribute to the component. this attribute is set to the currently visible record Id.

recordId is only visible when used directly in the component. But when used inside another component this attribute will get nullified.


Add a new interface to your component

To appear in the Lightning App Builder or a Lightning Page, a component must implement the flexipage:availableForAllPageTypes interface.

Mark your resources, such as a component, with access="global" to make the resource usable outside of your own org. For example, if you want a component to be usable in an installed package or by a Lightning App Builder user or a Community Builder user in another org.


Add SLDS to Lightning Components

In order to add SLDS styling to lightning components which are run from developer console. add below line of code to your lightning component

<ltng:require styles="/resource/SLDS105/assets/styles/salesforce-lightning-design-system.css" />