Category Archives: JavaScript

Salesforce Live Agent Error : Prechat API is not enabled by the specified deployment

In Live Agent, sometimes we need to pass some values from the page, where Start Chat button is located, to Pre-chat form.

To achieve this, we use liveagent.addCustomDetail() function to set the values. On Pre-chat form page, we use prechat.js and liveagent.details.preChatInit() function to access those details.

But if the “Allow Access to Pre-Chat API” in deployment is not enable, then we will face “Prechat API is not enabled by the specified deployment” JavaScript error.

Follow below steps to enable it.

Go to Setup || Customize || Live Agent || Deployments || Edit or Create your Deployment || Enable “Allow Access to Pre-Chat API” || Save

Lightning Tab With Next And Back Buttons In Lightning Component

Component:

<!--TabComponent-->
<aura:component>
    <aura:attribute name="selTabId" type="String" default="tab1" />
    <div aura:id="data-entry">
        <lightning:tabset variant="default" selectedTabId="{!v.selTabId}" >
            <lightning:tab label="Mobile" aura:id="tab1" tabindex="1" id="tab1" title="Mobile">
                <p>Apple</p>
                <p>Samsung</p>
                <p>Lenovo</p>
            </lightning:tab>
            
            <lightning:tab label="Laptop" aura:id="tab2" tabindex="2" id="tab2" title="Laptop">
                <p>Apple</p>
                <p>Lenovo</p>
                <p>Dell</p>
            </lightning:tab>  
            
            <lightning:tab label="Tablet" aura:id="tab3" tabindex="3" id="tab3" title="Tablet">
                <p>Apple</p>
                <p>Lenovo</p>
                <p>Dell</p>
            </lightning:tab> 
        </lightning:tabset>
    </div>
    
    <div class="slds-clearfix">
        <div class="slds-float_left">
            <!--disabled the back button on first Tab-->    
            <lightning:button disabled="{!v.selTabId == 'tab1'}" variant="neutral" label="Back" onclick="{!c.back}" />
        </div>
        <div class="slds-float_right">
            <!--disabled the back button on last Tab--> 
            <lightning:button variant="brand" disabled="{!v.selTabId == 'tab3'}" label="Next" onclick="{!c.next}" />
        </div>
    </div>
</aura:component>

Component Controller:

({
    next : function(component, event, helper) {
        //Get the current selected tab value
        var currentTab = component.get("v.selTabId");
        
        if(currentTab == 'tab1'){
            component.set("v.selTabId" , 'tab2');   
        }else if(currentTab == 'tab2'){
            component.set("v.selTabId" , 'tab3');     
        }
    },
    
    back : function(component, event, helper) {
        //Get the current selected tab value  
        var currentTab = component.get("v.selTabId");
        
        if(currentTab == 'tab2'){
            component.set("v.selTabId" , 'tab1');     
        } else if(currentTab == 'tab3'){
            component.set("v.selTabId" , 'tab2');     
        }
    }
})

Output:

Navigate From One Lightning Component to Another Lightning Component

Component1:

<!--Component1-->
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes">
    <ui:button label="Navigate to Component2" press="{!c.navigate}"/>
    {!v.body}    
</aura:component>

Component1 Controller:

({
    navigate : function(component, event, helper) {
        $A.createComponent(
            "c:Component2",
            {
                
            },
            function(newCmp){
                if (component.isValid()) {
                    var body = component.get("v.body");
                    body.push(newCmp);
                    component.set("v.body", body);
                }
            }
        );	        
    }
})

Component2:

<!--Component2-->
<aura:component>
    Component2 Successfully Loaded!
</aura:component>

Dynamic Add Delete Row In Lightning Component

In below example I’m adding account record in Salesforce Lightning Component with Add Delete Rows functionality.

Here I’ve created 2 lightning components and 2 lightning events, by these lightning components you can create multiple records as your requirement by Adding or Deleting new rows.

Step1 : Create Lightning Event “AddRowEvent.evt”

<aura:event type="COMPONENT" description="Event to add row"></aura:event>

Step2 : Create Lightning Event “DeleteRowEvent.evt”

<aura:event type="COMPONENT" description="Event to delete row" >
    <aura:attribute name="indexVar" type="Integer" description="Use For Delete Row" />
</aura:event>

Step3 : Create Lightning Component “Child.cmp”.

