Month: February 2018

Using Lightning Data Service in Action Overrides

Introduction:-

In this blog post, I am going to explain how to use the Lightning data services in Lightning component standard action overrides.  Use Lightning Data Service to load, create, edit, or delete a record in your component without requiring Apex code. Lightning Data Service handles sharing rules and field-level security for you.  Lightning Data Service as the Lightning Components version of the Visualforce standard controller. To override the standard action with lightning component, the component must implements lightning:actionOverride interface.
<aura:component implements="force:appHostable,force:hasRecordId,lightning:actionOverride" access="global" >
    <aura:attribute name="newWorkOrder" type="Object"/>
    <aura:attribute name="newWorkOrderRecord" type="Object"/>
    <aura:attribute name="newWorkOrderError" type="String"/>
    
    <force:recordData aura:id="newWorkOrderRecordId"
                      layoutType="FULL"
                      mode="EDIT"
                      targetRecord="{!v.newWorkOrder}"
                      targetFields="{!v.newWorkOrderRecord}"
                      targetError="{!v.newWorkOrderError}"
                      />
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <div class="New WorkOrder Details ">
        <lightning:card iconName="action:custom84_120" title="Create New WorkOrder">
            <div class="slds-p-horizontal--large">
               
               
                <lightning:input aura:id="workOrderIds" label="Status" value="{!v.newWorkOrderRecord.Status}"/>
                <lightning:input aura:id="workOrderIds"  label="Priority" value="{!v.newWorkOrderRecord.Priority}"/>
                <lightning:input aura:id="workOrderIds" label="Subject" value="{!v.newWorkOrderRecord.Subject}"/>
                <lightning:input aura:id="workOrderIds" label="Description" value="{!v.newWorkOrderRecord.Description}"/>
                <br/>
                <lightning:button label="Save" variant="brand" onclick="{!c.handleSave}"/>
                
            </div>
        </lightning:card>
    </div>
    
    <aura:if isTrue="{!not(empty(v.newWorkOrderError))}">
        <div class="recordError">
            {!v.newWorkOrderError}</div>
    </aura:if>
    
    
</aura:component>
({
    doInit: function(component, event, helper) {
        // Prepare a new record from template
        component.find("newWorkOrderRecordId").getNewRecord(
            "WorkOrder", // sObject type (entityAPIName)
            null,      // recordTypeId
            false,     // skip cache?
            $A.getCallback(function() {
                var record = component.get("v.newWorkOrder");
                var error = component.get("v.newWorkOrderError");
                if(error || (record === null)) {
                    console.log("Error initializing record template: " + error);
                }
                else {
                    console.log("Record template initialized: " + record);
                }
            })
        );
    },
    
    handleSave: function(component, event, helper) {
        component.find("newWorkOrderRecordId").saveRecord(function(saveResult) {
            if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {
                // record is saved successfully
                var resultsToast = $A.get("e.force:showToast");
                resultsToast.setParams({
                    "title": "Saved",
                    "message": "The record was saved."
                });
                resultsToast.fire();
                $A.get("e.force:refreshView").fire();   
                
                
            } else if (saveResult.state === "INCOMPLETE") {
                // handle the incomplete state
                console.log("User is offline, device doesn't support drafts.");
            } else if (saveResult.state === "ERROR") {
                // handle the error state
                console.log('Problem saving contact, error: ' + 
                            JSON.stringify(saveResult.error));
            } else {
                console.log('Unknown problem, state: ' + saveResult.state +
                            ', error: ' + JSON.stringify(saveResult.error));
            }
        });
        
    }
})

Override Edit Action 

To override the edit action you need to implement lightning: actionOverride interface and update the record using Lightning Data Service by calling saveRecord on the force:recordData component, and pass in a callback function to be invoked after the save operation completes.

