How I prepared for Salesforce certified app builder exam


How I prepared for Salesforce certified app builder exam




Hi All,

On 31st August 2018 I cleared Salesforce Platform App Builder Certification exam. And as soon I posted on social media I started to get question regarding the preparation that how I prepared, So finally I am writing my all the steps I took for this certification. Before starting I would like say a big thanks to my collegues and mentors(Aslam Bari , Ranu Bari , Naveen Soni) for motivating and guiding me for this exam.

When I decided for App builder exam, I got a very first question asked from my friends that, you are a developer then why you are going for this certification. You must go for Platform Developer2.So here is answer for all.
                      
As we all know salesforce provides so many out of the box No Code  tools, using them we can complete so many business requirements.We do not need to write a single line of code. So being a developer I should be having knowledge about these tools,becasuse it can save my efforts and increase my work efficiancy, and I was having that much knowledge. Then Why should not I appear in exam and get my skills certified from the salesforce. It was not wasting money/time. It was an investment so I did it.

So let’s start talking about exam. I took around 25 to 30 Hours in preparation of exam.
First of all I took a deep review of official exam guide, and analysis about which section cover higher ratio of question in exam and how much I am confident in that. So if you see the exam guide you will see that these are the topic which covers more then 70% of exam. And to clear exam you need only 63%.

Data Modeling And Management(20%)
Security(10%)
Business Logic And Process Automation(27%)
User Interface (14%)

You need to focus more on these topics. Most the question for these topics will be scenario based question. While answering the question remind the consideration for every option. It will help you to eliminate the answer so you can select the right answers.

There are some another topic also
Salesforce fundamentals(8%) : In this section very basic questions would be there, Such as a scenario will be given and you need to identify that should you search for a solution on appexchange.

Social (3%): 1 or 2 question would be in exam.

Reporting(5%): Read about the report types and standard reports available. Which reports are available for chart.

Mobile(5%): Read about the customize saleforce mobile app. Such as navigation, buttons on detail page etc.

App Devlopment(8%): Difference between managed and unmanaged package, when to use change set and when to use other migration tools.

Here are some other steps which I took.

  • Also read about the consideration about process automation tools, lookup/master detail fields, formula fields , roll upsummary. So you can understand when not to use them.

  • I also used an mobile app cram which was suggested by one of my Salesforce Ohana friend Bharat Kumar. On this app you will find flash cards , which are helpful for revising the topics. I used to do practice on this app before going to bed. And it was really helpful. I would like to say a big thank to Bharat for letting me know about this app.

Thanks,
Let me know your suggestions in comment section.




lightning:empApi Salesforce Winter19


lightning:empApi 




Hi All,
Today I will talk about brand new lightning component lightning:empApi , Which was delivered in winter 19 salesforce realease.

When to use empApi:  To see live data in on lightning component.

We had serval options to do this such as polling which is an old technique in this we call server (Apex class) again and again. Or we use streaming api, and cometD JS (external javascript) which requires lots of efforts.

Drawbacks of polling (Calling apex server) : In this we need to travel to server after every particular interval. In this sometimes our server trip is useless , if we do not have any latest data there. 

But now we have an native lightning component (lightning:empApi) , which is very helpful and reducse developer's effort.

lightning:empApi can only be used in desktop browser only and require API version 44.0 and higher. lightning:empApi can be used with platform events, PushTopic events, generic events and Change Data Capture events.

Let's see an example of lightning:empApi with platform events. My colleague Aslam bari already have written an outstanding blog (quick demo salesforce platform events) on Platform event.

In our example we will display all case which has status = open. We would not reload our component and will see live/latest data.

Demo:



So firts of all we will create a new platform event.
I have created platform event (UpdateRecord__e).

Then we need to publish it whenever a new case is inserted with status = 'open'. As well as you can also publish platform event when status is changed from open to any other or vice versa. And same you can do for delete also.

CaseTrigger:


