Navigate to Component Using Lightning Navigation API

With summer 18 release, navigating with to lightning components is made easier with new navigation API. With the lightning:isUrlAddressable interface, you now control which Lightning components can be opened programmatically. You can also now easily capture URL parameters using the v.pageReference attribute and use the parameter values in your component. With the lightning:navigation component, define a pageReference object for navigating to a custom component that implements lightning:isUrlAddressable and set any attributes the component allows. In standard navigation Lightning apps, you can use the lightning:navigation component to navigate to a custom component that implements lightning:isUrlAddressable. Using lightning:navigation with pageReference provides the following benefits over the now deprecated force:navigateToComponent for standard navigation Lightning apps.

  • Gives you control over whether a component can be opened programmatically, and which attributes can be dynamically set when
    the component is opened.
  • Control and manage which URL parameters are used in your component.
  •  Future-proofs your apps from changes in URL format.
  •  Generates a user-friendly URL for these components.

Quick Notes 

  • New interface lightning:isUrlAddressable is available for components that need to be implemented to navigated directly via URL
  • This interface is used with the component lightning:navigation to navigate from one component to the URL-addressable component. This navigation feature is only supported in Salesforce Lightning and the Salesforce Mobile App.
  • The lightning:isUrlAddressable interface extends the lightning:hasPageReference interface.
  • A component that implements lightning:isUrlAddressable then gets access to the page state through the pageReference attribute.
  • The page state is a representation of the current URL query parameters.
  • lightning:isUrlAddressable enables you to generate a user-friendly URL for a Lightning component with the pattern /cmp/componentName instead of the base-64 encoded URL you get with the deprecated  force:navigateToComponent event.

Usage

For example, c:hellotarget displays a string that’s passed in from another component from the navigation url.

hellotarget.cmp

<aura:component implements="lightning:isUrlAddressable" description="c:helloTarget component">
    <aura:attribute name="firstname" type="String" />
    <aura:handler name="init" value="{!this}" action="{!c.init}"/>
    Hello {!v.firstname}.
   
</aura:component>

In c:hellotarget component’s client-side controller, retrieve the attribute values from the page state.

({
    init: function(cmp, evt, helper) {
        var myPageRef = cmp.get("v.pageReference");
        var firstname = myPageRef.state.c__firstname;
        cmp.set("v.firstname", firstname);
    }
})

In the component that you want to trigger the navigation, include an instance of the lightning:navigation component. Then include the component to perform the jump to the other component. In this example, a lightning:button component is added to c:hello to trigger the navigation to the URL addressable component.

hello.cmp

<aura:component description="c:hello component" implements="flexipage:availableForAllPageTypes">
    <aura:attribute name="pageReference" type="Object"/>
    <aura:handler name="init" value="{! this }" action="{! c.init }"/>
    <lightning:navigation aura:id="navService"/>
    <lightning:button label="Navigate" onclick="{!c.handleClick}"/>
</aura:component>

Define your page reference for the component you’re navigating to. We recommend setting the page reference using an init handler. This example stores the pageReference in an attribute in the component, and is used to navigate later in the click handler.

({
    init : function(component, event, helper) {
        var pageReference = {
            type: 'standard__component',
            attributes: {
                componentName: 'c__helloTarget',
            },
            state: {
                "c__firstname": "John"
            }
        };
        component.set("v.pageReference", pageReference);
    },
    handleClick: function(component, event, helper) {
        var navService = component.find("navService");
        var pageReference = component.get("v.pageReference");
        event.preventDefault();
        navService.navigate(pageReference);
    }
})

Clicking the button in c:hello directs you to /lightning/cmp/c__helloTarget?c__firstname=John, and Hi John is displayed on the c:helloTarget page.

lightning/cmp/c__helloTarget?c__firstname=John

 

 

Chatter Rich Publisher Apps Example

                                                    Use the Chatter Rich Publisher Apps API to integrate your custom apps into the Chatter publisher. The Rich Publisher Apps API enables developers to attach any custom payload to a feed item. Rich Publisher Apps uses lightning components for composition and rendering. Salesforce provides two lightning interfaces and a lightning event to assist with integration. Rich Publisher Apps are available to Lightning communities in topics, group, and profile feeds and indirect messages. Use the lightning:availableForChatterExtensionComposer interface to integrate your custom apps into the Chatter publisher and place the custom app’s payload in the feed. This interface is available in Lightning communities. Use the lightning:availableForChatterExtensionRenderer interface to integrate your custom apps into the Chatter publisher and place the custom app’s payload in the feed. This interface is available in Lightning communities. The lightning:availableForChatterExtensionComposer interface works with the lightning:availableForChatterExtensionRenderer interface and the lightning:sendChatterExtensionPayload event to integrate your custom apps into the Chatter publisher and to render the app’s payload in the feed.

