Lightning Experience

Lightning Component Best Practices PART 2

Posted on

Hi All,

Few days before I wrote an article on best practices of Lightning Components. In that article I told you about best practices of Lightning Component Bundle(Controller, Helper, Renderer) and Events. Today I will tell you about best practices to create secure Lightning Components.

In Winter 16 release Salesforce introduced an important change to Lightning Component, In order to run Lightning Components in your org, you will be required to use the My Domain feature.

Why My Domain? At Salesforce, Trust is their number one value. The security team that reviews all changes to the Force.com platform have determined that requiring of My Domain will allow Salesforce to enact even better security around Lightning Components. And better security is good for everyone.

Because of this new feature insecurity is not neccessorily coming from Lightning Components but can come from JavaScript(Client Side) or Apex(Server Side). All the insecurities may come from JavaScript rather than from Lightning Component. Reason for this is the JavaScript from same domain can actually access,modify and read everything. You should follow below best practices to avoid insecurities from Client Side and Server Side. I tried to explore them.

Client Side

  • When modifying the DOM, avoid the use of HTML rendering functions such as innerHTML or $().append(). Rather use component getters and setters whenever possible.
  • //Component1.cmp
    <aura:component>
    	<aura:attribute name="msg" type="String"></aura:attribute>
    	<div><b>{!v.msg}</b></div>
    </aura:component>
    
    //Component1Helper.js
    ({
    	changeValue : function(component) {
    		component.set("v.msg","Changed value before Render"); // Modifying DOM using setter
    	},
    })
    
    //Component1Renderer.js
    ({
    	render: function(cmp, helper) {
    	   console.log('render');
    	   helper.changeValue(cmp); // Modifying DOM in renderer
    	   return this.superRender()
    	},
    })
    

    In above code I am modifying DOM using setter.

    The DOM may only be modified in a renderer. Outside a renderer, the DOM is read-only. Suppose if you are trying to modify DOM in a controller than you are playing out side of the cycle of aura. If you do modification in controller the renderer will wipe all the DOM modification and you will end up with no result.

    In above code I am modifying DOM in renderer.

    Note : JS code within a component can only modify DOM elements belonging to the component. For example, it cannot modify document head or directly access the DOM element belonging to another component. In order to modify a parent or sibling component, an event should be passed to the target component. Child components should only be accessed via their attributes, and not by accessing the DOM of the child component directly.

  • To change styles dynamically, use $A.util.toggleClass() or $A.util.addClass(),$A.util.removeClass().
    Use $A.util.toggleClass() for component instead of a DOM element.
  • //toggleCss.cmp
    <aura:component>
    	<div aura:id="changeIt">Change Me!</div><br />
    	<ui:button press="{!c.applyCSS}" label="Add Style" />
    	<ui:button press="{!c.removeCSS}" label="Remove Style" />
    </aura:component>
    //toggleCssController.js
    ({
    	applyCSS: function(cmp, event) {
    		var cmpTarget = cmp.find('changeIt');
    		$A.util.addClass(cmpTarget, 'changeMe');
    	},
    	removeCSS: function(cmp, event) {
    		var cmpTarget = cmp.find('changeIt');
    		$A.util.removeClass(cmpTarget, 'changeMe');
    	}
    })
    //toggleCss.css
    .THIS.changeMe {
    	background-color:yellow;
    	width:200px;
    }
    
  • Use $A.getCallback() to wrap any code that accesses a component outside the normal rerendering lifecycle, such as in a setTimeout() or setInterval() call or in an ES6 Promise. $A.getCallback() preserves the current execution context and grants the correct access level to the asynchronous code. Otherwise, the framework loses context and only allows access to global resources.
  • window.setTimeout(
    	$A.getCallback(function() {
    		if (cmp.isValid()) {
    			cmp.set("v.visible", true);
    		}
    	}), 5000
    )
    

    This sample sets the visible attribute on a component to true after a five-second delay.

  • Avoid the use of inline javascript except when referencing JS controller methods.
  • <div onmouseover="myfunction" >foo</div> //bad
    <div onmouseover="c.myControllerFunction" >foo</div> //OK
    
  • Do not overwrite window or document functions.
  • window.onload = function () {
       //some code
    }
    document.write = function() {
       //some code
    }
    
  • Don’t use Script or Link tag to include JavaScript or CSS file. Instead of this use use the [ltng:require] aura component.
  • <link type='text/css' rel='stylesheet' href='YOUR_CSS_FILE.css' /> //bad
    <script src="YOUR_JS_FILE.js"></script> //bad
    
    <ltng:require styles="CSS FILE 1,CSS FILE 2,..." scripts="JS FILE 1,JS FILE 2,.."></ltng:require> //OK
    
  • Avoid using absolute URL use relative URL with ‘/’ and encodeURL.
  • Events may only be fired within a controller or component file, but not in a renderer. If you fire an event in renderer the event will go and call the controller again and controller will instantiate again,setup data again and call renderer again and cycle will repeat. This will end up with an infinite loop.
  • Avoid using component. This component outputs value as unescaped HTML, which introduces the possibility of security vulnerabilities in your code. You must sanitize user input before rendering it unescaped, or you will create a cross-site scripting (XSS) vulnerability. Only use with trusted or sanitized sources of data.