trigger CaseTrigger on Case (after insert) { List<Case> listOfOpenCase = new List<Case>(); for(Case objCase : trigger.new){ if(objCase.Status == 'Open'){ listOfOpenCase.add(objCase); } } if(listOfOpenCase.size() > 0){ EventBus.publish(new UpdateRecord__e(message__c = listOfOpenCase[0].id)); } }


empApiExample.cmp:

<aura:component controller="empApiExampleController" implements="force:appHostable"> <aura:handler name="init" value="{!this}" action="{!c.doInit}"></aura:handler> <aura:attribute name="listOfCases" type="List"/> <aura:attribute name="subscription" type="Map" /> <aura:attribute name="showSpinner" type="Boolean" default="false"/> <lightning:empApi aura:id="empApi"/> <aura:if isTrue="{!v.showSpinner}"> <lightning:spinner size="small"/> </aura:if> <lightning:card title="empApi Example" footer=""> <div> <table class="slds-table slds-table_cell-buffer slds-table_bordered"> <thead> <tr class="slds-line-height_reset"> <th class="slds-text-title_caps" scope="col"> <div class="slds-truncate" title="Opportunity Name">Case Subject</div> </th> <th class="slds-text-title_caps" scope="col"> <div class="slds-truncate" title="Account Name">Priority</div> </th> <th class="slds-text-title_caps" scope="col"> <div class="slds-truncate" title="Close Date">Reason</div> </th> </tr> </thead> <tbody> <aura:iteration items="{!v.listOfCases}" var="objCase"> <tr class="slds-hint-parent"> <td data-label="Case Subject"> <div class="slds-truncate" title="Cloudhub">{!objCase.Subject}</div> </td> <td data-label="Case Priority"> <div class="slds-truncate" title="Cloudhub">{!objCase.Priority}</div> </td> <td data-label="Case Reason"> <div class="slds-truncate" title="Cloudhub">{!objCase.Reason}</div> </td> </tr> </aura:iteration> </tbody> </table> </div> </lightning:card> </aura:component>



empApiExampleController.js



