Dynamically Creating Lightning Tabs

In this blog, I am going to show how to create a lightning component tabs dynamically by using lightning:tabset and lightning:tab components. In this example, simple I am creating four tabs dynamically when the user clicks on the button.

Lightning Component 

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global">
    <aura:attribute name="moretabs" type="Aura.Component[]"/>
    <lightning:tabset variant="scoped">
        <lightning:tab label="Item One">
            Some content here
        </lightning:tab>
        <aura:iteration items="{!v.moretabs}" var="obj">
            {!obj}
        </aura:iteration>
        
    </lightning:tabset>
    <lightning:button label="Add tab" onclick="{!c.addTab}"/>
</aura:component>

 

({
    addTab: function(component, event) {
        var detail = component.get("v.moretabs");
        var newlst =[];
        newlst.push(detail);
        for(var i=0; i <4; i++){
            $A.createComponent("lightning:tab", {
                "label": "New Tab"+i,
                "id": "new"+i,
                "onactive": component.getReference("c.addContent")
            }, function (newTab, status, error) {
                if (status === "SUCCESS") {
                    newlst.push(newTab);
                    component.set("v.moretabs", newlst);
                } else {
                    throw new Error(error);
                }
            });
        }
    },
    addContent : function(component, event) {
        var tab = event.getSource();
        switch (tab.get('v.id')){
            case 'new':
                $A.createComponent("lightning:badge", {
                    "label": "NEW"
                }, function (newContent, status, error) {
                    if (status === "SUCCESS") {
                        tab.set('v.body', newContent);
                    } else {
                        throw new Error(error);
                    }
                });
                break;
        }
    }
})

On click of the button, the tabs will created dynamically as shown below.

 

lightning:notificationsLibrary Example

In this blog, I am going to explain how to use lightning:notificationsLibrary that provides an easy way to display notices and toast in the app. lightning:notificationsLibrary  component is supported in Lightning Experience, Salesforce app, and Lightning communities only. Include one <lightning:notificationsLibrary aura:id=”notifLib”/> tag in the component that triggers the notifications, where aura:id is a unique local ID. Only one tag is needed for multiple notifications.

Notices

Notices interrupt the user’s workflow and block everything else on the page. Notices must be acknowledged before a user regains control over the app again. As such, use notices sparingly. They are not suitable for confirming a user’s action, such as before deleting a record. To dismiss the notice, only the OK button is currently supported.

<lightning:notificationsLibrary aura:id="notifLib"/>
    <lightning:button name="Show Error Notice" label="Show Error Notice" onclick="{!c.handleShowErrorNotice}"/>

 

 handleShowErrorNotice : function(component, event, helper) {
        component.find('notifLib').showNotice({
            "variant": "error",
            "title":"Error",
            "header": "Something has gone wrong!",
            "message": "Unfortunately, there was a problem updating the record.",
            closeCallback: function() {
                alert('You closed the alert!');
            }
        });
    },

Toasts

Toasts are less intrusive than notices and are suitable for providing feedback to a user following an action, such as after a record is created. A toast can be dismissed or can remain visible until a predefined duration has elapsed.

<lightning:notificationsLibrary aura:id="notifLib"/>
<lightning:button name="success" label="Show Success" onclick="{!c.handlesuccessToast}"/>

 

handlesuccessToast : function(component, event, helper) {
        component.find('notifLib').showToast({
            "variant":"success",
            "title": "Notif library Success!",
            "mode":"sticky",
            "message": "The record has been updated successfully."
        });
    }

 

The Below lightning component shows the different type of notifications.

 

<aura:component implements="flexipage:availableForAllPageTypes,force:appHostable">
    <lightning:notificationsLibrary aura:id="notifLib"/>
    <lightning:button name="Show Error Notice" label="Show Error Notice" onclick="{!c.handleShowErrorNotice}"/>
    <lightning:button name="Show info Notice" label="Show info Notice" onclick="{!c.handleShowInfoNotice}"/>
    <lightning:button name="Show warning Notice" label="Show warning Notice" onclick="{!c.handleShowWarningNotice}"/>
    <lightning:button name="info" label="Show info" onclick="{!c.handleinfoToast}"/>
    <lightning:button name="warning" label="Show Warning" onclick="{!c.handlewarningToast}"/>
    <lightning:button name="success" label="Show Success" onclick="{!c.handlesuccessToast}"/>
    <lightning:button name="Erorr" label="Show Error" onclick="{!c.handleerrorToast}"/>  