1. Set Up the Composer Component

For the composer component, we created the component, controller, helper, and style files. Here is the component markup in compose.cmp. In this file, we implement the lightning:availableForChatterExtensionComposer interface.

<aura:component implements="lightning:availableForChatterExtensionComposer">
    <aura:attribute name="options" type="List" default="[
                                                        {'label': 'Gold Badge', 'value': 'https://img.icons8.com/dusk/50/000000/prize.png'},
                                                        {'label': 'Start', 'value': 'https://img.icons8.com/color/50/000000/sheriff.png'},
                                                        {'label': 'Best Seller', 'value': 'https://img.icons8.com/dusk/50/000000/best-seller.png'},
                                                        {'label': 'Start Rating', 'value': 'https://img.icons8.com/dusk/50/000000/star.png'},
                                                        {'label': 'Down Rating', 'value': 'https://img.icons8.com/flat_round/50/000000/thumbs-down.png'} ,
                                                        {'label': 'Up Rating', 'value': 'https://img.icons8.com/color/50/000000/facebook-like.png'} 
                                                        ]"/>
    <aura:iteration items="{!v.options}" var="item">
        <lightning:buttonIcon size="medium"  value="{!item.value}" title="{!item.label}" onclick="{! c.handleClick }" variant="brand"  />
    </aura:iteration>
    
</aura:component>

Use your controller and helper to initialize the composer component and to get the rating from a source. Once you get the rating, fire the event sendChatterExtensionPayload. Firing the event enables the Add button so the platform can associate the app’s payload with the feed item. You can also add a title and description as metadata for the payload. The title and description are shown in a non-Lightning context, like Salesforce Classic.

({
    handleClick : function (cmp, event, helper) {
        var lratings =event.getSource().get("v.label");    
        var compEvent = cmp.getEvent("sendChatterExtensionPayload");
        compEvent.setParams({
            "payload" : lratings,
            "extensionTitle" : "Selected Rating",
            "extensionDescription" : "Selected Rating"
        });
        compEvent.fire(); 
    }
    
})

 

2. Set Up the Renderer Component

Here is the component markup in Render.cmp. In this, we implement the lightning:availableForChatterExtensionRenderer interface, which provides the payload as an attribute in the component. You have a couple of ways of dealing with the payload. You can use the payload directly in the component {!v.payload}. You can use your controller to parse the payload provided by the lightning:availableForChatterExtensionRenderer interface and set its attributes yourself.

<aura:component implements="lightning:availableForChatterExtensionRenderer">
    {!v.payload}
 </aura:component>

3. Get the Asset Id

You need to get the asset id that shows as a charter extension icon. Go and upload the image in files as shown below

Get the File Id from the URL. After that Use the below Rest URI to get the Asset Id.

/services/data/v43.0/connect/files/0691U000000Lup8/asset

Go to Workbench > utilities > REST Explorer and make a new POST request for creating a file asset with a file Id from your Org.

 

4. Get Renderer and Composer Component Ids 

You need to get the component composer and render record ids to setup the Chatter Publisher. Use below SOQL

Select Id , DeveloperName from AuraDefinitionBundle

5. Set Up a New ChatterExtension Entity

ChatterExtension represents the metadata used to describe a Rich Publisher App that’s integrated with the Chatter publisher. Here is the key metadata about chatter extension. 

Not go to Workbench  Make sure that you’re using at least API version 41.0. Log in to your org, and create a ChatterExtension entity.

From the Data menu, select Insert.

In the Value column, provide values for charter extension fields. click confirm insert.

6. Select the Apps to Embed in the Chatter Publisher

An admin page is available in each community for selecting and arranging the apps to show in the Chatter publisher. Select up to five apps, and arrange them in the order you like. The order you set here controls the order the app icons appear in the publisher. In your community, go to Community Workspaces and open the Administration page. Click Rich Publisher Apps to open the page.

 

After you include the Rich Publisher Apps into the community, you can able to see the new icon as shown below image.

On click of the chatter publish action icon you can able to see the ratings. select the rating and click add to post on chatter.

 

References

https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/components_integrate_customapps_to_publisher.htm

https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/meta_chatterextensions.htm#meta_chatterextensions

 

https://developer.salesforce.com/docs/atlas.en-us.216.0.chatterapi.meta/chatterapi/connect_resources_files_asset.htm

 

Usage of lightning:actionOverride

