Tag: UI Elements

  • Salesforce Marketing Cloud Custom Profile and Preference Centre

    Salesforce Marketing Cloud Custom Profile and Preference Centre

    Custom Profile & Subscription Centre Working 

    1. Why we need Custom Profile & Subscription center

    • In SFMC we have seen Preference/Profile center either from Email Studio or at the bottom of email content messages using profile center URL. So, in standard one, there is not any designing option like we’re not able to change the logo, font-size, button, and other UI elements.
    • To overcome this issue, we need to make a Customized Profile & Subscription Centre using cloud landing pages as well as use programmatic language (AMPScript, SSJS).

    2. How we can get all the details of any subscriber into our cloud Page

    • We’re using CloudPagesURL inside our email content message that will give us subscriber information (emailaddr, _subscriberkey, member id, jobid, batchid).
    • Inside this method, we need to define Cloud Page ID. We can get this page id from web studio →  Collection → Cloud Page Properties → Page Id.

    Example: Using the anchor tag inside our email message content, we can set our cloud page Id.

     <a alias="Custom Preference Centre"
              href="%%=CloudPagesURL(552)=%%"
         title="Custom Preference Centre">
       Custom Preference Centre
    </a>

    3. Profile Centre Cloud Page Working

    Step – 1 →  We need to get all the Pre-populated values from the All Subscriber list as we’re updating the profile attribute fields. In the All Subscriber list we’ve seen that by default there are 2 required fields (Subscriber Key, Email Address), 3 optional fields (First/Last Name, Gender) & One preferences field (Currently we’re not using any preference fields). 

    • To get these values we’re using Subscriber Object & their methods as well as using Personalization Strings into AMPScript, but we’re not able to get Attributes & Preference values of any subscriber. https://dreamevent.secure.force.com/articleView?id=mc_es_available_personalization_strings.htm&type=5
    • To get Attribute Fields we need to use Subscriber. Attributes Object with the Retrieve method of Attribute. We also need the status of each subscriber and set it into a checkbox type tag inside our form.

    Example: Using AMPScript & Personalization Strings

    %%[ 
        SET @subscriberKey = [_subscriberkey] 
        SET @emailAddress = [emailaddr] 
        SET @genderMale = IIF([gender] == "Male", "checked", "") //gender is the attribute from SSJS & (By Default Value is blank) 
        SET @genderFemale = IIF([gender] == "Female", "checked", "") //gender is the attribute from SSJS & (By Default Value is blank) 
    ]%%
    // For FirstName & LastName (In SSJS)
    var subscriberObj = Subscriber.Init(sk); //Subscriber Object
    var attributes = subscriberObj.Attributes.Retrieve();
    Variable.SetValue("@fsName", Stringify(attributes[0]["Value"]));
    Variable.SetValue("@lsName", Stringify(attributes[1]["Value"]));
    
    // For Status (In SSJS)
    var subscriptionStatus = Subscriber.Retrieve({
        Property: "SubscriberKey",
        SimpleOperator: "equals",
        Value: Variable.GetValue("@subscriberKey")
    });
    if(subscriptionStatus[0].Status == "Active") {
        Variable.SetValue("subscriptionStatus", true);
    }
    else {
        Variable.SetValue("subscriptionStatus", false);
    }

    dont miss out iconDon’t forget to check out: What is Marketing Cloud? Know the Features and Benefits for Businesses

    Step – 2 → Now, we want to get all the updated values from the form into SSJS & update it into SFMC All Subscribers list. To get these values we’re using the name attribute inside the input tag & in SSJS we’re using the Platform library method GetFormField(). After getting all the form values we need to understand the Unsubscribe from all/Resubscribe feature.

    • At the time pre-populated values in step-1 we are fetching the status (Active/Held/Unsubscribe/Bounced etc.) of Subscriber using Subscriber. Init method. Now, In our form, we’re using conditional statements using IIF of amp script to change our name attribute (unsubscribe, subscribe). Whenever we’re not checked in Unsubscribe from all checkboxes then we’re getting true value of subscribe as name attribute & set it into subscribeTo variable otherwise we’re getting true for unsubscribe variable. 

    Example:

    // In HTML
    <input type="hidden" name="subscriberKey" value="%%=v(@subscriberkey)=%%"> 
    // POST VARIABLES (Using name attribute inside input tag)
    // In SSJS 
    var subscriberKey = Platform.Request.GetFormField('subscriberKey') || "";
        var firstName = Platform.Request.GetFormField('firstName') || "";
        var lastName = Platform.Request.GetFormField('lastName') || "";
        var email = Platform.Request.GetFormField('email') || "";
        var gender = Platform.Request.GetFormField('gender') || "";
        var unsubscribe = Platform.Request.GetFormField('unsubscribe') || false;
        var subscribeTo = Platform.Request.GetFormField('subscribe') || false;
    

    Step – 3 → To update the status as Unsubscribed we need the Unsubscribe method of Subscriber.Init() and to make it as Active we need to firstly make an Object variable that has all the attributes values (First/Last Name, Gender) inside Attributes Property as Key and other EmailAddress, SubscriberKey, Status values.

    Example:

    For Unsubscribing inside SSJS

    var subObj = Subscriber.Init(subscriberKey);
    if(unsubscribe) {
        var unsubscribeSatus = subObj.Unsubscribe();
        Variable.SetValue("unsubscribeSatus", unsubscribeSatus);
    }

    For Subscribing inside SSJS

    var subscriberData = {
        "EmailAddress":email,
        "Attributes": {
            "First Name" : firstName, 
            "Last Name" : lastName
        }
    };
    else {
        var udpateStatus = subObj.Update(subscriberData);
        Variable.SetValue("unsubscribeSatus", (subscribeTo &&   udpateStatus)?"SUBSCRIBED":"NA"); //Used as a ternary operator
        Variable.SetValue("udpateStatus", udpateStatus);
        Variable.SetValue("formSubmitted", true);
    }

    Step – 4 → To show SweetAlert , we’re creating or we can say updating the variable (If it’s not already created) value using the response of Unsubscribe method or Update method and after that we’re displaying sweetalert message through IF Else statements. Please add the CDN of Sweet Alert 3rd Party JS Library.

    Example: Using If Else inside AMPScript

     %%[ IF @formSubmitted AND @udpateStatus == "OK" AND @unsubscribeSatus == "NA" THEN ]%%
        <script>
          Swal.fire("Updated!", "Your preferences are updated successfully", "success").then(() => {    location.href = location.href; });  </script>

    NOTE: For Gender Checkbox, we’re not using the default value from Subscriber Attribute instead we’re setting it using IIF of ampscript & the default value is “”.

    4. Subscription Centre Cloud Page Working

    Step – 1 → We need to get all the Pre-populated Status values of lists and Status of Subscriber using All Subscriber List (Subscriber.Init() Object) → Lists (Subscriber.Lists.Retrieve) and iterate it through for loop using the Lists length. Now we fetch all the required information of the list to display using the Write method of SSJS.

    • Unsubscribe from all features is the same as we see in the profile centre working.

    Example: To get Subscriber List Values

    var subsKey=Variable.GetValue("@sk");
    var subscriberObj = Subscriber.Init(subsKey);
    var disSubslist = subscriberObj.Lists.Retrieve();
    for(var i = 0; i < disSubslist.length; i++) {
        Variable.SetValue("@listStatus", disSubslist[i]["Status"]);
        Variable.SetValue("@listId", disSubslist[i]["List"]["ID"]);
        Variable.SetValue("@listName", disSubslist[i]["List"]["Name"]);
    }
    

    Step – 2 → Now, we want to get all the updated values using the name attribute of the input tag. We only get the active list name with their id. So we need to find the unsubscribed list id first then updating the status field using  2 arrays into Object type variables and the upsert method

    • The value of the input tag for the list that was generated dynamically using for loop has the format like “ListName:ListId”. So we’re firstly finding active list id → Original List Id (Using Subscriber Object) → Unsubscribed List Id (Using array diff method that finds the unique elements).

    Example: Getting array like values for listname:listid i.e separated by comma

    var activeLsNameWithId = Platform.Request.GetFormField('activeListName');
    activeLsNameWithId-->Newsletter:5626, Promtions:5628

    To find differences between the original list id and the current active id, we use another array that deletes the current active list id values from the original one & returns unsubscribed list id values

    dont miss out iconCheck out an amazing Salesforce video tutorial here: Salesforce Tutorial | Data Extensions in Marketing Cloud

    Step – 3 → To update the status of each list, we’re firstly checking the length of both arrays(Active List Id, Unsubscribed List Id) then making an Object variable in which we’re giving the “Lists” property as Key & inside that key we’re giving Id (List Id),status and action (Add,Update,Upsert).

    • After that we’re using a Subscriber → List object Upsert method to Upsert the list’s status.For Status in All Subscriber List we’re doing just like profile centre.

    Example:- 

    if(correctActiveLsId != 'undefined') {
        var listSubObj = Subscriber.Init(subscriberKey);
        for(var j = 0; j < correctActiveLsId.length; j++) {
            var subscriberData1 = {
                "EmailAddress": email,
                "SubscriberKey": subscriberKey,
                "Lists": {
                    "ID": parseInt(correctActiveLsId[j]),
                    "Status": "Active",
                    "Action": "Upsert"
                }
            };
            var status1 = listSubObj.Upsert(subscriberData1);
        }
    }
    if(correctUnsubscribedLsId.length>0) {
        var listSubObj2 = Subscriber.Init(subscriberKey);
        for(var k = 0; k < correctUnsubscribedLsId.length; k++) {
            if(correctUnsubscribedLsId[k]!='undefined') {
                var subscriberData2 = {
                    "EmailAddress": email,
                    "SubscriberKey": subscriberKey,
                    "Lists": {
                        "ID":parseInt(correctUnsubscribedLsId[k]),
                        "Status": "Unsubscribed",
                        "Action": "Upsert"
                    }
                };
                var status2 = listSubObj2.Upsert(subscriberData2);
            }
        }
    )

    Output

    Preference/Subscription_Center in SFMC Profile_Center in SFMC

    For Reference:

    • https://ampscript.guide/
    • https://sfmarketing.cloud/
    • Gist link for Customized Profile & Subscription Centre 

  • How to develop Salesforce Visualforce apps using AngularJS ?

    How to develop Salesforce Visualforce apps using AngularJS ?

    If you need to display Salesforce data to people other than those that have Salesforce accounts, Visualforce pages is the best way to go. It allows users to view, edit, or even add data without exposing the data to third party systems. For developers creating Visualforce apps is way easier than creating ad-hoc third party web apps that call upon Salesforce data.

    Seeing the popularity of Visualforce, Salesforce started expanding upon the product and within a few years of its launch we saw support for jQuery, brand new REST API, and ForceTK; a JS proxy calling the library. However, the game-changer for Salesforce and JavaScript development was when Salesforce allowed JavaScript remoting for Apex Controllers. JS remoting allowed you to access server-side apex controller methods through JS directly. Along with Remote Objects, this allowed more flexibility and dynamic usage of Visualforce pages resulting in an even greater adoption of the tool. More and more organizations were depending upon Visualforce pages to display data to clients, partners, and other users now. This called for a more appealing UI for the Visualforce pages and frontend JS framework and libraries were naturally called into the fray. AngularJS being the most popular one was naturally the favorite for the task of creating eye-candy dynamic Visualforce pages.

    In our previous post we talked about why exactly AngularJS is great for creating Visualforce pages. In this post, we will talk about the HOWS. I am assuming that you have some general understanding of AngularJS framework, Salesforce Visualforce pages, and have experience with JavaScript.

    dont miss out iconDon’t forget to check out: Introduction of Visualforce in Salesforce

    For more info on any topic check out these links, they may help.
    AngularJS – https://docs.angularjs.org/tutorial
    Visualforce – https://developer.salesforce.com/trailhead/module/visualforce_fundamentals

    How to use AngularJS in Visualforce?

    JavaScript saw a renewed interest partially because of the success of its frameworks and partially because of greater need for a more visually appealing mobile-friendly single page application. In Visualforce pages, the backend part is not that flexible but that’s because of the level of security that comes with Visualforce. The frontend part, on the other hand, is all yours. So frontend frameworks like AngularJS are greatly preferred to create organized, structured applications having good response times.

    Now considering that each Visualforce app involves around CRUD (create, read, update, delete) operations on Salesforce data, there are three prevalent approaches for fetching and binding data from Salesforce to Visualforce controllers.

    Creating JavaScript Remote objects and using them with Visualforce,
    Using JSON,
    And using ForceTK libraries along with AngularJS libraries.

    The differences are subtle in small apps but as the complexity of your app grows, the difference would be more prominent.

    The beauty of Visualforce pages is that you can start coding from the word go without opening or uploading multiple files to a server or such. So here I am assuming that you have an understanding about VF pages and can create a standalone page in the SFDC setup.

    In this example, we are going to fetch a list of ‘Contacts’ saved in Salesforce in a tabular form and even add a simple search function highlighting two-way data binding of AngularJS.

    Let’s take a look at the main Visualforce page code:

    <apex:page showHeader="false" Controller="ContactsController">
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js">
        </script>
        <link rel="stylesheet"  href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" />
        <script type="text/javascript">
        var app = angular.module('MyApp',[]);  
        app.factory('VFRemotingFactory',function($q,$rootScope){  
            var factory = {};  
            factory.getData = function(searchText){  
                var deferred = $q.defer();  
                GetAllContactsByFilter(function(result){  
                    $rootScope.$apply(function(){  
                        deferred.resolve(result);  
                    });  
                }, searchText);  
                return deferred.promise;  
            }  
            return factory;  
        });
       
        function GetAllContactsByFilter(callback, searchText){  
            if(searchText == undefined)
            {
                searchText = '';
            }
            Visualforce.remoting.Manager.invokeAction(  
                '{!$RemoteAction.ContactsController.GetAllContactsByFilter}', searchText,
                callback,  
                {escape: false}  
            );
        }
        app.controller('myController',function($scope,VFRemotingFactory){  
            $scope.mcm = {};
           
            $scope.getFilteredData = function($event){
                if($scope.mcm.searchText.length > 1)
                {
                    var searchTxt = $scope.mcm.searchText;
                    VFRemotingFactory.getData(searchTxt).then(function(result){  
                        $scope.ContactData = result;  
                    });
                }
                else
                {
                    var searchTxt = $scope.mcm.searchText;
                    VFRemotingFactory.getData().then(function(result){  
                        $scope.ContactData = result;  
                    });
                }
            };
            $scope.Prafull = {};        
            VFRemotingFactory.getData().then(function(result){  
                $scope.ContactData = result;  
            });  
        });
        </script>
        <div ng-app="MyApp">
            <div ng-controller="myController">
                <label>Search: <input ng-model="mcm.searchText" ng-keyup="getFilteredData($event)"/></label>
                <table class="table">
                    <thead>
                        <tr>
                            <th>First Name</th>
                            <th>Last Name</th>
                            <th>Phone</th>
                            <th>Email</th>
                            <th>Title</th>
                            <th>Account Name</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr ng-repeat="contactVar in ContactData">
                            <td>{{contactVar.FirstName}}</td>
                            <td>{{contactVar.LastName}}</td>
                            <td>{{contactVar.Phone}}</td>
                            <td>{{contactVar.Email}}</td>
                            <td>{{contactVar.Title}}</td>
                            <td>{{contactVar.Account.Name}}</td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
    </apex:page>

     

    Now let’s analyze this code. We started off by including a custom Salesforce apex
    controller<https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_controller_custom.htm> for pulling contacts that we named very ingeniously “ContactsController”. This custom controller is also very simple.

    public class ContactsController {
       @RemoteAction
       public static List<Contact> GetAllContactsByFilter(String searchText)
       {
           String searchString = '%' + searchText + '%';
           List<Contact> contactList = [SELECT FirstName, LastName, Phone, Email, Title, Account.Name FROM Contact where FirstName like :searchString];
           return contactList;
       }
    }

    As you may have guessed we are using JS Remoting to access to pass on our data.

    We start off by creating our first AngularJS module that answers to the name ‘MyApp’, var app = angular.module(‘MyApp’,[]). This app is referenced in the main body div through.

    <div ng-app="MyApp">
    

    In our main body, we have created an input box that defines what we are going to display. By default, the content is ‘’ i.e. blank which triggers the app to display all contacts. As we start typing in the search box, it starts to filter out data based on the value in the search box, in real-time, on the same page, without refreshing. This is the magic of two-way data binding.

    Now from here on now, we started to complicate things a little. The main angular controller that we again ingeniously named “myController” is the brains behind the module’s (or app) operations and we have included it in our nested div of the body.

    We then created a module factory that invokes “GetAllContactsByFilter” function which in turn invokes Visualforce remote objects and our custom Visualforce controller ContactsController. This factory returns the list of contacts based on the search text, which by default is blank.

    We created a scope object named ‘mcm’ that contains the model data that we input through the Search input field. The $scope is the main magician that binds view with model.

    The ng function ng-keyup=”getFilteredData($event) that we referenced in search input, triggers a new event whenever a key is entered in the search box. Triggering of this event results in the automatic changing of the model and in our example, automatic changing of view as well. You can restrict changing of view through a button.

    Our AngularJS controller ‘myController’, triggers fetching of data based on the input value. For blanks it fetches all data so does it for typing only single alphabet. When the input string’s length becomes greater than one it filters out the data based on the input string. The fetched data is stored in the scope object ‘$scope.ContactData’ which in turn passes on data to ‘contactVar’ that finally displays data.

    To summarize how AngularJS helped most in this really small and basic example:

    • The ng-keyup automatically trigger events based on user input. A custom function for this is tricky at best.
    • The two way data binding using custom code is full day work at best. We did it in 1 hour.
    • ng-repeat, the small function used to populate the table, custom code for it will take at least 3-4 hours. We did in blink.
    • To add automatic filters we just have to add a line in the ng-repeat reference. For example, if we have to filter by an account we just have to add ng-repeat=”contactVar in ContactData | filter:account”. (Assuming account is the predefined variable).

    dont miss out iconCheck out another amazing blog by Algoworks here: HIPAA Compliant Salesforce Health Cloud – Why Healthcare Organizations Must Consider It

    An Even Simpler Approach

    Now in the previous example, we have needlessly complicated things through module factory and Visualforce remoting. This use case can be achieved through a simpler code. Check out the following code:

    <apex:page standardStylesheets="false" sidebar="false"
      showHeader="false" applyBodyTag="false" applyHtmlTag="false"
      docType="html-5.0" controller="AngularDemoController">
        <html lang="en" ng-app="demoApp">
            <head>
                <meta charset="utf-8"/>
                <meta name="viewport" content="width=device-width, initial-scale=1"/>
                <title>Angular Demo</title>
                <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"/>
                <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js"></script>
                <script>
                    // define the app
                    var demoApp = angular.module('demoApp', []);
                    // add the controller
                    demoApp.controller('DemoCtrl', function ($scope) {
                        $scope.account = {!account}
                        $scope.contacts = {!contacts}
                    });
                </script>
            </head>
            <body class="container" ng-controller="DemoCtrl">
                <h1 style="color:Green">{{account.Name}}</h1>
                <p class="lead" style="color:Gray">
                    {{account.BillingStreet}}<br/>
                    {{account.BillingCity}}, {{account.BillingState}}
                    {{account.BillingPostalCode}}
                </p>
                <b>Search</b>&nbsp;&nbsp;&nbsp;<input ng-model="query" /><br/><br/>
                <table class="table table-bordered">
                    <tr>
                        <th>Name</th>
                        <th>Email</th>
                        <th>Id</th>
                    </tr>
                    <tr ng-repeat="contact in contacts | filter:query">          
                        <td>{{contact.Name}}</td>
                        <td>{{contact.Email}}</td>
                        <td>{{contact.Id}}</td>
                    </tr>
                </table>
            </body>
        </html>
    </apex:page>

    Here is the code for controller:

    global with sharing class AngularDemoController {
        // hardcode an account id for demo purposes
        static String accountId = '00128000003u3uK';
        global static String getAccount() {
            return JSON.serialize([select name, billingstreet,
            billingcity, billingstate, billingpostalcode
            from account where id = :accountId][0]);
        }    
        global static String getContacts() {
            return JSON.serialize([select id, name, email
            from contact where accountId = :accountId]);
        }
    }
    

    Here we are using the JSON approach, and using Salesforce’s inbuilt features like ‘!account’ and ‘!contact’ that automatically lookout for getAccount variable and method called in a custom controller. In this example, we have created an app to fetch contacts of an account whose ID we have hardcoded (I was a little lazy there).

    Here we see the true meaning of Salesforce AngularJS integration.

    Salesforce Lightning vs AngularJS

    Salesforce launched a set of prebuilt UI elements as part of its Lightning platform. This bridges the gap that was leftwas by previous Visualforce in-built components especially in the field of UI. It allows you to create reusable components and has many features similar to AngularJS like tables, accordions, and other UI elements. Now the question comes whether you should go with Lightning for your new app forgoing Angular, or should you forget lightning for now and focus on Angular and other frameworks, or even create using both? The answer is complicated and to be frank, it requires some in-depth research. However, as of now AngularJShas no shortcomings and we can create anything using Angular, whereas the same cannot be said for Lightning. The best approach is to analyze both by use case and capabilities. And it’s not very difficult or problematic to use both.

    Reference: Algoworks

  • How To Set Up Your Company in Salesforce

    How To Set Up Your Company in Salesforce

    Use the corporate Information page in Setup to trace what’s important about your company’s organization in Salesforce. you’ll also manage your licenses and entitlements. This page contains the data that was provided when our company signed up with Salesforce.

    In our sandbox org, we will utilize this page to match provisioned licenses in production org with our sandbox organization. This matching process will update our sandbox org with licenses from production org and deletes any licenses in sandbox org that are not in production org.

    Manage Information About Your Company

    The Company Information page shows all the important information about your company (listed here in alphabetical order). The page also includes the user and have licenses purchased for your organization.

    Allow the desired Domains

    To enable your users to access Salesforce, you need to add the quality Salesforce domains to your list of allowed domains.

    Web Request Limits 

    Limits for concurrent usage on web requests.

    dont miss out iconDon’t forget to check out: Time for Your Salesforce Checkup

    Customize the program

    Give your users the simplest working experience you’ll be able to by putting in the interface to fulfill their needs. 

    Create the Lightning Experience Home Page

    We are here to give our users everything which he has to manage his day from the home page in Lightning Experience. Our sales representative can also see his quarterly performance summary & acquire necessary updates on critical tasks & opportunities. We will also customize this page for a number of forms of users and assign custom pages to different apps & app-and-profile combinations. 

    Customize Record Page Settings

    Customize the experience users have when working with records in Lightning Experience.

    Select Your Language, Locale, and Currency.

    The Salesforce settings for language, locale, time zone, and currency can affect how objects, like Accounts, Leads, or Opportunities, are displayed. 

    Define Your financial year

    Specify a yr that matches your business needs.

    Turn Einstein Features On or Off.

    Access to some Einstein features is subject to usage limitations and your acceptance of additional terms. See the subsequent help topics for instructions on turning these Einstein features on and off.

    Set Up Search

    Now we discover which objects and fields are searchable. Then Customize search settings and search result filters, also lookup search. Learn the way to boost the search experience for the users.

    Avail Maps and placement Services.

    Customize Reports and Dashboards

    Set up reports and dashboards to deliver information to your users within the ways in which work best for them.

    Response for Critical Updates

    Salesforce time to time releases updates to improve the performance, logic, and usefulness of Salesforce for users, but it also affects our existing customizations. Whenever these updates are available, Salesforce starts listing them in Setup at Critical Updates & provides a message to display when administrators move to Setup.

    dont miss out iconCheck out another amazing blog by Krati here: Access sObject’s (Salesforce Object Type) Fields and Its Record | Apex Developer Guide

    Keep Up with Security Alerts

    Salesforce time to time releases security updates that improve data security, but it may also affect our existing customizations. When these updates become available, Salesforce lists them in Setup at Security Alerts and displays a persistent message at the highest of the org for admins. As of Summer ‘20, you’ll also see your alerts within the Release Updates in Setup.

    Arrangement of Data with Partition

    Partitions allow us to segment our org’s data into logical sections,  for making searches, reports, and list views more meaningful & useful to our users. Divisions are also useful for orgs with extremely large amounts of knowledge.

    Salesforce Upgrades and Maintenance

    Salesforce reserves up to 5 minutes of service interruption for major upgrades, but you’ve got access to your data during other maintenance events, like splits and migrations.

    Permissions for UI Elements, Records, and Fields

    To access UI elements, records or fields in Salesforce requires specific permissions. At a minimum, you need to have the “Read” permission to look at a tab, record, record field, related list, button, or link. To edit a record or record field, you want to have the “Edit” permission. 

    Deactivate an Org

    When an org has outlived its usefulness and it’s time to maneuver on, you’ll be able to deactivate it or allow it to expire. 

    How Do I Discontinue Service?

    If the service doesn’t meet your needs, you must cancel it.

    References: trailhead.salesforce, success.salesforce, releasenotes.docs.salesforce, salesforce.stackexchange, brainscape

  • Lightning Data Service (LDS) in Salesforce

    Lightning Data Service (LDS) in Salesforce

    If we have a lightning application that Creates, Reads, Updates or Deletes a record (basically CRUD operations) in the Salesforce database, Lightning Data Service (LDS) is the best and most efficient way to do so. By using LDS, we don’t have to write Apex controller code to fetch or create data in Salesforce. The code is already implicitly written in LDS, and we only need to call it to use one of the several tools based on our requirements.

    Suppose we have several components made to fetch data from the same record, then without LDS, each component would have to make an independent call to the server irrespective of the fact that all these components are fetching information from the same data, hence it reduces efficiency and makes unnecessary calls to the server leading to inconsistencies. Through LDS, we need to fetch record once which reduces network transfers, app server load, and database server load. 

    Lightning Data service is designed to serve as a data Layer for Lightning Components. It is basically a Lightning Component counterpart of Visualforce Standard Controller, providing access to data displayed on the page. There are several advantages of using Lightning Data Service:

    dont miss out iconDon’t forget to check out: Salesforce Lightning Dialer | Boost Sales productivity by making hassle-free calls

    • Minimize XMLHttpRequests 
    • LDS eliminates requests that involve the same record data. It sends a single shared data request that updates all the relevant components.
    • Create notifications when record data changes

    Leveraging the tools of Lightning Data Service

    Salesforce provides us with the following form-based components:

    1. lightning:recordViewForm
    2. lightning:recordEditForm
    3. lightning:recordForm

    In addition to the above mentioned form based LDS tools, Salesforce provides a very versatile components named force:recordData.

    1. lightning:recordViewForm — We can use this component to view a record data.The fields are rendered with their labels and values which are read only. It requires recordId to display the fields on the record. This component also takes care of Field Level Security and Sharing Settings. To display the fields and values we require, we need to specify them using the inbuilt tag lightning:outputField. Here is an example:
    <lightning:recordViewForm recordId="{!v.recordId}" objectApiName="Account">
        <lightning:messages />
        <lightning:outputField fieldName="Name" />
    </lightning:recordViewForm>
    

    This example shows an account object record with the Id specified in recordId attribute and field inside the lightning:outputFIeld tag.The RecordId can either be hard-coded or can be obtained from the inbuilt interface for showing a page on the record :

    “flexipage:availableForRecordHome, force:hasRecordId”

    2. lightning:recordEditForm — We can use this component to create/edit a record data.The component displays fields with their labels and the current values, and enables us to edit their values. To specify editable fields, we need to use lightning:inputField components inside the lightning:recordEditForm component and lightning:button to save the changes made. Let us see this by an example:

    <lightning:recordEditForm recordId="{!v.recordId}" objectApiName="Account">
       <lightning:messages />
       <lightning:inputField fieldName="Name" />
       <lightning:button class="slds-m-top_small" type="submit" label="Create new" />
    </lightning:recordEditForm>
    

    This example shows an account object record with the Id specified in recordId attribute and field inside the lightning:inputFIeld tag along with lightning:button to submit it.

    3. lightning:recordForm — Both the tools defined above can be combined into lightning:recordForm component. This can be used to view, create and edit records based on RecordId. The record ID is inherited from the record page via the force:hasRecordId interface. For example:

    <lightning:recordForm recordId="{!v.recordId}" 
                                  objectApiName="Account"
                                  fields="Name" />

    In this example, lightning:recordForm displays the account name field and label with a pencil icon, just like how it appears on a record detail page. When the pencil icon is clicked, the field becomes editable with the Cancel and Save buttons shown below it.

    4. force:recordData —We can use this component to create,view, edit and delete records. This tool does not inherently include UI elements to show data fetched. We can use it to create highly customization user interfaces beyond what the form-based components provide.It does not contain UI elements. It is just the simple logic fed to the server to fetch relevant data. But for us to be able to view and modify data, we have to use UI elements, for example, lightning:formattedText. Here is the example of the component to load data:

    <aura:component>
        <aura:attribute name="recordId" type="String" />
        <aura:attribute name="record" type="Object" />
        <aura:attribute name="simpleRecord" type="Object" />
        <force:recordData aura:id="forceRecordCmp"
    recordId="{!v.recordId}"
    layoutType="{!v.layout}"
    fields="{!v.fieldsToQuery}"
    mode="VIEW"
    targetRecord="{!v.record}"
    targetFields="{!v.simpleRecord}" />
    <div class="recordName">
    <p class="slds-text-heading--medium">
    <lightning:formattedtext title="Record Name" value="{!v.simpleRecord.Name}" /></p>
    </div>
    </aura:component>

    dont miss out iconCheck out another amazing blog by Anurag here: Best Practices for Data Security in Salesforce

    To load a record on the client side, we have to add the force:recordData tag to our component, and set our recordIdmode, and layoutType or fields attributes.

    • recordId specifies the record to load. Records can’t be loaded without a recordId.
    • mode can be set to either EDIT or VIEW, which determines the behavior of notifications and what operations are available to perform with the record. If you’re using force:recordData to change the record in any way, set the mode to EDIT.
    • layoutType specifies the layout (FULL or COMPACT) used to display the record, which determines what fields are included. Using layoutType allows your component to adapt to layout definitions.
    • fields specifies which fields in the record to query.

    The force:recordData tag also supports a set of target attributes, which are attributes that force:recordData populates itself. The target attributes can be used to allow access from the UI.

    • targetRecord is populated with the loaded record
    • targetFields is populated with the simplified view of the loaded record
    • targetError is populated with any errors

    Reference: trailhead.salesforce, rajvakati