</aura:component>

 

({    
    handleShowErrorNotice : function(component, event, helper) {
        component.find('notifLib').showNotice({
            "variant": "error",
            "title":"Error",
            "header": "Something has gone wrong!",
            "message": "Unfortunately, there was a problem updating the record.",
            closeCallback: function() {
                alert('You closed the alert!');
            }
        });
    },
    handleShowInfoNotice : function(component, event, helper) {
        component.find('notifLib').showNotice({
            "variant": "info",
            "title":"Info",
            "header": "Infomration Message!",
            "message": "Please Modify the Record.",
            closeCallback: function() {
                alert('You closed the alert!');
            }
        });
    },
    handleShowWarningNotice : function(component, event, helper) {
        component.find('notifLib').showNotice({
            "variant": "warning",
            "title":"Error",
            "header": "Something has gone wrong!",
            "message": "Unfortunately, there was a problem updating the record.",
            closeCallback: function() {
                alert('You closed the alert!');
            }
        });
    },
    handleinfoToast : function(component, event, helper) {
        component.find('notifLib').showToast({
            "variant":"info",
            "title": "Notif library Success!",
            "message": "The record has been updated successfully."
        });
    },
    handlewarningToast : function(component, event, helper) {
        component.find('notifLib').showToast({
            "variant":"warning",
            "mode":"dismissable",
            "title": "Notif library Success!",
            "message": "The record has been updated successfully."
        });
    },
    handlesuccessToast : function(component, event, helper) {
        component.find('notifLib').showToast({
            "variant":"success",
            "title": "Notif library Success!",
            "mode":"sticky",
            "message": "The record has been updated successfully."
        });
    },
    handleerrorToast : function(component, event, helper) {
        component.find('notifLib').showToast({
            "variant":"error",
            "mode":"pester",
            "title": "Notif library Success!",
            "message": "The record has been updated successfully."
        });
    }
})

 

 

 

Usage of lightning:treeGrid

In this blog, I am going to show how to use lightning:treeGrid. A lightning:treeGrid component displays hierarchical data in a table. Its appearance resembles lightning:datatable, with the exception that each row can be expanded to reveal a nested group of items. Rows that contain nested data display a chevron icon to denote that they can be expanded or collapsed. Each column can be displayed based on the data type. In this example, I am going to show account and its contacts and opportunities as a tree grid.

Apex Class 

public class TreeGridExamples {
    @AuraEnabled
    public static String getTreeGridData(){
        List<Account> accs = [Select Id , Name,(Select Id , Name from Contacts) from Account];
        Map<Id , Contact> opps =new Map<Id , Contact>( [Select Id , Name,(Select Id ,Name From Opportunities) from Contact]);
        
        List<AccountWrapper> aooo = new List<AccountWrapper>();
        for(Account a : accs){
            AccountWrapper aWraper = new AccountWrapper() ; 
            aWraper.name =a.Name ;
            aWraper.label =a.Name ;
            List<Items> co = new List<Items>();
            for(Contact c : a.Contacts){
                Items conWrapp = new Items();
                conWrapp.name =c.Name ;
                conWrapp.label =c.Name ;
                
                List<Items> wrapperOooo = new List<Items>();
                for(Opportunity o : opps.get(c.Id).Opportunities){
                    Items ooo = new Items(); 
                    ooo.name = o.Name ;
                    ooo.label = o.Name ;
                    wrapperOooo.add(ooo);
                }
                
                conWrapp.items =wrapperOooo ;
                co.add(conWrapp);
            }
            aWraper.items = co;
            aooo.add(aWraper);
            
        }
        return JSON.serializePretty(aooo) ;
    } 
    public Class AccountWrapper{
        @AuraEnabled
        public String name {get;set;}
        @AuraEnabled
        public String label {get;set;}
        @AuraEnabled
        public List<Items> items {get;set;}
    }
    public Class Items{
        @AuraEnabled
        public String name {get;set;}
        @AuraEnabled
        public String label {get;set;}
        @AuraEnabled
        public List<Items> items {get;set;}
    }
    
}