Server Side

  • All controller classes must have the with sharing keyword. There are no exceptions. In some cases, your code will need to elevate privileges beyond those of the logged in user.
  • public class DemoController() {  //Unsafe
        
        @AuraEnabled
        public static String getSummary() {
            //code
        }
    }
    
    public with sharing class DemoController() {  //safe
        
        @AuraEnabled
        public static String getSummary() {
            //code
        }
    }
    
  • CRUD/FLS permissions are not automatically enforced in lightning components or controllers, nor can you rely on lightning components to enforce security (as the client is under the control of the attacker, so all security checks must always be performed server-side). You must explicitly check for for isAccessible(), isUpdateable(), isCreateable(), isDeletable() prior to performing these operations on sObjects.
public with sharing class DemoController() {
    
    @AuraEnabled
    public static Contact getContact(String fieldName) { //safe
        if(Schema.SObjectType.Contact.fields.getMap().get('Name').getDescribe().isAccessible()){
			//code
		}
    }
}

Above best practices will help your Lightning Components in passing through security review of AppExchange.

Hope this will be helpful cheers!! 🙂

Who Viewed Record Last Lightning Component

Posted on

Hi All,

In this article I will tell you how to create Lightning Component which shows list of users who viewed record.You can use this Lightning Component for any object whether it is a custom object or standard object.

This can be useful when trying to trace who last Viewed a record? There’s no way to do this in salesforce as of now.It would be great if you could see on a record if anyone has recently viewed it, so I thought to create this Component.

To implement this you have to do following things.
1) On any object you want to use this Lightning Component, create a new custom textarea(255) field called “Last Visited By“.
2) Set History Tracking on for this field.

When complete it will look like this.

Let’s walk through code.

LastVisitedController.apxc :

public with sharing class LastVisitedController{
    
    @AuraEnabled
    public static sObject getViewersList(String recordId, String objectName){
        System.debug('objectName = '+objectName +' recordId = '+recordId);
        
        String query = 'SELECT Id, Name, '+
                       '(Select OldValue, NewValue, Field From Histories Where Field = \'Last_Visited_By__c\' ORDER BY CreatedDate DESC) '+
                       'FROM '+objectName +' Where Id = \''+ recordId + '\' LIMIT 1' ;
        
        sObject obj = Database.Query(query);
        
        return obj;
    }
    
    @AuraEnabled
    public static void updateRecord(String recordId, String objectName){
        Datetime sdate = System.now();        //Format the datetime value to your locale        
        String sysTime = sdate.format('dd/MM/yyyy HH:mm');
    
        String query = 'SELECT Id, Name, Last_Visited_By__c '+
                        'FROM '+objectName +' Where Id = \''+ recordId + '\' LIMIT 1' ;
        
        sObject obj = Database.Query(query);
        obj.put('Last_Visited_By__c' , System.Userinfo.getFirstName() + ' '+ System.Userinfo.getLastName() +' '+ sysTime);
        update obj;
    }
    
}

