Friday, 28 February 2020

Shadow DOM in LWC

 DOM stands for Document Object Model.Lightning web component use the shadow DOM.
 
   The element in each lightning web component are encapsulated in a
   shadow tree.This part of the DOM is called a shadow tree because it's
   hidden from the document that contains it.The shadow tree affects how
   you work with css,events and the DOM.
 
   Shadow DOM is a web standard that encapsulates the elements of a component
   to keep styling and behavior consistent in any context.
   Since not all browsers that Salesforce supports implement shadow DOM, LWC
   uses a shadow DOM polyfill.
   A polyfill is code that allows a feature to work in a web browser.
 
   The Shadow DOM have three primary effects
   1.DOM access
   2.CSS isolation
   3.event propagation
 
   Shadow DOM basics :

 
   1.Shadow host : The regular DOM node that the shadow DOM is attached to.
                    it hosts the shadow root.
   2.Shadow root : The root node of the shadow tree.
   3.shadow tree : the DOM tree inside the shadow DOM.
   4.shadow boundary : the place where the shadow DOM ends,and the regular DOM begins.

Sunday, 26 January 2020

Lightning Web Component lifecycle hooks

A lifecycle hook is a callback method triggered at a specific phase of a component instance's lifecycle.

1.constructor()

-> Constructor is invoked when the component is created.
-> since flow is from parent to child, do not access child elements in the component body because they don't exist yet.
-> First Statement must be super() with no parameters.

2.connectedCallback()

-> Connectedcallback is invoked when the component is inserted into DOM.
-> since flow is from parent to child, do not access child elements in the component body because they don't exist yet.
-> we can access the Parent elements and modify them in this hook.

3.disconnectedCallback()

-> disconnectedCallback is invoked when component is removed from DOM.
-> This hook flows from parent to child.
-> it can fire more than once.

4.render()

-> This hook is used to override the standard rendering functionality.
-> It gets called after connectedCallback() and it returns a valid HTML template.
-> This hook flows from parent to child.
-> It can fire more than once.

5.renderCallback()

-> Called after component is rendered.
-> This hook flows from child to parent.
-> It can fire more than once.

6.errorCallback(error,stack)

-> This hook is called when the component throws an error in one of its hooks.
-> The Error argument is a javascript native error object and the stack argument is a string.
-> This method works like a javascript catch{} block for catching errors.


ex:
/* eslint-disable no-console */
import { LightningElement,api } from 'lwc';
import temp1 from './hooktemp1.html';
import temp2 from './hooktemp2.html';

export default class Lwchooks extends LightningElement {
    @api templateSelected='temp1';
    constructor(){
        super();
        console.log('Inside of Constructor');
    }
    connectedCallback(){
        console.log('Inside of connectedCallback');
    }
    disconnectedCallback(){
        console.log('Inside of disconnectedCallback');
    }
    handleTemplate(){
        if(this.templateSelected==='temp1'){
            this.templateSelected= 'temp2';
        }else{
            this.templateSelected='temp1';
        }
    }
    render(){
       console.log('Inside render');
       if(this.templateSelected==='temp1')
       // return tempalte 1
        return temp1;
       // return tempalte 2
        return temp2;
         
    }
    renderedCallback(){
        console.log('Inside renderedCallback');
    }
    errorCallback(error,stack){
        console.log('Inside error Callback'+ error + stack);
    }
}


<!--hooktemp1.html -->

<template>
    <div> Displayed Template 1 </div>
    <lightning-button label="Show Template 2" onclick={handleTemplate}></lightning-button>
</template>

<!--hooktemp2.html -->

<template>
    <div> Displayed Template 2 </div>
    <lightning-button label="Show Template 1" onclick={handleTemplate}></lightning-button>
</template>

Saturday, 25 January 2020

Lightning web Component Bundle Structure

1.Metadata (XML)
2.javascript
3.HTML
4.Optional CSS and more javascript

HTML Provides the structure for your component.

In LWC, the camel case name of the components are rendered as kebab-case(words separated by hypen) and that component must have a closing tag.

ex :  <template>
         <c-my-component></c-my-component>
      </template>

HTML attributes are in kebab case and its used in LWC for component rendering,calling from one component to another component,Set value attribute name to other component LWC.

Javascript defines the core business logic and event handling.