Lightning Component 

<aura:component controller="TreeGridExamples">
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    <aura:attribute name="gridColumns" type="List" />
    <aura:attribute name="gridData" type="Object" />
    <aura:attribute name="gridExpandedRows" type="Object" />
    
    <lightning:treeGrid columns="{! v.gridColumns }"
                        data="{! v.gridData }"
                        keyField="name"
                        aura:id="mytree"
                        />
</aura:component>

 

({
    doInit: function (cmp, event, helper) {
        cmp.set('v.gridColumns', [
            {label: 'name', fieldName: 'name', type: 'text'},
            {label: 'label', fieldName: 'label', type: 'text'},
            ]);
        helper.getData(cmp);
    },
            
   
})

 

({
    getData : function (cmp) {
        var action = cmp.get("c.getTreeGridData");
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                var data = response.getReturnValue();
                var temojson = JSON.parse(JSON.stringify(data).split('items').join('_children'));
                console.log(temojson);
                cmp.set('v.gridData', JSON.parse(temojson));
            }
            // error handling when state is "INCOMPLETE" or "ERROR"
        });
        $A.enqueueAction(action);
    }
})

Below image shows the treegrid output.

 

 

Custom Navigation Model for Flow Screens with Lightning Component

In this blog, I am going to explain how to use the custom lightning component button that is used to control the navigation of flow.By default, users navigate a flow by clicking standard buttons at the bottom of each screen. The lightning:availableForFlowScreens interface provides two attributes to help you fully customize your screen’s navigation. To figure out which navigation actions are available for the screen, loop through the availableActions attribute. To programmatically trigger one of those actions, call the navigateFlow action from your JavaScript controller.

Flow Navigation Actions

The availableActions attribute lists the valid navigation actions for that screen NEXT, BACK, PAUSE, RESUME, FINISH are the possible actions. A screen’s available actions are determined by:

  • Where in the flow the screen is. For example, Previous isn’t supported on the first screen in a flow, Finish is supported for only the last screen in a flow, and you can never have both Next and Finish.
  • Whether the flow creator opted to hide any of the actions in the screen’s Navigation Actions controls. For example, if Allow Pause is de-selected, the Pause action isn’t included in availableActions.

Component 

Here is the lightning component

<aura:component implements="lightning:availableForFlowScreens" access="global" >
    <!-- Get the script text from the flow -->    
    <aura:attribute name="scriptText" type="String" required="true" />
    <!-- Pass the value of the selected option back to the flow -->
    <aura:attribute name="value" type="String" />
    <aura:attribute name="action" type="String" />
    <div class="script-container">
        Navigation Action :   {!v.value}
    </div>
    <!-- Buttons for the agent to click, according to the customer’s response -->
    <div class="slds-p-top_large slds-p-bottom_large">
        <p><lightning:formattedText value="Customer Response" 
                                    class="slds-text-body_small" /></p>
        <lightning:buttongroup >
            <lightning:button label="Previous" aura:id="previousId" 
                              variant="neutral" onclick="{!c.handleChange}"/>
            <lightning:button label="Next" aura:id="nextId" 
                              variant="neutral" onclick="{!c.handleChange}"/>
            <lightning:button label="Finish" aura:id="finishId" 
                              variant="neutral" onclick="{!c.handleChange}"/>
            
        </lightning:buttongroup>
    </div>
</aura:component>

 

({
    handleChange : function(component, event, helper) {
        // When an option is selected, navigate to the next screen
        var response = event.getSource().getLocalId();
        component.set("v.value", response);
        var navigate = component.get("v.navigateFlow");
        console.log('navigate'+navigate)
        if(response=='previousId'){
            navigate("BACK");
        }
        if(response=='nextId'){
            navigate("NEXT");
        }
        if(response=='finishId'){
            navigate("FINISH");
        }  
    }
})

 

<design:component>
    <design:attribute name="scriptText" label="Script Text" 
                      description="What the agent should say to the customer" />
    <design:attribute name="action" label="Navigation Action" 
                      description="" />
        
</design:component>

Flow 

Here the simple flow that I created for testing
You can see below the image that shows how the lightning component interacts with flow navigation.
Once you click the next button on the component it will take to the next action i.e Finish.