The getViewersList method is used to return list of users who visited record recently. Method updateRecord is used to update “Last Visited By” field when a user visited record.

LastVisitedCmp.cmp :

<aura:component controller="LastVisitedController" implements="force:appHostable,force:hasRecordId,force:hasSObjectName,flexipage:availableForAllPageTypes">
    <ltng:require styles="/resource/SLDS/assets/styles/salesforce-lightning-design-system-vf.css"/>
    <!-- Atrribute Defination for Object Name -->
	<aura:attribute name="sObjectName" type="String"></aura:attribute>
    <!-- Atrribute Defination for Record Id -->
	<aura:attribute name="recordId" type="String"></aura:attribute>
    <!-- Atrribute Defination for Who visited -->
	<aura:attribute name="visitorsList" type="sObject"></aura:attribute>
    <!-- Event Handler for init Event-->
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"></aura:handler>
    <!--page header-->
    <div class="slds">
        <div class="slds-page-header">
            <div class="slds-grid">
                <div class="slds-col slds-has-flexi-truncate">
                    <div class="slds-media">
                        <div class="slds-media__body">
                            <div class="slds-grid">
                                <h1 class="slds-text-heading--medium slds-m-right--small slds-truncate slds-align-middle">Recently Visited By</h1>
                            </div>
                        </div>
                    </div>
                </div>
            </div>   
        </div>
    </div>
    <!--Container-->
    <div class="container" style="overflow-y:scroll;height:300px">
        <ul class="slds-list--vertical slds-has-cards">
            <aura:iteration items="{!v.visitorsList.Histories}" var="h">
                <li class="slds-list__item">
                    <div class="slds-tile slds-tile--board">
                        <div class="slds-tile__detail">
                            <p class="slds-text-heading--medium">{!h.NewValue}</p>
                        </div>
                    </div>
                </li>
            </aura:iteration>	
        </ul>
    </div>
</aura:component>

The force:appHostable interface indicates the component can be hosted in the Salesforce1 Mobile app.
The flexipage:availableForAllPageTypes interface indicates the component can be used in App Builder.
The force:hasRecordId interface indicates the current record Id should be injected in the component’s recordId attribute.
The force:hasSObjectName interface indicates the current sObjectName should be injected in the component’s sObjectName attribute.

When the component is instantiated on the page, the current record Id and sObject are automatically injected in the recordId and sObjectName attribute. You can then make calls to the server passing the recordId and sObjectName as a parameter to retrieve or save data for that specific record.

LastVisitedCmpController.js :

({
	doInit : function(component, event, helper) {
		helper.getViewerList(component);
	},
})

LastVisitedCmpHelper.js :

({
	getViewerList : function(component) {
		var action = component.get("c.getViewersList");
        action.setParams({
            "recordId" : component.get("v.recordId"),
            "objectName" : component.get("v.sObjectName")
        });
        action.setCallback(this, function(action) {
        	component.set("v.visitorsList",action.getReturnValue());
        });
        
        $A.enqueueAction(action);
	},
    updateRecord : function(component) {
		var action = component.get("c.updateRecord");
        action.setParams({
            "recordId" : component.get("v.recordId"),
            "objectName" : component.get("v.sObjectName")
        });
        $A.enqueueAction(action);
	},
})

LastVisitedCmpRenderer.js :

({
    afterRender : function(component,helper){
        this.superAfterRender();
        helper.updateRecord(component);
    }	
})

The afterRender will be called when Component render completly. It will call helper function which updates “Last Viewed By” field of current record in the background.

🙂

Lightning Component Best Practices

Posted on Updated on

Hi All,

In this article, I will tell you the best practices for Lightning Components, Lightning component bundle and Events.

Lightning Component