Js files in LWC are ES6 modules where everything declared in a module is local to the module.

CSS provides the look,feel and animation for your component.


ex :
 <!-- myComponent.html -->
 <template>
    <!-- your markup here -->
 </template>

 //myComponent.js
import { LightningElement, api} from 'lwc';
export default class myComponent extends LightningElement{
  @api prop1;
  @api prop2=false;
}

//myComponent.js-meta.xml

?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>45.0</apiVersion>
<isExposed> true </isExposed>
<masterLabel> LWC Demo </masterLabel>
<description> This is Lightning web component Demo </description>
<targets>
 <target>lightning__AppPage</target>
 <target>lightning__HomePage</target>
 <target>lightning__RecordPage</target>
 <target>lightningCommunity__Default</target>
 <target>lightningCommunity__Page</target>
 <target>lightning__UtilityBar</target>
 <target>lightning__Tab</target>
 <target>lightning__FlowScreen</target>
 <target>lighting__Inbox</target>
 <target>lightning__ChatMessage</target>
</targets>
<targetCongfigs>
 <targetConfig targets="lightning__AppPage, lightning_HomePage">
   <property name="prop2" type="Boolean" />
 </targetConfig>
 <targetConfig targets="lightning__RecordPage">
          <property name="prop1" type="String" />
          <objects>
              <object>Account</object>
              <object>Opportunity</object>
              <object>Warehouse__c</object>
          </objects>
      </targetConfig>
</targetConfigs>
</LightningComponentBundle>

The configuration file defines the metatdata values for the component,including the design configuration for the Lightning App Builder and Community Builder.

Configuration file tags :
=================

apiversion :
=========
A double value that binds the component to a salesforce API version.

description :
=========
A short description of the component, usually a single sentence.Appears in list views, like the list of Lightning Componnets in Setup,and as a tooltip in the Lightning App Builder and in Community Builder.

isExposed :
=========
A Boolean value. Expose the component in all orgs, and in Lightning App Builder and Community Builder.

To Make a component usable in a managed package, set isExposed to true.
To Make a component usable in Lightning App Builder and Community Builder set isExposed to true.

masterLabel :
=============
The title of the component .Appears in list views,like the list of Lightning Components in
Setup, and in the Lightning App Builder and in Community Builder.

Note : If you do not use masterLabel tag in the configuration file, your component name will
default as the label of the component.

targets :
=======
Specifies which type of lightning page the component
can be added to . If you want your component to appear in the
Lightning App Builder or in Community Builder, specify at least
one Lightning Page Type

ex :

<targets>
 <target>lightning__AppPage</target>
</targets>


lightning__AppPage

Enables a component to be used on the Lightning Page of type App Page.

lightning__HomePage

Enables a component to be used on the Lightning Experience Home Page.

lighting__RecordPage

Enables a component to be used on a Lightning record Page.

lighningCommunity__Page

Enables a component to be used on a Lightning community page in community builder.

lightningCommunity__Default

Used together with lightningCommunity__Page.

Enable a component that includes configurable properties to be used on a Lightning community page in community builder.When the component is selected on the page , the properties appear.


targetConfigs :
===============
Configure the component for different page types and define component properties.

Note : A component could have different properties on a record home page than
on the Salesforce Home page or an app page.

targetConfig :
==============
It is subtag of targetConfigs and used for different page type configuration.

Property :
===========
Specifies a public property of a component that can be set in Lightning App Builder App Manager,Lightning Flow Builder or
Community Builder. The component author defines the property in the component's javascript
class using the @api decorator.

ex :

<property name="picklistValue" type="String" datasource="Option One, Option Two, Option Three" />
<property name="stringValue" type="String" placeholder="Type something here..." />
<property name="numberValue" type="Integer" min="0" max="100" default="10" />

property tag supports different attributes such as datasource,default,description,label,max,min etc

name :

Reuired if you're setting properties for your component.The attribute name.This value must match the property name in the component's javascript class.

type : The attribute data type

label : Display as a label for the attribute in the tool.

deafult : The default value for the attribute.

description : Displays as an i-bubble for the attribute in the tool.

datasource : Renders a field as a picklist, with static values.Supported only if the type attribute is String.


objects :
=======
A set of one or more objects the component is supported for.
This tag set works only inside a parent targetConfig that's configured for lightning__RecordPage.
Specify the objects tag set only once inside a targetConfig set.
supports the object subtag.