<!--Child-->
<aura:component >    
    <!--Attribute for store single Account object instance--> 
    <aura:attribute name="AccountInstance" type="Account"/>
    <!--Attribute for store Index of Particular Instance --> 
    <aura:attribute name="rowIndex" type="String"/>
    
    <!-- Register 2 Lightning Event for handle add or Delete rows on Parent Component  --> 
    <aura:registerEvent name="DeleteRowEvent" type="c:DeleteRowEvent"/> 
    <aura:registerEvent name="AddRowEvent" type="c:AddRowEvent"/> 
    
    <!-- Table Row -->   
    <tr class="slds-text-title_caps">
        <td> 
            {!v.rowIndex + 1}
        </td>
        <td>
            <ui:inputText class="slds-input" value="{!v.AccountInstance.Name}"/>
        </td>
        <td>
            <ui:inputText class="slds-input" value="{!v.AccountInstance.AccountNumber}"/>
        </td>
        <td>
            <ui:inputPhone class="slds-input" value="{!v.AccountInstance.Phone}"/>
        </td>
        <td>
            <!-- conditionally Display Add or Delete Icons, if rowIndex is 0 then show add row Icon else show delete Icon--> 
            <aura:if isTrue="{!v.rowIndex == 0}">
                <a onclick="{!c.addRow}">
                    <lightning:icon iconName="utility:add" class="slds-icon slds-icon_small" size="small" alternativeText="Add"/>
                    <span class="slds-assistive-text">Add</span>
                </a>    
                <aura:set attribute="else">
                    <a onclick="{!c.deleteRow}">
                        <lightning:icon variant="error" iconName="utility:delete" class="slds-icon slds-icon_small" size="small" alternativeText="Delete"/>
                        <span class="slds-assistive-text">Delete</span>
                    </a>
                </aura:set> 
            </aura:if>
        </td> 
    </tr>
</aura:component>

Step4 : Add “Child.cmp” controller “ChildController.js” method.

  • “addRow” method to add row.
  • “deleteRow” method to delete row.
({
    addRow : function(component, event, helper){
        //Execute the AddRowEvent Lightning Event 
        component.getEvent("AddRowEvent").fire();     
    },
    
    deleteRow : function(component, event, helper){
        //Execute the DeleteRowEvent Lightning Event and pass the deleted Row Index to Event attribute
        component.getEvent("DeleteRowEvent").setParams({"indexVar" : component.get("v.rowIndex") }).fire();
    }, 
    
})

Step5 : Create Apex Controller “AuraSampleController.apxc”.

  • “SaveAccounts” method to save list of Account.
public with sharing class AuraSampleController{
   @AuraEnabled
    public static void SaveAccounts(List<Account> accList){
        Insert accList;
    }
}

Step6 : Create Lightning Component “Parent.cmp”

<!--Parent-->
<aura:component controller="AuraSampleController" Implements="flexipage:availableForRecordHome,force:hasRecordId">
    <!--Init handler which is call doInit js function on component Load-->  
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    
    <!--Event handler for Add and Delete Row Event which is execute from Child Component-->    
    <aura:handler name="DeleteRowEvent" event="c:DeleteRowEvent" action="{!c.removeDeletedRow}"/>
    <aura:handler name="AddRowEvent" event="c:AddRowEvent" action="{!c.addRow}"/>
    
    <!--Aura Attribute for store Account Object List as Array-->    
    <aura:attribute name="AccountList" type="Account[]"/> 
    
    <!--Header Part-->        
    <div class="slds-page-header">
        <h1 class="slds-page-header__title">Create Multiple Accounts in Lightning</h1>
    </div>
    
    <!--Table Part-->           
    <table class="slds-table slds-table_bordered slds-table_cell-buffer"> 
        <thead>
            <tr class="slds-text-title_caps">
                <th scope="col">
                    <div class="slds-truncate">#</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Account Name">Account Name</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Account Number">Account Number</div>
                </th>
                <th scope="col">
                    <div class="slds-truncate" title="Phone">Phone</div>
                </th>
                 <th scope="col">
                    <div class="slds-truncate" title="Action">Action</div>
                </th>
            </tr>
        </thead>   
        <tbody>
            <!--Iterate the child Component for display Table rows 
               with pass the List Item Index for track the Every child Component 
               and pass each List Account Instance -->         
            <aura:iteration items="{!v.AccountList}" var="item" indexVar="index">
                <c:Child AccountInstance="{!item}" rowIndex="{!index}" />
            </aura:iteration>
        </tbody>
    </table>
    <br/>
    <!--Save Button which is call Save js function on click --> 
    <button class="slds-button slds-button_brand"  onclick="{!c.Save}">Save</button>
</aura:component>

Step7 : Add “Parent.cmp” controller “ParentController.js” method.

  • “doInit” method for component load.
  • “Save” method for data Save.
  • “addRow” method to add new row.
  • “removeDeletedRow” method to remove delete row from list.