Lightning is all about components. You can build applications by assembling components created by you and other developers. A component can contain other components, as well as HTML, CSS, JavaScript, or any other Web-enabled code. This enables you to build apps with sophisticated UIs. We should always keep in mind Lightning Component’s modular approach while creating a Lightning App. It is always a best practice to use component based developement approach. Following are the benifits of component based approach.

  1. Increases
    a. Developer Productivity
    b. Feature availablity
    c. Application Scaliblity
  2. Decreases
    a. Application Complexity
    b. Time to Delivery
    c. Overall Cost

Lightning Component Bundle

Each Lightning Component is made up of a markup, JavaScript controller, a Helper, a Renderer and more(Component Bundle).

final00001

Controller

  1. Use Controllers to listen to user events and other events like Component Event, Appliction Event.
  2. Delegate your business logic to helper methods.
  3. Do not trigger DML operation on component initializaton. If you are doing DML in init(), you are creating a CSRF(Cross-Site Request Forgery).
  4. Do not modify DOM in Controller. If you modify DOM in Controller it will call renderer method which will end in no result.

Helper

Always write your business logic in helper functions because

  1. Helper functions may be called from any other javascript in the component bundle.
  2. Whenever a component runs Lightning Framework creates an instance of the Controller, an instance of the Renderer for each component but creates only one copy of the Helper and passes the reference of the Helper into every Controller instance and every Renderer instance. Below picture will make you understand this well.

final00002

Since Helper is shared across everything, it allows us to share and keep logic across of Controllers and Renderers in one place. It also helps us keep logic within Controllers and Renderers lean. Anytime you need to call one controller function from another controller function, move that logic to Helper.

Renderer

  1. Use Renderer whenever you want to customize default rendering, rerendering, afterrendering and unrendering behaviour for a component.
  2. Do not fire an event in renderer, firing an event in a renderer can cause an infinite rendering loop.
  3. If you need to directly manipulate DOM elements in your component, you should do it in the component’s renderer.

Events

  1. Always use events to implement communication between components.
  2. Always try to use a component event instead of an application event, if possible. Component events can only be handled by components above them in the containment hierarchy so their usage is more localized to the components that need to know about them. Below picture will make you understand better about component event.final00003
  3. Application events are best used for something that should be handled at the application level, such as          navigating to a specific record.appevent
  4. It’s a good practice to handle low-level events, such as a click, in your event handler and refire them as higher-level events, such as an approvalChange event or whatever is appropriate for your business logic.
  5. If you have a large number of handler component instances listening for an event, it may be better to identify a dispatcher component to listen for the event. The dispatcher component can perform some logic to decide which component instances should receive further information and fire another component or application event targeted at those component instances.
  6. Do not use onclick and ontouchend events in a component. The framework translates touch-tap events into clicks and activates any onclick handlers that are present.

That’s it for now I will come with more details in upcoming posts. 🙂

 

 

Visualforce vs Lightning

Posted on Updated on

Hi

There are lots of questions in the mind of Salesforce developers regarding Lightning but the question which comes in every Salesforce developer’s mind is, will Lightning replace Visualforce?

You will be able to answer this question after exploring the Lightning Experience and VisualForce.

vfvslightning

Lightning Experience is not finished yet. There is plenty of work for developers to do just  building out the basic Salesforce application. Many things are working great, some things are working well in “Beta”. As it is in “beta” version  there are a number of things we just haven’t gotten to yet.

We are living in a multi device world where users are expecting highly interactive and immersive experiences literally at their fingertips. Companies like Google, Facebook are making user experience highly interactive using isolated components. Online forms now come with immediate error feedback when users enter invalid data. This interactivity is no longer a novelty, it’s the norm.

So what does this mean for us?

The Visualforce framework provides a robust set of tags that are resolved at the server-side and that work alongside standard or custom controllers to make database and other operations simple to implement. This is a page-centric web application model. It’s great for basic functionality, but it’s challenging to deliver the new, more dynamic experience that users expect. Fundamentally, this is because it relies on the server to generate a new page every time you interact with the application.