Here we will understand how to override the different salesforce standard action on lightning using lightning component. In order to override any action, your component must implement lightning:actionOverride interface. This interface is a marker interface. A marker interface is a signal to the component’s container to add the interface’s behavior to the component. You don’t need to implement any specific methods or attributes in your component, you simply add the interface name to the component’s implements attribute. The lightning:actionOverride doesn’t add or require any attributes on components that implement it. Components that implement this interface don’t automatically override any action. You need to manually override relevant actions in Setup. However in Lightning Experience, the standard Tab and View actions display as a page, while the standard New and Edit actions display in an overlaid panel. When used as action overrides, Lightning components that implement the lightning:actionOverride interface replace the standard behavior completely. However, overridden actions always display as a page, not as a panel. Your component displays without controls, except for the main Lightning Experience navigation bar. Your component is expected to provide a complete user interface for the action, including navigation or actions beyond the navigation bar.

Overriding the new action 

Here is the sample code to override the new action. the component has implemented the lightning:actionOverride interface and we are using the force:recordData for input form.

<aura:component implements="lightning:actionOverride,force:appHostable,force:hasRecordId,force:hasSObjectName,flexipage:availableForRecordHome,flexipage:availableForAllPageTypes"> 
    
    <aura:attribute name="record" type="Object"/>
    <aura:attribute name="oppRecord" type="Object" />
    <aura:attribute name="recordError" type="String"/>
    
    <force:recordData aura:id="record"
                      layoutType="FULL"
                      recordId="{!v.recordId}"
                      targetError="{!v.recordError}"
                      targetRecord="{!v.record}"
                      targetFields ="{!v.oppRecord}"
                      mode="EDIT"/>
    
    <lightning:card title="New  Opportunity">
        <lightning:input label="Opprtunity Name" value="{!v.record.Name}"/>
        <lightning:input label="Opprtunity Amount" value="{!v.record.Amount}"/>
        <lightning:input label="Opprtunity Stage" value="{!v.record.StageName}"/>
        <lightning:input label="Opprtunity Type" value="{!v.record.Type}"/>
        <lightning:input label="Opprtunity CloseDate" value="{!v.record.CloseDate}"/>
        <lightning:input label="Account" value="{!v.record.AccountId}"/>
        <br/>
        <lightning:button label="Save Opprtunity" variant="brand" onclick="{!c.handleSaveRecord}" />
    </lightning:card>
</aura:component>
({
    handleSaveRecord: function(component, event, helper) {
        component.find("recordEditor").saveRecord($A.getCallback(function(saveResult) {
            if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {
                console.log("Save completed successfully.");
            } else if (saveResult.state === "INCOMPLETE") {
                console.log("User is offline, device doesn't support drafts.");
            } else if (saveResult.state === "ERROR") {
                console.log('Problem saving record, error: ' + 
                           JSON.stringify(saveResult.error));
            } else {
                console.log('Unknown problem, state: ' + saveResult.state + ', error: ' + JSON.stringify(saveResult.error));
            }
        }));}
})

Now go ahead and override the new action with the above code as shown below

Once you click on the new button it will prompt the new screen as shown below.

Overriding the Edit Action 

Use the below code to override the edit action. In this example we are using force:recordEdit to show the edit form.

<aura:component implements="lightning:actionOverride,force:hasRecordId,force:hasSObjectName" access="global"> 
    <lightning:card title="Opportunity Edit">
        <force:recordEdit aura:id="edit" recordId="{!v.recordId}"/>
        <lightning:button label="update" onclick="{!c.update}"/>   
    </lightning:card>
</aura:component>
({
    update : function(component, event, helper) {
        component.find("edit").get("e.recordSave").fire();
    }
})

Go and override the Edit action with the above code as shown below.
Once you click on the edit button you can able to see the screen as shown below.

 

Overring The View Action 

Use the below code to override the view action. Here I am using the force: recordView form to view the data.

<aura:component implements="lightning:actionOverride,force:hasRecordId,force:hasSObjectName" access="global"> 
    <lightning:card title="Opportunity Details">
        <force:recordView recordId="{!v.recordId}" type="FULL"/>
    </lightning:card>
</aura:component>

Now override the view action as shown below.

Once you are trying to view the record you can able to see the screen as shown below

Overriding the Tab 

Use the below code to override the tab. In this example, i am using the lightning:listView  to get the list of opportunities.

<aura:component implements="lightning:actionOverride,force:hasRecordId,force:hasSObjectName"> 
    <lightning:card title="Opportnity Tab Override by using action override ">
        <lightning:listView aura:id="listViewOpp"
                            objectApiName="Opportunity"
                            listName="AllOpportunities"
                            rows="25"
                            showSearchBar="true"
                            showActionBar="true"
                            enableInlineEdit="true"
                            showRowLevelActions="true"
                            />
    </lightning:card>
</aura:component>

Now override the tab action with the above code as shown below

You can see the opportunity tab now as shown below.

 

 

Usage Of lightning:availableForFlowScreens

Salesforce flow is one of the most powerful business automation tools that will be used to build the application with drag and drop. Now we will see how to use the lightning component available for the flow screens. Make your custom Lightning components available to flow screens in the Cloud Flow Designer by implementing the lightning:availableForFlowScreens interface. In the Cloud Flow Designer, flow screen components appear as options for Lightning component screen fields. In this example, I will get the current conversion rates from the external API and will display on the flow by using component.