object :
======
Define which objects the component is supported for.
Use one object tag for each supported object.
You can't use '*' to denote all objects.

Note :
targetConfigs is an optional tag, if you want to restrict the component
to be used for some particular object record page.

Wednesday, 1 January 2020

Application library events in lightning

Open a record create Page :
===========================

It is event which is fired to show the full Record create panel.

To display the record create a page for an object,set the object name
on the entityApiName attribute and fire the event.

recordTypeId is optional and, if provided,specifies the record type for the created
object. defaultFieldValues is optional and if povided, specifies values to use to
prepopulate the create record form.

ex :
createAccount : function(component,event,helper){
  var accountCreate = $A.get(e.force.createRecod');
  accountCreate.setParams({
  "entityApiName":"Account",
  "defaultFieldValues":{
    'Name':'Test Account'
  },
  "recordTypeId":RecTypeID
  });
}

Open a record edit Page :
===========================

editRecord : function(component, event, helper)
    var editRecordEvent = $A.get("e.force:editRecord");
    editRecordEvent.setParams({
      "recordId": component.get("v.contact.Id")
   });
    editRecordEvent.fire();
}

this will open an edit form with pre-populated values from contact record whose id we have passed in controller.

opened edit form is based on the page-layout associated with the record id.

Navigate to a record :
======================
1.force:navigateToList

To navigate to a list view, set the list view ID on the listViewId attribute and fire the event.

gotoList : function (component, event, helper) {
    var action = component.get("c.getListViews");
    action.setCallback(this, function(response){
        var state = response.getState();
        if (state === "SUCCESS") {
            var listviews = response.getReturnValue();
            var navEvent = $A.get("e.force:navigateToList");
            navEvent.setParams({
                "listViewId": listviews.Id,
                "listViewName": null,
                "scope": "Contact";
            });
            navEvent.fire();
        }
    });
    $A.enqueueAction(action);
}

@AuraEnabled
public static List<ListView> getListViews() {
    List<ListView> listviews =
        [SELECT Id, Name FROM ListView WHERE SobjectType = 'Contact'];
     // Perform isAccessible() check here
    return listviews;
}

2. force:navigateToObjectHome

Navigates to the object home specified by the scope attribute.


navHome : function (component, event, helper) {
    var homeEvent = $A.get("e.force:navigateToObjectHome");
    homeEvent.setParams({
        "scope": "myNamespace__myObject__c"
    });
    homeEvent.fire();
}

3.force:navigateToRelatedList

 Navigates to the related list specified by parentRecordId.

gotoRelatedList : function (component, event, helper) {
    var relatedListEvent = $A.get("e.force:navigateToRelatedList");
    relatedListEvent.setParams({
        "relatedListId": "Cases",
        "parentRecordId": component.get("v.contact.Id")
    });
    relatedListEvent.fire();
}

4. force:navigateToSobject

Navigates to an sObject record specified by recordId.


createRecord : function (component, event, helper) {
    var navEvt = $A.get("e.force:navigateToSObject");
    navEvt.setParams({
      "recordId": "00QB0000000ybNX",
      "slideDevName": "related"
    });
    navEvt.fire();
}

5. force:navigateToURL

 Navigates to the specified URL.

 1)   Using a relative URL.

   gotoURL : function (component, event, helper) {
    var urlEvent = $A.get("e.force:navigateToURL");
    urlEvent.setParams({
      "url": "/006/o"
    });
    urlEvent.fire();
}

2)   Using external website when the link is clicked.

navigate : function(component, event, helper) {
 
    //Find the text value of the component with aura:id set to "address"
    var address = component.find("address").get("v.value");
    var urlEvent = $A.get("e.force:navigateToURL");
    urlEvent.setParams({
      "url": 'https://www.google.com/maps/place/' + address
    });
    urlEvent.fire();
}

Thursday, 26 December 2019

Lightning web Components


why using Lightning web components ?
1.Re-usability     - Imports,Exports and Templates allows us to reuse the components.
2.Composition      - Breaking components to smaller chunks
3.Encapsulation    - Using the shadow DOM
4.Standardization  - Part of W3C specs and supported by majority of browser.

Core Elements of web Components ?