Lightning components are part of the new Salesforce user interface framework for developing dynamic web applications for desktop and mobile devices. They use JavaScript at the client-side and Apex at the server-side to provide the data and business logic. To deliver a more interactive experience, you need help from JavaScript on the client-side. In this new app-centric model, JavaScript is used to create, modify, transform, and animate the user interface rather than completely replacing it a page at a time. This model is exciting, interactive, and fluid.

Both the page-centric and app-centric models have their own advantages and both are here to stay. Combining the models lets applications deliver the right type of experience for the right use case.

Let’s explore the differences between Lightning and Visualforce.

Visualforce

UI Generation

  • Server-Side

Workflow

  1. User requests a page
  2. The server executes the page’s underlying code and sends the resulting HTML to the browser
  3. The browser displays the HTML
  4. When the user interacts with the page, return to step one.

 Advantages

  1. Tried and true model
  2. Easy to implement for greater productivity
  3. Naturally splits large applications into small, manageable pages
  4. Has built-in metadata integration

 Disadvantages

  1. Limited interactivity (aside from added JavaScript functionality)
  2. Higher latency

 Lightning

 UI Generation

  •  Client-Side

 Workflow

  1. The user requests an application or a component
  2. The application or component bundle is returned to the client
  3. The browser loads the bundle
  4. The JavaScript application generates the UI
  5. When the user interacts with the page, the JavaScript application modifies the user interface as needed (return to previous step)

Advantages

  1. Enables highly interactive and immersive user experiences
  2. Aligns with Salesforce user interface strategy
  3. Built on metadata from the foundation, providing an integrated developer experience
  4. The Developer Console supports Lightning components, so there’s an integrated developer experience

Disadvantages

  1. Higher learning curve compared to Visualforce
  2. Higher complexity than Visualforce—you’re building an application, not a page
  3. Since Lightning components are new, there are still some features that aren’t supported
  4. There are a limited number of out-of-the-box components

You have gone through pros and cons of Lightning and Visualforce now you have to decide which tool you should use.

Here are some guidelines to help you decide-which tool you should use and when.

When you should use Lightning

  • If you are developing for Salesforce1 Mobile Application you should use Lightning as visualforce characteristics, especially the page-centric orientation, can be a poor match for mobile apps with limited, high-latency network connections and limited compute resources. Lightning components, by contrast, was designed specifically to handle this context.
  • If you are building an interactive experience with JavaScript to meet user experience requirements you should use Lightning.
  • If you are enabling non-developers to build apps by assembling standard or custom components you should use Lightning App Builder and Lightning components for custom components. Use Visualforce if the required components aren’t yet available.
  • If you are adding user interface element for example, say you want to add a tab to a record home. This task is a simple drag-and-drop in Lightning App Builder.
  • If you are building a Community for Customers you should use Community Builder to create a Lightning-based community site leveraging Lightning components.
  • If you are committed to invest in latest technology you should start using Lightning Components.
  • If you are starting a brand new project you should use Lightning Components. If you’re not familiar with them, there’s no better time than now to learn!

Continue using Visualforce

  • If you are building a page-centric experience with limited Client-Side logic use Visualforce.
  • If you are committed to Javascript Framework such as AngularJS or React continue using Visualforce.
  • If you are building an interactive experience with Javascript and you need third party Framework you should use Visualforce as a container for third party Framework.
  • If you are building a community for partners continue using Visualforce in Salesforce Classic. Explore using Lightning components with Lightning components for Visualforce.
  • If you are exposing a Public-Facing Unauthenticated Website continue using Visualforce. Lightning components don’t support an anonymous (unauthenticated) user context yet.
  • If you are rendering pages as PDF in your application use Visualforce. Lightning components don’t support rendering as PDF output yet.
  • If you are adding to an existing project with lots of Visualforce Pages continue to use Visualforce. Consider moving to Lightning components using Lightning components for Visualforce.

Now you are able to decide which tool to use. But, because web applications are taking more advantage of the app-centric model, I will encourage all Salesforce developers to learn at least the basics of Lightning components. You’ll want to use these components in your future development work.