<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId,lightning:actionOverride">
    
    <aura:attribute name="workorderrecord" type="Object"/>
    <aura:attribute name="workordeksimpleRecord" type="Object"/>
    <aura:attribute name="recordError" type="String"/>
    
    <force:recordData aura:id="recordHandler"
                      recordId="{!v.recordId}"
                      layoutType="FULL"
                      targetRecord="{!v.workorderrecord}"
                      targetFields="{!v.workordeksimpleRecord}"
                      targetError="{!v.recordError}"
                      mode="EDIT"
                      recordUpdated="{!c.handleRecordUpdated}"
                      />
    
    <!-- Display a header with details about the record -->
    <div class="slds-page-header" role="banner">
        <p class="slds-text-heading_label">Edit Record</p>
        <h1 class="slds-page-header__title slds-m-right_small
                   slds-truncate slds-align-left">{!v.workordeksimpleRecord.Name}</h1>
    </div>
    
    <!-- Display Lightning Data Service errors, if any -->
    <aura:if isTrue="{!not(empty(v.recordError))}">
        <div class="recordError">
            <ui:message title="Error" severity="error" closable="true">
                {!v.recordError}
            </ui:message>
        </div>
    </aura:if>
    
    <!-- Display an editing form -->
    <lightning:input aura:id="recordName"  label="Status"
                     value="{!v.workordeksimpleRecord.Status}" />
    <lightning:input aura:id="recordName"  label="Description"
                     value="{!v.workordeksimpleRecord.Description}" />
    
    <lightning:input aura:id="recordName"  label="Subject"
                     value="{!v.workordeksimpleRecord.Subject}" />
    
    
    <lightning:button label="Save Record" onclick="{!c.handleSaveRecord}"
                      variant="brand" class="slds-m-top_medium"/>
</aura:component>

 

({
    handleSaveRecord: function(component, event, helper) {
        component.find("recordHandler").saveRecord($A.getCallback(function(saveResult) {
            // NOTE: If you want a specific behavior(an action or UI behavior) when this action is successful 
            // then handle that in a callback (generic logic when record is changed should be handled in recordUpdated event handler)
            if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {
                // handle component related logic in event handler
            } 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));
            }
        }));
    },
    
    /**
     * Control the component behavior here when record is changed (via any component)
     */
    handleRecordUpdated: function(component, event, helper) {
        var eventParams = event.getParams();
        if(eventParams.changeType === "CHANGED") {
            // get the fields that changed for this record
            var changedFields = eventParams.changedFields;
            console.log('Fields that are changed: ' + JSON.stringify(changedFields));
            // record is changed, so refresh the component (or other component logic)
            var resultsToast = $A.get("e.force:showToast");
            resultsToast.setParams({
                "title": "Saved",
                "message": "The record was updated."
            });
            resultsToast.fire();
            
        } else if(eventParams.changeType === "LOADED") {
            // record is loaded in the cache
        } else if(eventParams.changeType === "REMOVED") {
            // record is deleted and removed from the cache
        } else if(eventParams.changeType === "ERROR") {
            // there’s an error while loading, saving or deleting the record
        }
    }
})

Override View Action

To override the edit action you need to implement lightning: actionOverride interface and Loading a data by using the Lightning Data Service.  To load a record using Lightning Data Service, add the force:recordData tag to your component. In the force:recordDatatag, specify the ID of the record to be loaded, a list of fields, and the attribute to which to assign the loaded record. 
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId,lightning:actionOverride">
    
    <aura:attribute name="workOrderRec" type="Object"/>
    <aura:attribute name="simpleworkOrderRec" type="Object"/>
    <aura:attribute name="workOrderError" type="String"/>
    
    <force:recordData aura:id="recordLoader"
                      recordId="{!v.recordId}"
                      layoutType="FULL"
                      targetRecord="{!v.workOrderRec}"
                      targetFields="{!v.simpleworkOrderRec}"
                      targetError="{!v.workOrderError}"
                      recordUpdated="{!c.handleRecordUpdated}"
                      />
    
    <!-- Display a header with details about the record -->
    <div class="slds-page-header" role="banner">
        <h1 class="slds-page-header__title slds-m-right_small
                   slds-truncate slds-align-left">Work Order Details </h1>
        <p class="slds-text-heading_label">{!v.simpleworkOrderRec.WorkOrderNumber}</p>
    </div>
    
    <!-- Display Lightning Data Service errors, if any -->
    <aura:if isTrue="{!not(empty(v.workOrderError))}">
        <div class="recordError">
            <ui:message title="Error" severity="error" closable="true">
                {!v.workOrderError}
            </ui:message>
        </div>
    </aura:if>
    
    <lightning:recordViewForm recordId="{!v.recordId}" objectApiName="WorkOrder">
        
        <div class="slds-box slds-theme_default">
            
            <lightning:outputField fieldName="Case"/>
            <lightning:outputField fieldName="Description" />
            <lightning:outputField fieldName="Duration" />
            <lightning:outputField fieldName="Priority" />
            <lightning:outputField fieldName="StartDate" />
            <lightning:outputField fieldName="Status" />
            <lightning:outputField fieldName="Subject" />
            
            <lightning:outputField fieldName="TotalPrice" />
            <lightning:outputField fieldName="EndDate" />
        </div>
    </lightning:recordViewForm>