Apex class
public class FlowGetExchangeRates {
    
    @AuraEnabled
    public static ConversionRates getConversionRates(String source , String target){
        ConversionRates cr = new ConversionRates() ;
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint('http://apilayer.net/api/live?access_key=456fab5d3bee967f81169416e234387e&currencies='+target+'&source='+source+'&format=1');
        request.setMethod('GET');
        System.debug('response'+request);
        HttpResponse response = http.send(request);
        if (response.getStatusCode() == 200) {
            Map<String, Object> results = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
            System.debug('results'+results);
            Map<String , Object> qts = (Map<String , Object>) results.get('quotes');
            for(String s : qts.keySet() ){
                System.debug('s'+s);
                if(s=='USDEUR'){
                    cr.USDEUR =  String.valueOf((Object)qts.get(s));
                }
                if(s=='USDGBP'){
                    cr.USDGBP =  String.valueOf((Object)qts.get(s));
                }
                if(s=='USDCAD'){
                    cr.USDCAD =  String.valueOf((Object)qts.get(s));
                }
                if(s=='USDPLN'){
                    cr.USDPLN =  String.valueOf((Object)qts.get(s));
                }
            }
        }
        return cr ; 
        
    }
    
    
    public class ConversionRates{
        @AuraEnabled
        public String USDEUR{get;set;}
        @AuraEnabled
        public String USDGBP{get;set;}
        @AuraEnabled
        public String USDCAD{get;set;}
        @AuraEnabled
        public String USDPLN{get;set;}
        
        
    }
    
}

The above class is covert the exchange rates based on the source currency specified. Make sure you added the Rest API URI to remove site settings.

Lightning component 

<aura:component implements="lightning:availableForFlowScreens" access="global" Controller="FlowGetExchangeRates">
    <aura:attribute name="sourcecurrencies" type="String" access="global" default="USD"/>
    <aura:attribute name="targetcurrencies" type="String" access="global" default="EUR,GBP,CAD,PLN" />
    <aura:attribute name="resVal" type="FlowGetExchangeRates.ConversionRates" access="global"  />
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    
    <table class="slds-table slds-table_cell-buffer slds-table_bordered slds-table_striped">
        <tr>
            <th>USD</th>
            <th>Conveted Val</th>
        </tr>
        <tr>
            <td>EUR</td>
            <td>{!v.resVal.USDEUR}</td>
        </tr>
        <tr>
            <td>GBP</td>
            <td>{!v.resVal.USDGBP}</td>
        </tr>
        <tr>
            <td>CAD</td>
            <td>{!v.resVal.USDCAD}</td>
        </tr>
        <tr>
            <td>PLN</td>
            <td>{!v.resVal.USDPLN}</td>
        </tr>
    </table>
    
    
</aura:component>

 

({
    doInit : function(component, event, helper) {
        var action=  component.get('c.getConversionRates'); 
        action.setParams({"source":component.get("v.sourcecurrencies") , "target":component.get("v.targetcurrencies")})
        action.setCallback(this,function(response){
            var state=response.getState();
            if(state=='SUCCESS')
            {
                component.set('v.resVal',response.getReturnValue()); 
            }
        });
        $A.enqueueAction(action);
    }
})

To make an attribute’s value customizable in the Cloud Flow Designer, add it to the component’s design resource. That way, flow admins can pass values between that attribute and the flow when they configure the Local Action element. That way, flow admins can pass values between that attribute and the flow when they configure the screen field. Here is the designer for component

<design:component>
    <design:attribute name="sourcecurrencies" label="sourcecurrencies"  default="USD"/>
    <design:attribute name="targetcurrencies" label="targetcurrencies"  default="EUR,GBP,CAD,PLN" />
</design:component>

A design resource describes the design-time behavior of a Lightning component information that visual tools need to allow adding the component to a page or app. Adding this resource is similar to adding it for the Lightning App Builder. When admins reference this component in a flow, they can pass data between the flow and the Lightning component. Use the Inputs tab to set an attribute using values from the flow. Use the Outputs tab to store an attribute’s value in a flow variable

Use Component in flow 

Now we will use the above lightning component in flow designer. Go to salesforce flow builder and create a new flow. Drag and Drop the screen element to flow designer and configure the flow screen as shown below. the flow contains the two input text element that will accept the source and target currencies.

 

Drag and drop another screen element into the designer and configure flow to receive the input values from the first screen element as shown below.

Click save. Connect the two flow screen elements as shown below. Set the first screen as a starting element

Testing 

Now go to the flow and enter the source and target currencies as shown below

Click Next and you will see the result from the Lightning component as shown below.