1.HTML Templates
2.Custom Elements
3.Shadow DOM
4.ES Modules

Templates and Slots :
=====================
1.Templates allow us to load HTML tags without rendering them on initial load.
2.Write once and reuse in multiple pages or multiple apps.
3.Attach them to Shadow DOM or DOM.
4.Slots are placeholders in template that allow you to insert your own HTML markup.

Custom Elements :
=================
Allows us to define an element and let browser learn about the new tag.

class MyCustomElement extends HTMLElement{
 
  constructor(){
    // always call super() first in your constructor to inherit from your Parent class
super();
  }

}
customElements.define('my-custom-element',MyCustomElement);

Shadow DOM :
==============
1.Shadow DOM allows the web browser to render DOM elements without putting them into the main document DOM tree.
2.One can attach shadow DOM to an element using the API Element.attachShadow(mode:open}).
3.You can attach the Shadow to the custom element.
4.Offers encapsulation (CSS in outer DOM cannot bleed into the shadow DOM).

Lightning Web Components (LWC)

1.Lightning Components used aura framework and its renamed as Aura Components.
2.Components built using Web Components standard now are referred as lightning web components.
3.Lightning web components(LWC) adheres closely to the web components standards.
4.Modules for Data services, UI API and provides reactive properties.


Note : Shadow DOM
1.The elements in each Lightning web component are encapsulated in a shadow tree.
2.This part of the DOM is called a shadow tree because it's hidden from the document that contains it.
3.The shadow tree affects how you work with CSS,events and the DOM.
4.Since not all browsers that Salesforce supports implement Shadow DOM,LWC uses a shadow DOM polyfill.

ex :
<c-todo-app>
 #shadow-root
   <div>
    <p>Your To Do List</p>
   </div>
   <c-todo-item>
    #shadow-root
<div>
   <p>Go to the store</p>
</div>
</c-todo-item>
</c-todo-app>

Shadow tree for todoApp
Shadow tree for todoItem

Javascript Properties :
======================
1.Reactive Property - Change in property value automatically reRenders the template.
2.To create a public property use @api.
3.To create a private property and reRender DOM use @track.

Lightning Data Service :
==========================
1.Mark the property with @wire if you want the property to receive the changes when data change happens to record.
2.LWC supports UI APIs and Metadata describes.

Life Cycle Hooks :
===================
1.constructor()             - When Component Created
2.connectedCallback()       - When Component inserted in DOM.
3.disconnectedCallback()    - When Component removed from DOM.
4.render                    - Called after ConnectedCallBack.For Complex rendering Logic.
5.renderedCallback()        - After render
6.errorCallback(error,stack)- If any error in component life-cycle methods.

Important point :
==================

Handle Event When Component not in Same DOM

1.Use pub sub model

Component :
============
1.Component HTML File
2.Component Javascript File.
3.Component Configuration File.

Javascript files in Lightning web components are ES6 modules.
By default, everything declared in module is local-it's scoped to the module.

To import a class,function or variable declared in module,use the export statement.

ex :

import { LightningElement } from 'lwc';
export default class MyComponent extends LightningElement{

}

lwc is core module from wher we import LightningElement.
LightningElement is custom wrapper of the standard HTML element creates javascript class for LWC.

Decorators :
=============
The Lightning Web Components programming model has three decorators
that add functionality to a property or function.
The ability to create decorators is part of ECMAScript,but these three decorators
are unique to Lightning Web Components.

1.@api :

To expose a public property,decorate it with @api.
An owner component that uses the component in its markup can
access the component's public properties.

2.@track :

To track a private property's value and re render a component
when it changes,decorate the property with @track.
Tracked properties are also called private reactive properties.

3.@wire :

To read Salesforce data, Lightning web components use a reactive wire
service . When the wire service Provisions data, the component rerenders.

Components use @wire in their javaScript class to specify a wire adaptor or an Apex method.

Components use @wire in their javaScript class to read data from one of the wire adapter
in lightning/ui*Api namespace.

wire adapters :
==============
1.getListUi
2.getObjectInfo
3.getPicklistValues
4.getPicklistValuesByRecordType
5.getRecord
6.getRecordUi

Note :
The wire service delegates control flow to the Lightning web Component engine.
Delegating control is great for read operations,bit it isn't great for create and
delete operations.As a developer ,you want complete control over operations
that change data.use Javascript API instead of wire service.


