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': ''},
                                                        {'label': 'Start', 'value': ''},
                                                        {'label': 'Best Seller', 'value': ''},
                                                        {'label': 'Start Rating', 'value': ''},
                                                        {'label': 'Down Rating', 'value': ''} ,
                                                        {'label': 'Up Rating', 'value': ''} 
    <aura:iteration items="{!v.options}" var="item">
        <lightning:buttonIcon size="medium"  value="{!item.value}" title="{!item.label}" onclick="{! c.handleClick }" variant="brand"  />

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");
            "payload" : lratings,
            "extensionTitle" : "Selected Rating",
            "extensionDescription" : "Selected Rating"


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">

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.


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.





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"
                      targetFields ="{!v.oppRecord}"
    <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}"/>
        <lightning:button label="Save Opprtunity" variant="brand" onclick="{!c.handleSaveRecord}" />
    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: ' + 
            } 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}"/>   
    update : function(component, event, helper) {

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"/>

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"

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:appHomeTemplate

Now with the custom app page templatesyou no longer limited to the standard templates available for Lightning app pages. Take your business needs in hand, and create a custom page template of your own that has the structure and components that you define. Add as many regions as you need, and even custom styling.  Every standard Lightning page is associated with a default template component, which defines the page’s regions and what components the page includes. Custom Lightning page template components let you create page templates to fit your business needs with the structure and components that you define. Once implemented, your custom template is available in the Lightning App Builder’s new page wizard for your page creators to use. Implement the lightning:appHomeTemplate interface to enable your component to be used as a custom Lightning page template for pages of type App Page. This interface has no effect except when used within Lightning Experience and the Salesforce app. Each template component should implement only one template interface. Template components shouldn’t implement any other type of interface, such as flexipage:availableForAllPageTypes or force:hasRecordId. A template component can’t multi-task as a regular Lightning component. It’s either a template, or it’s not.

1. Build Template Component Structure

You need to create a custom template is a Lightning component bundle that should include at least a .cmp resource and a design resource. The .cmp resource must implement a lightning:appHomeTemplate interface, and declare an attribute of type Aura.Component[] for each template region. The Aura.Component[] type defines the attribute as a collection of components.

<aura:component implements="lightning:appHomeTemplate">
    <aura:attribute name="top" type="Aura.Component[]" />
    <aura:attribute name="center" type="Aura.Component[]" />
    <aura:attribute name="botton" type="Aura.Component[]" />
    <div class="slds-grid slds-grid_vertical">
        <div class="slds-col">
        <div class="slds-col">
        <div class="slds-col">

2.Configure  Design Resource

The design resource controls what kind of page can be built on the template. The design resource specifies what regions a page that uses the template must have. It also specifies what kinds of components can be put into those regions. Here’s the design file that goes with the .cmp resource. The label text in the design file displays as the name of the template in the new page wizard.

<design:component label="Custom App Page Template">
    <flexipage:template >
        <flexipage:region name="top" defaultWidth="LARGE"/>
        <flexipage:region name="center" defaultWidth="LARGE" />
        <flexipage:region name="botton" defaultWidth="LARGE" />

The component designer will support these tags

This tag has no attributes and acts as a wrapper for the flexipage:region tag.
This tag defines a region on the template and has these attributes.
Use this tag to specify how much space the component takes on the page based on the type of device that it renders on. This tag should be specified as a child of the flexipage:region tag. Use multiple flexipage:formFactor tags per flexipage:region to define flexible behavior across form factors.

3. (Optional) Add a Template Image

If you added a description to your .cmp resource, both it and the template image display when a user selects your template in the Lightning App Builder new page wizard. Here is the simple SVG code the component.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "">
<svg version="1.1" xmlns="" xmlns:xlink="" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<g><path d="M10,336.7h571.7v326.7H10V336.7z"/><path d="M581.7,91.7L990,500L581.7,908.3V91.7z"/></g>

4. Use in App Builder  App Page Template

Now we are going to use this template to build the custom app page template as shown below. To use this app Page templates go to the lightning app builder and include this template like as shown below.

Best Practices

Keep these best practices and limitations in mind when creating Lightning page template components.
  • Custom templates can’t be extensible nor extended—you can’t extend a template from anything else, nor can you extend other things from a template.
  • Using getters to get the regions as variables works at design time but not at runtime. 
  • Don’t add custom background styling to a template component. 
  • Including scrolling regions in your template component can cause problems when you try to view it in the Lightning App Builder.
  • You can remove regions from a template as long as it’s not being used by a Lightning page, and as long as it’s not set to access=global. You can add regions at any time.
  • A region can be used more than once in the code, but only one instance of the region should render at runtime.
  • A template component can contain up to 25 regions.


Flow Local Actions Using Lightning Components

                    Flow Local Actions Using Lightning Components allow you to execute client-side logic in your flow, build or modify custom Lightning components to use as local actions in flows. For example, get data from third-party systems without going through the Salesforce server, or open a URL in another browser tab. Once you configure the Lightning component’s markup, client-side controller, and design resource, it appears in the Cloud Flow Designer as a Local Action element. In this example, the input screen on the flow will take a country name and from there invoke the local action and return the country information from the web service.

How to add Flow Local Actions 

          Add the lightning:availableForFlowActions interface to a Lightning component to make it available as a flow action. When a component is executed as a flow action, the flow calls the invoke method in the client-side controller. Flows that include Lightning components are supported only in Lightning runtime. Lightning components that implement lightning:availableForFlowActions are available as Local Action elements in the Cloud Flow Designer. When a component is executed as a flow local action, the flow calls the invoke method in the client-side controller. To run the code asynchronously in your client-side controller, such as when you’re making an XML HTTP request (XHR), return a Promise. When the method finishes or the Promise is fulfilled, control is returned back to the flow.

Flow Action Component 

Here is the simple component that we will be used as flow action.
<aura:component implements="lightning:availableForFlowActions" access="global">
    <aura:attribute name="countryName" type="String" default="USA" access="global" />
    <aura:attribute name="response" type="String" default="USA" access="global" />
    invoke : function(component, event, helper) {
        var cancelToken = event.getParam("arguments").cancelToken;
        return new Promise(function(resolve, reject) {
            var xhttp = new XMLHttpRequest();
            xhttp.onreadystatechange = $A.getCallback(function() {
                if (this.readyState === 4) { 
                    if (this.status >= 200 && this.status < 300) {
                        var response = JSON.parse(xhttp.responseText);
                        component.set("v.response", JSON.stringify(response));
                    } else {
                        var errorText = "";
                        if (this.status === 0) {
                            errorText = 'Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.';
                        } else {
                            errorText = this.statusText;
            var countryName = component.get("v.countryName");
  "GET", ""+countryName, true);
            cancelToken.promise.then(function(error) {
When a component is executed as a flow local action, the flow calls the invoke method in the client-side controller. To run the code asynchronously in your client-side controller, such as when you’re making an XML HTTP request (XHR), return a Promise. When the method finishes or the Promise is fulfilled, control is returned back to the flow. When a Promise is resolved, the next element in the flow is executed. When a Promise is rejected or hits the timeout, the flow takes the Local Action element’s fault connector and sets $Flow.FaultMessage to the error message. By default, the error message is “An error occurred when the elementName element tried to execute the c:FlowAction component.” To customize the error message in $Flow.FaultMessage, return it as a new Error object in the reject() call. When a Promise is fulfilled, the next element in the flow is executed. When a Promise is rejected or times out, the flow takes the Local Action element’s fault connector and sets $Flow.FaultMessage to the error message. By default, the error message is “An error occurred when the flow tried to execute the c:FlowAction component.”. To customize the error message, return it as an error in the reject() call.

Configure the designer 

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 corresponding Local Action element.

    <design:attribute name="countryName" label="String"  />
    <design:attribute name="response" label="String"  />

Invoke Action from the Flow 

Now go to the cloud flow designer and create a new screen element to enter the country name

Add the Flow locale actions into the screen and configure the input params as shown below.

Create a screen element to show the output response as shown below.
Final screen flow looks like below


Synchronous Code

the example code we have seen so far is Asynchronous Code where we will get the promise and here is the synchronous version of the controller.js

    invoke : function(component, event, helper) {
        var cancelToken = event.getParam("arguments").cancelToken;
        var xhttp = new XMLHttpRequest();
        var countryName = component.get("v.countryName");"GET", ""+countryName, false);
        if (xhttp.status === 200) {
            component.set("v.response", JSON.stringify(xhttp.responseText));