({
    
    // function call on component Load
    doInit: function(component, event, helper) {
        // create a Default RowItem [Account Instance] on first time Component Load
        // by call this helper function  
        helper.createObjectData(component, event);
    },
    
    // function for save the Records 
    Save: function(component, event, helper) {
        // first call the helper function in if block which will return true or false.
        // this helper function check the "Account Name" will not be blank on each row.
        if (helper.validate(component, event)) {
            // call the apex class method for save the Account List
            // with pass the contact List attribute to method param.  
            var action = component.get("c.SaveAccounts");
            action.setParams({
                "accList": component.get("v.AccountList")
            });
            // set call back 
            action.setCallback(this, function(response) {
                var state = response.getState();
                if (state === "SUCCESS") {
                    // if response if success then reset the 'AccountList' Attribute 
                    // and call the common helper method for create a default Object Data to Account List 
                    component.set("v.AccountList", []);
                    helper.createObjectData(component, event);
                    alert('Account records saved successfully');
                }
            });
            // enqueue the server side action  
            $A.enqueueAction(action);
        }
    },
    
    // function for create new object Row in Contact List 
    addRow: function(component, event, helper) {
        // call the comman "createObjectData" helper method for add new Object Row to List  
        helper.createObjectData(component, event);
    },
    
    // function for delete the row 
    removeDeletedRow: function(component, event, helper) {
        //get the selected row Index for delete, from Lightning Event Attribute  
        var index = event.getParam("indexVar");
        //get the all List (AccountList attribute) and remove the Object Element Using splice method    
        var AllRowsList = component.get("v.AccountList");
        AllRowsList.splice(index, 1);
        //set the AccountList after remove selected row element  
        component.set("v.AccountList", AllRowsList);
    },
})

Step8 : Add “Parent.cmp” component helper “ParentHelper.js” method.

  • “createObjectData” method for create new instance of Account object.
  • “validate” method to validate Account Name.
({
    createObjectData: function(component, event) {
        //get the AccountList from component and add(push) New Object to List  
        var RowItemList = component.get("v.AccountList");
        RowItemList.push({
            'sobjectType': 'Account',
            'Name': '',
            'AccountNumber': '',
            'Phone': ''
        });
        // set the updated list to attribute (AccountList) again    
        component.set("v.AccountList", RowItemList);
    },
    //helper function for check if Account Name is not null/blank on save  
    validate: function(component, event) {
        var isValid = true;
        var allAccountRows = component.get("v.AccountList");
        for (var indexVar = 0; indexVar < allAccountRows.length; indexVar++) {
            if (allAccountRows[indexVar].Name == '') {
                isValid = false;
                alert('Account Name Cannot be blank on row number ' + (indexVar + 1));
            }
        }
        return isValid;
    },
})

Step9 : Create Lightning App “MyDemo.app”.

<!--MyDemo-->
<aura:application implements="force:appHostable" extends="force:slds">
    <c:Parent />    
</aura:application>

Output :

Create Account Record :

Created Account Records :

Call Multiple Apex Methods in Lightning Controller

Apex Controller:

public with sharing class AccountController {

    @AuraEnabled
    public static Account getAccount(Id accountId) {
        Account acc = new Account();
        acc = [SELECT Id, Name, Description FROM Account WHERE Id=:accountId];
        return acc;
    }
    
    @AuraEnabled
    public static List<Attachment> getAttachments(Id parentId) {                            
        List<Attachment> listAttachment = new List<Attachment>();
        listAttachment = [SELECT Id, Name FROM Attachment WHERE ParentId = :parentId];
        return listAttachment;
    }
}

Lightning Component:

<aura:component controller="AccountController" implements="force:appHostable,flexipage:availableForAllPageTypes,force:hasRecordId" access="global">
    <aura:attribute name="recordId" type="Id" />
    <aura:attribute name="acc" type="Account"/>
    <aura:attribute name="attachments" type="Attachment[]"/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    
    <div>
        <div>{!v.acc.Name}</div>
        <div>{!v.acc.Description}</div>
        
        <ul>
            <aura:iteration items="{!v.attachments}" var="a">
                <li>
                    <a target="_blank" href="{! '/servlet/servlet.FileDownload?file=' + a.Id }">{!a.Name}</a>
                </li>
            </aura:iteration>
        </ul>
    </div>

Lightning Controller:

({
    doInit : function (component) {
    var action = component.get('c.getAccount');
    action.setParams({
        "accountId": component.get("v.recordId")
    });
        
	action.setCallback(this, function(response) {
        var state = response.getState();
        if (state == "SUCCESS") {
            var account = response.getReturnValue();
            component.set("v.acc", account);
        }
    });
        
    var action2 = component.get('c.getAttachments');
    action2.setParams({
        "parentId": component.get("v.recordId")
    });
        
	action2.setCallback(this, function(response) {
        var state = response.getState();
        if (state == "SUCCESS") {
            var attachments = response.getReturnValue();
            component.set("v.attachments", attachments);
        }
    });
    $A.enqueueAction(action);
    $A.enqueueAction(action2);
}
})