Call Apex Method using wire service :
=====================================

ex:
import { LightningElement,track,Wire } from 'lwc';
import findContacts from '@salesforce/apex/ContactController.findContacts';

export default class ApexWireMethodToProperty extends LightningElement{
  @track searchkey='';
  @wire (findContacts,{ searchkey : 'searchkey'}) contacts;
 
}

Imperative Methods :
=====================
import { LightningElement,track,Wire } from 'lwc';
import getContactList from '@salesforce/apex/ContactController.getContactList';

export default class ApexImperativeMethod extends LightningElement{
 
   @track contacts;
   @track error;
 
   handleLoad(){
       getContactList()
        .then(result => {
           this.contacts=result;
         })
         .catch(error => {
          this.error=error;
         });  
 
   }

}

Javascript logic :
===================
1. ES6 classes are used to define logic.
2. ES6 module imports/exports are used to import and export logic.

ex :

 @api recordId;
 @wire(getRecord,{recordId : $recordId',fields});

 In the wire adapter's configuration object,prefix a value with $ to reference a property of the component instance.
 The $ prefix tells the wire service to treat it as a property of the class and evaluate it as this.PropertyName.
 The property is reactive. If the property's value changes,new data is provisioned
 and the component rerenders.

 Lightning web component Communication :
 ========================================

 1.Public Properties (Passing data down)

 ex :
   child component
 
   import { LightningElement,api} from 'lwc';
 
   export default class ChildComponent extends LightningElement{
     @api myProperty ='DeafultValue';
   }
 
  Parent Component
 
  <template>
     <c-child-component my-property={parentCmpProperty}></c-child-component>
  </template>
 
  Note : In child component you can assign a default value to a public property,
  but you should never change the value of a public property in the component itself.
  Remember the purpose of this property is to the Public API of the component,
  so only the parent component should set or change its value.
 
 2.Public methods (passing data down)

 public methods can receive parameters and return values.

  ex :
 
  child Coponent
 
  import { LightningElement, api } from 'lwc';

export default class ChildComponent extends LightningElement {
    @api
    doWhatever(param1) {
        // Do whatever...
        return 'Finished!';
    }
}

 Parent component

 import { LightningElement } from 'lwc';

export default class ParentComponent extends LightningElement {
   
   
        const returnValue = this.template.querySelector('c-child-component').doWhatever('My param');     
   
}

3.Custom Event (Passing data up)

ex :

 child component

 import { LightningElement } from 'lwc';

export default class ChildComponent extends LightningElement {
 
        const myEvent = new CustomEvent('eventname',
                                        {
                                            detail: {
                                                prop1: value
                                            }
                                        });
        this.dispatchEvent(myEvent);
   
}

parent component (event listener declaratively)

<template>
    <c-child-component oneventname={handleEvent}></c-child-component>
</template>

import { LightningElement } from 'lwc';

export default class ParentComponent extends LightningElement {
    handleEvent(event) {
        // Do whatever with event.detail
    }
}

Note : Event type Naming conventions ( Here "eventname" is Event Type)
1.No uppercase letters.
2.No spaces
3.Use underscores to separate words.
4.Don't prefix your event name with string 'on'.


ex : event Listener Pro-grammatically

child component

import { LightningElement } from 'lwc';

export default class ChildComponent extends LightningElement {
    handleResponse(event) {
        event.target.disabled = true;
        const btnName = event.target.label;
        const answerEvent = new CustomEvent("answer", { detail: btnName, bubbles: true });
        this.dispatchEvent(answerEvent);
    }
}

Parent Component

import { LightningElement, track } from 'lwc';

export default class ParentComponent extends LightningElement {
    @track answer = "Child: ";
    question = "Parent: Have you completed study for today?";

    constructor() {
      super();   
      this.template.addEventListener('answer', this.handleAnswer.bind(this));
    }
 
    handleAnswer(event) {
      /*eslint-disable-next-line*/
      console.log("res--&gt;" + event.detail);
      const res = event.detail;
      this.answer = this.answer + res;
    }
}

Note :

1.Add an event Listener to an element with in a shadow boundary, use this.template.addEventListener() method.
2.Add an event Listener to an element that the template doesn't own, use this.addEventListener() method directly.

 -> "this" refers to the default class.
 -> Container component can add event listeners and access elements directly on "this".
    so,we should use this.addEventListener and this.querySelector.
 -> Owner component has to add event-listeners and identification through "template".
    so,we should use this.template.addEventListener and this.template.querySelector.

ex : consider 3 components Grandparent, Parent and child

GrandParent

<template>
    <div>Grandparent:</div>
    <c-parent>
        <span slot='myslot'>
            <c-child></c-child>
        </span>
    </c-parent>
</template>

export default class Grandparent extends LightningElement {
    constructor() {
        super();
        console.log('this => ', this);       
        this.template.addEventListener('myevent', this.myeventHandlerTemplate);
    }
    renderedCallback() {       
        console.log("Grandparent renderedCallback template => ", this.template.querySelector('c-child'));
    } 
    myeventHandlerTemplate(event) {
        console.log('Grand parent template - myevent handled');
    }
}

Note :
GrandParent component is the owner of c-child component.
c-parent component is the container of c-child component.

Parent component

<template>
    <div>
        <slot name='myslot'></slot>
    </div>
</template>

export default class Parent extends LightningElement {
    constructor() {
        super();
        console.log('this => ', this);
        this.addEventListener('myevent', this.myeventHandler);
       
    }
    renderedCallback() {
        console.log("parent renderedCallback => ", this.querySelector('c-child'));
     
    }
    myeventHandler(event) {
        console.log('parent - myevent handled');
    }   
}

child component

export default class Child extends LightningElement {
    connectedCallback() {
        this.dispatchEvent(new CustomEvent('myevent', { bubbles: true }));
    }
}

Note :
bubbles:true and composed:false (default is false) will make the event bubble up until shadow boundary.

Out put :

this =>  Grandparent {setAttribute: Æ’}
this =>  Parent {setAttribute: Æ’}
parent - myevent handled
Grand parent template - myevent handled
parent renderedCallback =>  c-child
Grandparent renderedCallback template =>  c-child



4.pubsub event

1.pubsub is a singleton library that follows publish subscribe pattern.
2.Each component that subscribes to the event receives the event.

ex :

fire the event

 <template>
    <lightning-card title="Source" >
        <div class="slds-m-around_medium">
            <lightning-input type="text" onchange={handleChange} class="slds-m-bottom_small" label="Enter Text"></lightning-input>
        </div>
    </lightning-card>
</template>

import { LightningElement,wire} from 'lwc';
import { CurrentPageReference } from 'lightning/navigation';
import { fireEvent } from 'c/pubsub';
export default class Publishsource extends LightningElement {
    @wire(CurrentPageReference) pageRef;
    handleChange(event) {
        fireEvent(this.pageRef, 'inputChangeEvent', event.target.value);
    }
}

subscribe event

<template>
    <lightning-card title="Target">

        {inpVal}
    </lightning-card>
</template>

import { LightningElement, track, wire } from 'lwc';
import { CurrentPageReference } from 'lightning/navigation';
import { registerListener, unregisterAllListeners, fireEvent } from 'c/pubsub';

export default class Publishreceiver extends LightningElement {
      @track inpVal;
      @wire(CurrentPageReference) pageRef;

      connectedCallback() {
          // subscribe to inputChangeEvent event
          registerListener('inputChangeEvent', this.handleChange, this);
      }

      disconnectedCallback() {
          // unsubscribe from inputChangeEvent event
          unregisterAllListeners(this);
      }

      handleChange(inpVal) {
          this.inpVal = inpVal;
      }
}


Lightning Data service :
=========================
1.Caches results on the client.
2.Invalidates cache entry when data and meta data changes.
3.Optimizes server calls.

UI API :
============
1.Public Salesforce API to build UI.
2.Gives data and metadata in a single response.
3.UI responses respect CRUD,FLS and Sharing settings.

Base Lightning Components :
==========================
1.Lightning Record Form

supports edit,view and read-only modes.

2.Lightning Record View Form

displays a read-only form.

3.Lightning Record Edit Form

displays an editable form.

These Base Lightning Components works on top of the Lightning Data service.

Advantages of Base Lightning Components :
1.Metadata aware (data types etc).
2.Does not require Apex code
3.Provide Form Layout
4.Field labels are displayed based on Org's defaults.
5.Built on Lightning Data service and UI API.
6.Can access model statically.
7.Can also access model dynamically.


Overriding Standard Actions :
=============================
we can not directly override action with Lightning web component directly.
You need to call your component in Aura Component and use that aura component to override the action.

Lwc in Lightning Out :
======================
its possible to use LWC in visualforce as lightning out.


Composition :
==============

Owner

1.Set public properties on child.
2.Call public methods on child.
3.Listen for any events from child.

Container

1.Can read public properties on child.
2.Call public methods on child.
3.Listen for events bubbled from child.


Event Propagation Phases
========================
Event propagation can be controlled using two properties on the event.
1.bubbles
2.composed

bubbles :

1.A Boolean value indicating whether the event bubbles up through the DOM or not.
2.Defaults to false.

composed :

1.A Boolean value indicating whether the event can pass through the shadow boundary.
2.Defaults to false.

controlling Event Propagation :
===============================

1.bubbles:false and composed:false
The event doesn't bubble up through the DOM and doesn't cross the shadow boundary.

2.bubbles:true and composed:false
The event bubbles up through the DOM,but doesn't cross the shadow boundary.

3.bubbles:true and composed:true

The event bubbles up through the DOM,crosses the shadow boundary,and continues bubbling up through the DOM to the document root.

4.bubbles:false and composed:true

Lightning web components doesn't use this configuration.


Working with Third-Party Libraries :
=====================================

In LWC static resource is imported through "import" command
and then loadScript or loadStyle methods can be used to load the third-party library.

ex :

import { LightningElement } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { loadScript, loadStyle } from 'lightning/platformResourceLoader';
import D3 from '@salesforce/resourceUrl/d3';
import DATA from './data';

export default class LibsD3 extends LightningElement {
    svgWidth = 400;
    svgHeight = 400;

    d3Initialized = false;

    renderedCallback() {
        if (this.d3Initialized) {
            return;
        }
        this.d3Initialized = true;

        Promise.all([
            loadScript(this, D3 + '/d3.v5.min.js'),
            loadStyle(this, D3 + '/style.css'),
        ])
            .then(() => {
                this.initializeD3();
            })
            .catch(error => {
                this.dispatchEvent(
                    new ShowToastEvent({
                        title: 'Error loading D3',
                        message: error.message,
                        variant: 'error',
                    }),
                );
            });
    }

Lightning Locker :
==================

Lightning Locker is a layer which sits in between your browser and DOM (document object).
In other words, Lightning Locker is a virtual browser that allows only secure request to go through.
This virtual browser sits in front of your real browser which is unsafe as you get access to complete DOM and can easily manipulate it.

Sunday, 20 October 2019

Strip inaccessible fields in salesforce

To enforce FLS and CRUD in Apex.

ex :

List<Campaign> campaigns = new List<Campaign>{
    new Campaign(Name='Campaign1', BudgetedCost=1000, ActualCost=2000),
    new Campaign(Name='Campaign2', BudgetedCost=4000, ActualCost=1500)
};
insert campaigns;
// Strip fields that are not readable
SObjectAccessDecision decision = Security.stripInaccessible(
    AccessType.READABLE,
    [SELECT Name, BudgetedCost, ActualCost FROM Campaign]
);
// Print stripped records
for (SObject strippedCampaign : decision.getRecords()) {
    System.debug(strippedCampaign); // Does not display ActualCost
}
// Print modified indexes
System.debug(decision.getModifiedIndexes());
// Print removed fields
System.debug(decision.getRemovedFields());
//Lines from output log
//|DEBUG|Campaign:{Name=Campaign1, BudgetedCost=1000, Id=701xx00000011nhAAA}
//|DEBUG|Campaign:{Name=Campaign2, BudgetedCost=4000, Id=701xx00000011niAAA}
//|DEBUG|{0, 1}
//|DEBUG|{Campaign={ActualCost}}

Note :

1. You can use it remove inaccessible fields from sObjects before a DML operation
to avoid exceptions.

2. you can use the stripInaccessible() method to sanitize sObjects that
have been deserialized from an untrusted source.

Saturday, 7 September 2019

Platform cache in salesforce


Platform Cache can increase performance,replace Custom settings
and Custom Meta data Types by storing data temporarily without
any need of extra storage,and eliminates the need to use web callouts.


Note : session cache doesn't support synchronous Apex.
For example, you can't use future methods or batch Apex with
session cache.

Platform cache to improve the API callouts.


ex : access token for external service

Cache.OrgPartition orgPart = Cache.Org.getPartition('local.SomePartitionName');
orgPart.put('IntegrationAccessToken','123w12e12wzws1jnds3rbhh3');
orgPart.put('IntegrationTokenExpiry','10/03/2018');
system.debug((string)orgPart.get('IntegrationAccessToken'));


1.Org cache

Org cache can store Org-wide data such that anyone in the org can access
it.Org cache is accessible across sessions,requests, and org users and profiles.
For Org cache,data can live upto 48 hours in the cache.
By default, the time-to-live (TTL) value for org cache is 24 hours.


global values for all users
exists for upto 48 hours

2.Session Cache
specific to user sessions
Expires in 8 hours or if session ends

enterprise - 10MB (Mega bytes)
unlimited and performance - 30 MB (Mega bytes)
All others -0MB (mega bytes)

Maximum partition size - 5 MB (mega bytes)

Use Case :
============
1. Want to get top 10 by annual Revenue
2. Want to get number of VIP Accounts in each region (7 regions)

ex :

List<Account> accounts = [select Name,Region__c,BillingAddress,Description,
   Industry,Status__c,Type,Opportunity_count__c,AnnualRevenue
   from Account order by AnnualRevenue DESC NULLS LAST LIMIT 10];

   // Add to Cache
   Cache.Org.put('local.AcctPartition.TopAccounts',accounts);
 
   // Get the cache Partition
 
   cache.OrgPartition orgPart = cache.Org.getpartition('local.AcctPartition);
 
   // Get the data and cast it to the right datatype
 
   List<Account> accuntsCache = (List<Account>) orgPart.get('TopAccounts);
 
   if(accuntsCache !=null){
     return accountsCache;
   }
    return accountscache;

ex :

Map<String,Integer> accountsByRegion = new Map<String,Integer>();
List<Schema.PicklistEntry> regions = Account.Region__c.getDescribe().getPicklistValues();
for(Schema.PicklistEntry pe : regions){
  accountsByRegion.put(pe.value,0);
}

for(String regionName : accountsByRegion.keyset()){
   Integer count =[ select count() from account where Region__c =: regionName and Type ='VIP'];
   accountsByRegion.put(regionName,count);
  }
   // put any data structure into the cache
 
   Cache.Org.put('local.AcctPartition.VIPAccounts',accountsByRegion);
 
   Map<String,Integer> accountsByRegion = (Map<String,Integer>)cache.Org.getPartition('local.AcctPartition').get('VIPAccounts');
 
   if(accountsByRegion !=null){
      return convertMapToDetail(accountsByRegion);
   }
 
 return getAccountsByRegion();

 Note :
 The Cache Diagnostics user permission allows you to see detailed
 information about the platform Cache feature.

 Session cache :
 ================
 Session cache stores data that are tied to a user's session
 such that other users in the Org cannot access this data.
 The maximum life of a session cache is 8 hours.

 use the Cache.Session and cache.SessionPartition classes
 to access values stored in the session cache.

 Cache.Session.put(Key,value);


 CacheBuilder Interface :
 ========================
 public class Accountcache implements Cache.CacheBuilder{
   Public Object doLoad(String topTen){
 
   List<Account> accounts = (List<Accounts>)[select Id,AnnualRevenue,Name,Region__c
    FROM Account ORDER BY AnnualRevenue DESC NULLS LAST LIMIT 10];
  return accounts;

   
   }

 }

 CacheBuilder Interface has method with 1 parameter.
 CacheBuilder use the class and key to request.

 //populate the cache
 List<Account> myAccounts = (List<Account>) Cache.Org.get(AccountCache.class,'TopTen');

 // Retrieve from cache
 List<Account> myAccounts2 = (List<Account>) Cache.Org.get(AccountCache.class,'TopTen');

 Interface checks if value is cached.

 If cached return value else calculate,cache and return.

 Note :
 Instead of storing and retrieving cache, it is better to provide
 loading strategy toPlatform cache, so upon cache miss,Salesforce
 automatically calls the class to load the cache for that key.
 This reduces the code and handles cache miss much more gracefully.