Lightning Best Practices
Lightning Component Best Practices PART 2
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.
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; }
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.
<div onmouseover="myfunction" >foo</div> //bad <div onmouseover="c.myControllerFunction" >foo</div> //OK
window.onload = function () { //some code } document.write = function() { //some code }
<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
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 } }
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!! 🙂
Lightning Component Best Practices
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.
- Increases
a. Developer Productivity
b. Feature availablity
c. Application Scaliblity - 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).
Controller
- Use Controllers to listen to user events and other events like Component Event, Appliction Event.
- Delegate your business logic to helper methods.
- Do not trigger DML operation on component initializaton. If you are doing DML in init(), you are creating a CSRF(Cross-Site Request Forgery).
- 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
- Helper functions may be called from any other javascript in the component bundle.
- 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.
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
- Use Renderer whenever you want to customize default rendering, rerendering, afterrendering and unrendering behaviour for a component.
- Do not fire an event in renderer, firing an event in a renderer can cause an infinite rendering loop.
- If you need to directly manipulate DOM elements in your component, you should do it in the component’s renderer.
Events
- Always use events to implement communication between components.
- 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.
- Application events are best used for something that should be handled at the application level, such as         navigating to a specific record.
- 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.
- 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.
- 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. 🙂