({ doInit : function(component, event, helper) { helper.getData(component); // Get the empApi component. var empApi = component.find("empApi"); // Error handler function that prints the error to the console. var errorHandler = function (message) { console.error("Received error ", JSON.stringify(message)); }; // Register error listener and pass in the error handler function. empApi.onError(errorHandler); var channel = '/event/UpdateRecord__e'; // platform event name var replayId = -1; var callback = function (message) { console.log("Event Received : " + JSON.stringify(message)); helper.getData(component); }; // Subscribe to the channel and save the returned subscription object. empApi.subscribe(channel,replayId, callback).then(function(newSubscription) { component.set("v.subscription", newSubscription); // can be used if you want to unsubscribe event }); } })

empApiExampleHelper.js



({ getData : function(component) { component.set("v.showSpinner",true); var action = component.get('c.getListOfCases'); action.setCallback(this,function(response){ if(response.getState() === "SUCCESS"){ component.set("v.listOfCases",response.getReturnValue()); component.set("v.showSpinner",false); } }); $A.enqueueAction(action); } })


empApiExampleController (Apex)


public class empApiExampleController { @AuraEnabled public static List<Case> getListOfCases(){ return [SELECT Id,Subject,Priority,Reason FROM Case WHERE Status = 'Open']; } }

Thanks,



Lightning Data Services


Lightning Data Services

What is LDS :
                        LDS is Lightning Component that display the data on Page in Salesforce  Lightning. Using LDS we don’t need any apex  controller to perform CRUD operation. using LDS we can increase the performance. It also provide the way to cache the data to work offline in case user is not connected to network. Once the connection is restored data will sync.
LDS also handle Field Level Security and sharing rules security. Record loaded in Lightning Data Services are stored in cache and shared between all components.Using LDS all component performance is increase because data is loaded once and used by many component, no need to make separate request from different-different components . when any of the component  updates  a record then other component will  automatically updated with new value.

force:recordData :
                                    This tag is must be used to load the data in component  using LDS.
Attributes of force:recordData : 
recordId : Id of current page record that will be load
      mode : (Edit,View) its depend on what operation we are performing. If we want to update,create then Mode=’Edit’ else Mode=’View’
layoutType : specify the layout type to display record and its determine what field are included in component. 
          fields : specifies which fields in the record to query.

Target Attribute :
1.      targetRecord  : populate with loaded record.
2.      targetField      : view of loaded record.
3.     targetError      :  populate with error.    

Methods :
1.      saveRecord() : insert of update the current record in force:recordData.
2.      deleteRecord() : delete the current record in force:recordData.
3.      getNewRecord() :  load the new record instance to insert the record of that object from force:recordData.
4.      reloadRecord() : reload the current record with new data.

Keep In Mind When Using It :
i.                LDS is simple but it’s not complete replacement of apex controller.
ii.              LDS is not supported in lightning out and visualforce page. Its only for lightning.
iii.            LDS perform CRUD only on single record. It’s not supported for bulk data.
iv.             In Summer 17, release LDS used force:recordPreview component.But now it’s completely replaced by force:recordData. Difference between force:recordPreview  and force:recordData  is force:recordData  returns record in new shape using UI API and targetfield is added in parameter.
v.               To update from force:recordPreview  to force:recordData is to change reference from targetRecord to targetField.
vi.              If you want to query multiple operations in one transaction then use apex controller @AuraEnabled.


Example :
            Here we are creating a component that is added on Account detail page. It will create a new contact for current account record.


1. Create a new Record :

    Lightning Component :
    <aura:component implements="flexipage:availableForRecordHome, force:hasRecordId">
<aura:attribute name="newContact" type="Object"/>
<aura:attribute name="createContact" type="Object"/>
<aura:attribute name="newContactError" type="String"/>
<force:recordData aura:id="contactRecordCreator"
    layoutType="FULL"
    targetRecord="{!v.newContact}"
    targetFields ="{!v.createContact}"
    targetError="{!v.newContactError}"/>
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
            <div class="Create Contact">
                        <lightning:card iconName="action:new_contact" title="Create Contact">
                                                <div class="slds-p-horizontal--small">
<lightning:input aura:id="contactField" label="First Name" value="{!v.createContact.FirstName}"/>
<lightning:input aura:id="contactField" label="Last Name" value="{!v.createContact.LastName}"/>
<lightning:button label="Save Contact" variant="brand" onclick="{!c.handleSaveContact}"/>
                                    </div>
</lightning:card>
            </div>
    <aura:if isTrue="{!not(empty(v.newContactError))}">
        <div class="recordError">
            {!v.newContactError}</div>
    </aura:if>
    </aura:component>

   Lightning Controller :
   ({
    doInit: function(component, event, helper) {
        console.log('changes');
        component.find("contactRecordCreator").getNewRecord(
            "Contact", // sObject type (entityAPIName)
            null,      // recordTypeId
            false,     // skip cache?
            $A.getCallback(function() {
                var rec = component.get("v.newContact");
                var error = component.get("v.newContactError");
                if(error || (rec === null)) {
                    console.log("Error initializing record template: " + error);
                }
                else {
                    console.log("Record template initialized: " + rec.sobjectType);
                }
            })
        );
    },
    SaveContact: function(component, event, helper) {
        component.set("v.createContact.AccountId", component.get("v.recordId"));
        component.find("contactRecordCreator").saveRecord(function(saveResult) {
            if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {
                var resultsToast = $A.get("e.force:showToast");
                resultsToast.setParams({
                    "title": "Saved",
                    "message": "New Contact ."
                });
                resultsToast.fire();
            } else if (saveResult.state === "INCOMPLETE") {
                console.log("User is offline, device doesn't support drafts.");
            } else if (saveResult.state === "ERROR") {
                console.log(JSON.stringify(saveResult.error));
            } else {
                console.log('Unknown problem, state: ' + saveResult.state);
            }
        });
    }
    })
Result :


2. Delete A record :
            Here we added Delete Component on Account Detail Page. It will Delete Current Account when we click on Delete Button in below component.

Lightning Component :
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId">
    <aura:attribute name="recordError" type="String" access="private"/>
    <force:recordData aura:id="dataRecord"
            recordId="{!v.recordId}"
            fields="Id"
            targetError="{!v.recordError}"
            recordUpdated="{!c.handleRecordUpdated}"/>
     <div class="Delete Record">
            <lightning:card iconName="delete" title="Delete Record">
                                    <div class="slds-p-horizontal--small">
<lightning:button label="Delete Record" variant="destructive" onclick="{!c.handleDeleteRecord}"/>
                                    </div>
            </lightning:card>
       </div>
    <aura:if isTrue="{!not(empty(v.recordError))}">
        <div class="recordError"> {!v.recordError}</div>
     </aura:if>
</aura:component>

Lightning Controller :
({
handleDeleteRecord: function(component, event, helper) {
             component.find("dataRecord").deleteRecord($A.getCallback(function(deleteResult) {
            if (deleteResult.state === "SUCCESS" || deleteResult.state === "DRAFT") {
                console.log("Record is deleted.");
            } else if (deleteResult.state === "INCOMPLETE") {
                console.log("User is offline, device doesn't support drafts.");
            } else if (deleteResult.state === "ERROR") {
                console.log('Problem deleting record, error: ');
            } else {
                console.log('Unknown problem, state: ');
            }
        }));
    },
 handleRecordUpdated: function(component, event, helper) {
        var eventParams = event.getParams();
        if(eventParams.changeType === "CHANGED") {
        } else if(eventParams.changeType === "LOADED") {
        } else if(eventParams.changeType === "REMOVED") {
            var resultsToast = $A.get("e.force:showToast");
            resultsToast.setParams({
                "title": "Deleted",
                "message": "The record was deleted."
            });
            resultsToast.fire();

        } else if(eventParams.changeType === "ERROR") { }
    }
})

Result :


3. Update a Record :
            Here We create a component that will update the account detail on Account Detail page on click of save Button in component.

Lightning Component :
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId">
    <aura:attribute name="record" type="Object"/>
    <aura:attribute name="accRecord" type="Object"/>
    <aura:attribute name="recordError" type="String"/>
    <force:recordData aura:id="recordHandler"
      recordId="{!v.recordId}"
      layoutType="FULL"
      targetRecord="{!v.record}"
      targetFields="{!v.accRecord}"
      targetError="{!v.recordError}"
      mode="EDIT"
      />
    <div class="Record Details">
        <lightning:card iconName="action:edit" title="Edit Account">
            <div class="slds-p-horizontal--small">
               <lightning:input label="Account Name" value="{!v.accRecord.Name}"/>
               <br/>
               <lightning:button label="Save Account" variant="brand" onclick="{!c.SaveRecord}" />
            </div>
        </lightning:card>
    </div>
    <aura:if isTrue="{!not(empty(v.recordError))}">
        <div class="recordError">
            {!v.recordError}</div>
    </aura:if>
</aura:component>

Lightning Controller :
({
    SaveRecord: function(component, event, helper) {
        component.find("recordHandler").saveRecord($A.getCallback(function(saveResult) {
            if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {
                console.log("User drafts.");
            } else if (saveResult.state === "INCOMPLETE") {
                console.log("User is offline, device doesn't support drafts.");
            } else if (saveResult.state === "ERROR") {
                console.log('Problem saving record, error: ' + JSON.stringify(saveResult.error));
            } else {
                console.log('Unknown problem, state: ' + saveResult.state + ', error: ' + JSON.stringify(saveResult.error));
            }
        }));
    }
})

Result :