</aura:component>

 

({
    handleRecordUpdated: function(component, event, helper) {
        var eventParams = event.getParams();
        if(eventParams.changeType === "LOADED") {
            // record is loaded (render other component which needs record data value)
            console.log("Record is loaded successfully.");
        } else if(eventParams.changeType === "CHANGED") {
            // record is changed
        } else if(eventParams.changeType === "REMOVED") {
            // record is deleted
        } else if(eventParams.changeType === "ERROR") {
            // there’s an error while loading, saving, or deleting the record
        }
    }
})

 

Lightning Components Actions Override

Introduction:-

In this blog, I am going to show how to override the standard action for the lightning experience by using lightning component. To override the standard action with the lightning component you need to implement lightning:actionOverride interface. You can override the View, New, Edit, and Tab standard actions on most standard and all custom components. Overriding standard actions allows you to customize your org using Lightning components, including completely customizing the way you view, create, and edit records.There are six standard actions available on most standard and all custom objects: Tab, List, View, Edit, New, and Delete.Components you plan to use as action overrides usually need details about the object type they’re working with, and often the ID of the current record. Your component can implement the following interfaces to access those object and record details.Add the force: hasRecordId interface to a Lightning component to enable the component to be assigned the ID of the current record. The current record ID is useful if the component is used on a Lightning record page, as an object-specific custom action or action override in Lightning Experience or the Salesforce app, and so on.Add the force: hasSObjectName interface to a Lightning component to enable the component to be assigned the API name of current record’s sObject type. The sObject name is useful if the component can be used with records of different sObject types, and needs to adapt to the specific type of the current record.

New Action Override

Create a new lightning component with the below code
<aura:component implements="lightning:actionOverride,force:hasRecordId,force:hasSObjectName">
    <lightning:recordEditForm aura:id="recordEditForm" 
                              objectApiName="Opportunity">
        <lightning:messages />
        <lightning:inputField fieldName="Name" />
        <lightning:inputField fieldName="Amount" />
        
        <lightning:inputField fieldName="CloseDate" />
        <lightning:inputField fieldName="Description" />
        <lightning:inputField fieldName="StageName" />
        <lightning:inputField fieldName="Probability" />
        <lightning:inputField fieldName="Type" />
        <lightning:inputField fieldName="LeadSource" />
        
        <lightning:inputField fieldName="CurrentGenerators__c" />
        <lightning:inputField fieldName="TrackingNumber__c" />
        
        
        <lightning:button class="slds-m-top_small" type="submit" label="Create new" />
    </lightning:recordEditForm>
    
</aura:component>

Go to object manager and override the new  button action as shown below 

View Action Override

Crate a new lightning component with below code

<aura:component implements="lightning:actionOverride,force:hasRecordId,force:hasSObjectName">
    
    <lightning:recordViewForm recordId="{!v.recordId}" objectApiName="Opportunity">
        <div class="slds-box">
            <lightning:outputField fieldName="Name" />
            <lightning:outputField fieldName="Amount" />
            <lightning:outputField fieldName="CloseDate" />
            <lightning:outputField fieldName="Description" />
            <lightning:outputField fieldName="ExpectedRevenue" />
            <lightning:outputField fieldName="StageName" />
            <lightning:outputField fieldName="Probability" />
            <lightning:outputField fieldName="Type" />
            <lightning:outputField fieldName="CurrentGenerators__c" />
            <lightning:outputField fieldName="TrackingNumber__c" />
            
        </div>
    </lightning:recordViewForm>
    
</aura:component>

Override the view action as shown below

Override Edit Action

Create a new Lightning component with below code

<aura:component implements="lightning:actionOverride,force:hasRecordId,force:hasSObjectName">
    
    <lightning:recordEditForm recordId="{!v.recordId}" objectApiName="Opportunity">
        <lightning:messages />
        
        <lightning:inputField fieldName="Name" />
        <lightning:inputField fieldName="Amount" />
        <lightning:inputField fieldName="CloseDate" />
        <lightning:inputField fieldName="Description" />
        <lightning:inputField fieldName="ExpectedRevenue" />
        <lightning:inputField fieldName="StageName" />
        <lightning:inputField fieldName="Probability" />
        <lightning:inputField fieldName="Type" />
        
        <lightning:button class="slds-m-top_small" variant="brand" type="submit" name="update" label="Update" />
    </lightning:recordEditForm>
</aura:component>

Override the edit action as shown below

 In this example, i used the lightning:recordEditForm and lightning:recordViewForm components to wrap the form for edit and view modes.

Lightning component forceChatter examples

In this blog I am going to show how to use salesforce forceChatter:** components and how its use them to create your own components show the feed. A forceChatter: feed component represents a feed that’s specified by its type. Use the type attribute to display a specific feed type. The strategy used to find items associated with the subject. Valid values include Bookmarks, Company, DirectMessages, Feeds, Files, Filter, Groups, Home, Moderation, Mute, News, PendingReview, Record, Streams, To, Topics, UserProfile.

For example, set type=” groups” to display the feed from all groups the context user either owns or is a member of.

<aura:component implements="force:appHostable">
    <forceChatter:feed type="groups"/>
</aura:component>

You can also display a feed depending on the type selected. This example provides a drop-down menu that controls the type of feed to display

<aura:component implements="force:appHostable">
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <aura:attribute name="options" type="List" />
    <aura:attribute name="type" type="String" default="News" description="The type of feed" access="GLOBAL"/>
    <aura:attribute name="types" type="String[]"
                    default="Bookmarks,Company,DirectMessages,Feeds,Files,Filter,Groups,Home,Moderation,Mute,News,PendingReview,Record,Streams,To,Topics,UserProfile"
                    description="A list of feed types"/>
    <h1>My Feeds</h1>
    <lightning:select aura:id="typeSelect" onchange="{!c.onChangeType}" label="Type" name="typeSelect">
        <aura:iteration items="{!v.options}" var="item">
            <option text="{!item.label}" value="{!item.value}" selected="{!item.selected}"/>
        </aura:iteration>
    </lightning:select>
    <div aura:id="feedContainer" class="feed-container">
        <forceChatter:feed />
    </div>
</aura:component>
({
    // Handle component initialization
    doInit : function(component, event, helper) {
        var type = component.get("v.type");
        var types = component.get("v.types");
        var opts = new Array();
        
        // Set the feed types on the lightning:select component
        for (var i = 0; i < types.length; i++) {
            opts.push({label: types[i], value: types[i], selected: types[i] === type});
        }
        component.set("v.options", opts);
    },
    
    onChangeType : function(component, event, helper) {
        var typeSelect = component.find("typeSelect");
        var type = typeSelect.get("v.value");
        component.set("v.type", type);
        
        // Dynamically create the feed with the specified type
        $A.createComponent("forceChatter:feed", {"type": type}, function(feed) {
            var feedContainer = component.find("feedContainer");
            feedContainer.set("v.body", feed);
        });
    }
})

Here is the app

<aura:application extends="force:slds">	
    <c:FeedMaster/>
</aura:application>

 

Lightning Accordion Component Example

In this blog, I am going to explain how to use salesforce lightning: accordion component. A  lightning:accordion component groups related content in a single container. Only one accordion section is expanded at a time. When you select a section, it’s expanded or collapsed. Each section can hold one or more Lightning components. In this blog, I am going to show the list of books by its category as an accordion.

Apex Class

public class BookController {
    @AuraEnabled
    public static List<Book_Categories__c> getBooksByAllCategories(){
        List<Book_Categories__c> categeroy = [Select  Name,(Select Name, Author_Name__c, Book_Categories__c,Publisher_Id__c from Books__r) from Book_Categories__c];
        return categeroy;
    } 
    
   
}

Lightning Component

<aura:component controller="BookController">
    <aura:attribute name="bookList" type="Book_Categories__c[]" />
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    
    <lightning:accordion aura:id="accordion">
        <aura:iteration items="{!v.bookList}" var="books">
            <lightning:accordionSection name="A" label="{!books.Name}" >
                <aura:set attribute="body">
                    
                    <table class="slds-table slds-table--bordered slds-table--cell-buffer slds-table--striped slds-max-medium-table--stacked-horizontal"
                           role="grid">
                        <thead>
                            <tr>
                                <th class="slds-is-sortable slds-cell-wrap" scope="col">
                                    Name
                                </th>
                                <th class="slds-is-sortable slds-cell-wrap" scope="col">
                                    Author Name
                                </th>
                                <th class="slds-is-sortable slds-cell-wrap" scope="col">
                                    Publisher Id
                                </th>
                            </tr>
                        </thead>
                        <tbody>
                            <aura:iteration items="{!books.Books__r}" var="book">
                                <tr class="slds-hint-parent">
                                    <td role="gridcell" class="slds-cell-wrap">
                                        <div class="">{!book.Name}</div>
                                    </td>
                                    <td role="gridcell" class="slds-cell-wrap">
                                        <div class="" data-label="Role">{!book.Author_Name__c}</div>
                                    </td>
                                    <td role="gridcell" class="slds-cell-wrap">
                                        <div class="" data-label="Role">{!book.Publisher_Id__c}</div>
                                    </td>
                                    
                                </tr>
                                
                            </aura:iteration>
                        </tbody>
                    </table>
                </aura:set>
            </lightning:accordionSection>
        </aura:iteration>
        
    </lightning:accordion>
    
    
</aura:component>

 

({
    doInit : function(component, event, helper) {
        var action = component.get("c.getBooksByAllCategories");
        action.setCallback(this, function(a) {
            component.set("v.bookList", a.getReturnValue());
        });
        $A.enqueueAction(action);
    }
})

You can see final accordion in the below image.

 

lightning:carousel example

In this blog, I am going to explain how to use lightning: carousel example. Here I am using to display the user chatter profile image to display as the carousel.A lightning: carousel component displays a series of images in a single container. This example creates a basic carousel with three images. Auto-scrolling is enabled by default, and every image stays active for 5 seconds before moving on to the next one.

Apex Class

public class UserProfileController {

    @AuraEnabled 
    public static List<User> getUserProfiles(){
        return [Select Id,Address ,BannerPhotoUrl,CompanyName,Department,Email,FirstName , LastName ,FullPhotoUrl from User];
    }
}

Lightning Component 

<aura:component controller="UserProfileController">
    <aura:attribute name="users" type="List" />
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <lightning:carousel >
        <aura:iteration items="{!v.users}" var="user">
            <lightning:carouselImage
                                     src = "{!user.FullPhotoUrl}" 
                                     header = "{!user.FirstName}" 
                                     description = "{!user.AboutMe}" 
                                     alternativeText = "{!user.LastName}"></lightning:carouselImage>
        </aura:iteration>
        
    </lightning:carousel>
    
</aura:component>

 

({
    doInit : function(component, event, helper) {
        var action = component.get("c.getUserProfiles"); 
        action.setCallback(this, function(response){
            var state = response.getState();
            if (component.isValid() && state === "SUCCESS") {
                var retrunRes = response.getReturnValue();
                component.set("v.users" ,retrunRes );
            }
        });
        $A.enqueueAction(action);
    }
})

Simple App for testing

<aura:application extends="force:slds">
    <c:CarouselExample />
</aura:application>