• Eric Smith 9
  • NEWBIE
  • 15 Points
  • Member since 2015
  • Director of Software Development
  • GWI


  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 3
    Likes Given
  • 5
    Questions
  • 9
    Replies
I have some Apex code that returns data for a LWC datatable component.  If I have a lookup field, I'm able to return the lookup record's Name field value along with the Id.  If it is a Master-Detail field, I get an error: "salesforce relationship object__r is not editable".  

I'm trying to implement a work-around mentioned here:
Generic sobject, field not editable error on master-detail field (https://developer.salesforce.com/forums/?id=906F000000091KxIAI)

When I look at the records in line 190:
System.debug('records: ' + JSON.serializePretty(records));

they do not contain the update I'm trying to add in line 184: 
so = (sobject)json.deserialize(str, sobject.class);

Any ideas on what I'm missing here?

This is the complete Apex Class
/**
 * 
 * Based on a component (ItemsToApprove) created by: Alex Edelstein (Salesforce) 
 * Based on a component (FlatTable) created by: J. Pipkin (OpFocus, Inc)
 * 
 * Description: getColumnData
 *              Get field information from a list of field names in order to build
 *              the column definitions for the datatable
 * 
 *              getRowData
 *              Take a List of Records and a List of Lookup Field Names and
 *              use the recordId values in the lookup fields get the values
 *              of the Name fields in the corresponding records. Return the
 *              records that now include both the Id and Name for each lookup.
 * 
 * 04/01/20 -   Eric Smith -    Version 1.0
 * 04/14/20 -   Eric Smith -    Version 1.1     Cleaned up some error handling
 * 04/28/20 -   Eric Smith -    Version 1.2     Handle lookup Objects without a Name field & handle Master/Detail
 * 
 **/

public with sharing class SObjectController {

    //this is just a convenient way to return multiple unique pieces of data to the component
    public class ReturnResults {
        List<SObject> rowData;
        String dtableColumnFieldDescriptorString;
        List<String> lookupFieldList;
        List<String> percentFieldList;
        List<String> noEditFieldList;
        list<String> timeFieldList;
        String objectName;
    }

    @AuraEnabled
    public static string getReturnResults(List<SObject> records, String fieldNames){
        ReturnResults curRR = new ReturnResults();
        if (records.isEmpty()) {
            // throw new MyApexException ('The datatable record collection is empty');
            List<String> emptyList = new List<String>();
            curRR.dtableColumnFieldDescriptorString = '{"label":"Empty Table", "fieldName":"Id", "type":"text"}';
            curRR.lookupFieldList = emptyList;
            curRR.percentFieldList = emptyList;
            curRR.noEditFieldList = emptyList;
            curRR.timeFieldList = emptyList;
            curRR.rowData = records;
            curRR.objectName = 'EmptyCollection';
        } else {           
            String objName = records[0].getSObjectType().getDescribe().getName();
            curRR = getColumnData(curRR, fieldNames, objName);
            curRR.rowData = getRowData(records, curRR.lookupFieldList, curRR.percentFieldList);
            curRR.objectName = objName;
        }
        return JSON.serialize(curRR);  
    }

    @AuraEnabled
    public static ReturnResults getColumnData(ReturnResults curRR, String fields, String objectName) {
        
        SObjectType sobjType = ((SObject)(Type.forName('Schema.'+objectName).newInstance())).getSObjectType();
        DescribeSObjectResult objDescribe = sobjType.getDescribe();

        String datatableColumnFieldDescriptor = '';
        String fieldType = '';
        List<Schema.DescribeFieldResult> curFieldDescribes = new List<Schema.DescribeFieldResult>();
        List<String> lookupFields = new List<String>();
        List<String> percentFields = new List<String>();
        List<String> noEditFields = new List<String>();
        List<String> timeFields = new List<String>();

        for (String fieldName : fields.split(',')) {

            Map<String, Schema.SObjectField> fieldMap = objDescribe.fields.getMap();
            Schema.SObjectField fieldItem = fieldMap.get(fieldName);
            if (fieldItem == null) 
                throw new MyApexException('could not find the field: ' + fieldName + ' on the object ' + objectName);
            Schema.DescribeFieldResult dfr = fieldItem.getDescribe();
            curFieldDescribes.add(dfr);
            datatableColumnFieldDescriptor = datatableColumnFieldDescriptor 
                + ',{"label" : "' + dfr.getLabel() 
                + '", "fieldName" : "' + fieldName 
                + '", "type" : "' + convertType(dfr.getType().name()) 
                + '", "scale" : "' + dfr.getScale() 
                + '"}';

            switch on dfr.getType().name() {
                when 'REFERENCE' {
                    lookupFields.add(fieldName);
                }
                when 'PERCENT' {
                    percentFields.add(fieldName);
                }
                when 'TEXTAREA' {
                    if (!dfr.isSortable()) noEditFields.add(fieldName); // Long Text Area and Rich Text Area                   
                }
                when 'ENCRYPTEDSTRING', 'PICKLIST', 'MULTIPICKLIST' {
                    noEditFields.add(fieldName);
                }
                when 'CURRENCY', 'DECIMAL', 'DOUBLE', 'INTEGER', 'LONG' {
                    // *** create scale attrib in datatableColumnFieldDescriptor and pass the getScale() values in that way. ***
                }
                when 'TIME' {
                    timeFields.add(fieldName);
                }
                when else {
                }
            }   
        }

        System.debug('final fieldDescribe string is: ' + datatableColumnFieldDescriptor);
        curRR.dtableColumnFieldDescriptorString = datatableColumnFieldDescriptor.substring(1);   // Remove leading ,
        curRR.lookupFieldList = lookupFields;
        curRR.percentFieldList = percentFields;
        curRR.noEditFieldList = noEditFields;
        curRR.timeFieldList = timeFields;
        return curRR;
    }

    @AuraEnabled
    public static List<SObject> getRowData(List<SObject> records, List<String> lookupFields, List<String> percentFields) {
        // Update object to include values for the Name field referenced by Lookup fields
        String objName = records[0].getSObjectType().getDescribe().getName();
        Map<String, Set<Id>> objIdMap = new Map<String, Set<Id>>();
        List<String> fields = lookupFields;

        // Get names of the related objects
        for(SObject so : records) {
            for(String lf : fields) {
                if(so.get(lf) != null) {
                    Id lrid = ((Id) so.get(lf));
                    String relObjName = lrid.getSobjectType().getDescribe().getName();
                    if(!objIdMap.containsKey(relObjName)) {
                        objIdMap.put(relObjName, new Set<Id>());
                    }
                    objIdMap.get(relObjName).add(lrid);
                }
            }
        }

        // Lookup the Name field in the related object 
        Map<String, Map<Id, SObject>> dataMap = new Map<String, Map<Id, SObject>>();
        for(String obj : objIdMap.keySet()) {
            Set<Id> ids = objIdMap.get(obj);
            String nameField = getNameUniqueField(obj);
            SObject[] recs = Database.query('Select Id, ' + nameField + ' from ' + obj + ' where Id in :ids');        
            System.Debug('Name Field: '+obj+' - '+nameField);
            Map<Id, SObject> somap = new Map<Id, SObject>();
            for(SObject so : recs) {
                somap.put((Id) so.get('Id'), so);
            }
            dataMap.put(obj, somap);
        }

        // Add new field values to the records
        for(SObject so : records) {   
            
            // Divide percent field values by 100
            for(String pf : percentFields) {
                if(so.get(pf) != null) {
                    so.put(pf, double.valueOf(so.get(pf))/100);
                }
            }
            // Add new lookup field values 
            for(String lf : fields) {         
                if(so.get(lf) != null) {
                    Id lrid = ((Id) so.get(lf));
                    String relObjName = lrid.getSobjectType().getDescribe().getName();
                    Map<Id, SObject> recs = dataMap.get(relObjName);
                    if (recs == null) continue;
                    SObject cso = recs.get(lrid);
                    if (cso == null) continue;
                    String relName;
                    if (lf.toLowerCase().endsWith('id')) {
                        relName = lf.replaceAll('(?i)id$', '');
                    } else {
                        relName = lf.replaceAll('(?i)__c$', '__r');
                    }
                    try {
                        so.putSObject(relName, cso);
                    } catch(exception e) {
                        // Workaround for "Field is not editable" error (Master/Detail)
                        String str = json.serialize(so);
                        str = str.replaceFirst('\\}','}, "'+relName+'":'+json.serialize(cso));
                        so = (sobject)json.deserialize(str, sobject.class);
                    }
                }
            }
        }

        System.debug('records: ' + JSON.serializePretty(records));
        return records;
    }

    public class MyApexException extends Exception {
    }

    //convert the apex type to the corresponding javascript type that datatable will understand
    private static String convertType (String apexType){
        switch on apexType {
            when 'BOOLEAN' {
                return 'boolean';
            }
            when 'CURRENCY' {
                return 'currency';
            }
            when 'DATE' {
                return 'date';
            }
            when 'DATETIME' {
                return 'datetime';   // Custom type for this component
            }
            when 'DECIMAL', 'DOUBLE', 'INTEGER', 'LONG' {
                return 'number';
            }
            when 'EMAIL' {
                return 'email';
            }
            when 'ID' {
                return 'id';
            }
            when 'LOCATION' {
                return 'location';
            }
            when 'PERCENT' {
                return 'percent';
            }
            when 'PHONE' {
                return 'phone';
            }
            when 'REFERENCE' {
                return 'lookup';    // Custom type for this component
            }
            when 'TIME' {
                return 'time';      // Custom type for this component
            }
            when 'URL' {
                return 'url';
            }
            when else {
                // throw new MyApexException ('you\'ve specified the unsupported field type: ' + apexType );
                return 'text';
            }
        }
    }
    
    //Get the 'Name' field for the given SObjectType
    private static String getNameUniqueField(String objectName) {
        String strResult = null;
        SObjectType sobjType = ((SObject)(Type.forName('Schema.'+objectName).newInstance())).getSObjectType();
        DescribeSObjectResult objDescribe = sobjType.getDescribe();
        Map<String, Schema.SObjectField> fieldMap = objDescribe.fields.getMap();
        for(String fieldName : fieldMap.keySet()) {
            SObjectField objField = fieldMap.get(fieldName);
            Schema.DescribeFieldResult dfr = objField.getDescribe();
            if(dfr.isNameField()) {
                strResult = dfr.getName();
                break;
            }
            if(strResult != null) {
                return strResult;
            }
        }
        for(String fieldName : fieldMap.keySet()) {
            SObjectField objField = fieldMap.get(fieldName);
            Schema.DescribeFieldResult dfr = objField.getDescribe();
            if(dfr.isAutoNumber()) {
                strResult = dfr.getName();
                break;
            }
            if(strResult != null) {
                return strResult;
            }        
        }
        for(String fieldName : fieldMap.keySet()) {
            SObjectField objField = fieldMap.get(fieldName);
            Schema.DescribeFieldResult dfr = objField.getDescribe();
            if(dfr.isUnique()) {
                strResult = dfr.getName();
                break;
            }
        }
        return strResult;
    }

}

 
I've found a couple of errors in the online documentation for the LWC datatable component.  Where should I go to report these?
Twice I have received emails for CodeLive events where the Add to Calendar link for the Google Calendar is off by 1 hour.  The iCal link is correct and I'm not able to test the Outlook link.

The most recent one is for the "CodeLive with Brian Kwong -Converting App Pages from Visualforce to Lightning" event.

Dear Eric,
This is a reminder that "CodeLive with Brian Kwong -Converting App Pages from Visualforce to Lightning" will begin in 1 Hour on:
Tue, Oct 15, 2019 5:00 PM - 6:00 PM GMT
Add to Calendar: Outlook® Calendar (http://global.gotowebinar.com/icsCalendar.tmpl?webinar=4331538553563950860&user=691493468&cal=outlook) | Google Calendar™ (https://global.gotowebinar.com/icsCalendar.tmpl?webinar=4331538553563950860&user=691493468&cal=google) | iCal® (https://global.gotowebinar.com/icsCalendar.tmpl?webinar=4331538553563950860&user=691493468&cal=ical)
Please send your questions, comments and feedback to: developer@salesforce.com
How to Join the Webinar
I'm looking to update a custom page template with a third (pinned) column and I'm not sure how to do it.  Is the source code available for the standard templates provided by Salesforce?  It would be nice to see how each of them was created.

Here is my template for a page with a pinned section for 2 full-width headers and 2 columns with the right column being collapsible.  I would like to add a pinned left column to this template.

COMPONENT
<aura:component implements="lightning:recordHomeTemplate" description="Full-width header above a main column and collapsible right sidebar.">
    
    <aura:attribute name="headerP" type="Aura.Component[]" description="Pinned header region"/>
    <aura:attribute name="subHeaderP" type="Aura.Component[]" description="Pinned header region 2nd component"/>
    <aura:attribute name="headerS" type="Aura.Component[]" description="Scrolling header region"/>    
    <aura:attribute name="main" type="Aura.Component[]" description="Main region"/>
    <aura:attribute name="sidebar" type="Aura.Component[]" description="Collapsible sidebar region"/>
    
    <aura:attribute name="isSidebarCollapsed" type="Boolean" access="PRIVATE" default="false" />
    
    <aura:handler event="aura:doneRendering" action="{!c.doneRendering}"/>
    
    <div>
        <div id="stickySection" class="p-header">
            <lightning:layout multipleRows="true" aura:id="stickySection" class="slds-p-around_none">
                <lightning:layoutItem flexibility="auto" class="slds-size_12-of-12 slds-p-around_none">
                    {!v.headerP}
                    {!v.subHeaderP}
                </lightning:layoutItem>
            </lightning:layout>
        </div>
        <div class="slds-p-top_small">
            {!v.headerS}
        </div>
        <lightning:layout class="slds-m-top_medium">
            <lightning:layoutItem flexibility="auto">
                {!v.main}
            </lightning:layoutItem>
            <lightning:layoutItem flexibility="no-flex">
                <lightning:buttonIcon onclick ="{!c.toggleSection}"
                                      class="design-allow-interaction toggle slds-p-around_xxx-small slds-m-horizontal_xx-small"
                                      variant="border-filled"
                                      iconName="{! v.isSidebarCollapsed ? 'utility:chevronleft' : 'utility:chevronright' }" 
                                      alternativeText="{! v.isSidebarCollapsed ? 'Expand Sidebar' : 'Collapse Sidebar' }" />
            </lightning:layoutItem>
            <lightning:layoutItem class="{! v.isSidebarCollapsed ? ' slds-hide' : '' }" size="4">
                {!v.sidebar}
            </lightning:layoutItem>
        </lightning:layout>
    </div>
</aura:component>
CONTROLLER
({
    toggleSection : function(component, event, helper) {
        component.set('v.isSidebarCollapsed', !component.get('v.isSidebarCollapsed'));
    },
    
    doneRendering : function(component, event, helper) {
        try {
            var stickySectionAura = component.find("stickySection");
            if(window && stickySectionAura){
                window.onscroll = function() {
                    //Purely informational
                    var html = document.documentElement;
                    var scrollHeight = parseInt(html.scrollHeight);
                    var clientHeight = parseInt(html.clientHeight);
                    
                    //This is where it happens, so adjust this per your requirement
                    if(parseInt(window.pageYOffset) > 75) 
                        $A.util.addClass(stickySectionAura, 'stickySection');
                    else
                        $A.util.removeClass(stickySectionAura, 'stickySection');
                }
            }
        } catch(err){
            console.log('-------> doneRendering ERROR: ' + err + ' ** MESSAGE: ' + err.message + ' ** STACK: ' + err.stack);
        }
    }
})
STYLE
.THIS .stickySection {
    position: fixed;
    z-index: 999;
    width: 100%;
    margin: -20px 1px 0 -24px !important;
}

.THIS .p-header {
    margin: 0px 0px 0px 0px;
}
DESIGN
<design:component label="Header and Collapsible Right Sidebar">
    <flexipage:template>
        <flexipage:region name="headerP" defaultWidth="LARGE" />
        <flexipage:region name="subHeaderP" defaultWidth="LARGE" />
        <flexipage:region name="headerS" defaultWidth="LARGE" />
        <flexipage:region name="main" defaultWidth="MEDIUM" />
        <flexipage:region name="sidebar" defaultWidth="SMALL" />
    </flexipage:template>
</design:component>




 
I have a simple component using Lightning Data Service to set the value of a field.  I would like to pass the name of the field to update in as a parameter instead of hardcoding it.  What changes should I make to my component to do this?
<aura:component implements="flexipage:availableForAllPageTypes,force:lightningQuickActionWithoutHeader,force:hasRecordId" access="global" >

    <aura:attribute name="record" type="Object" />
    <aura:attribute name="simpleRecord" type="Object" />
    <aura:attribute name="recordError" type="String" />
    <force:recordData aura:id="recordEditor"
                      layoutType="FULL"
                      recordId="{!v.recordId}"
                      targetError="{!v.recordError}"
                      targetRecord="{!v.record}"
                      targetFields="{!v.simpleRecord}"
                      mode="EDIT" />
    
    <!-- Display LDS 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>

    <!--    Custom Interface Goes Here -->
    <lightning:button class="slds-button_neutral" label="New OSP Project" onclick="{!c.handleSaveRecord}" />

</aura:component>
({
	handleSaveRecord : function(component, event, helper) {

         //     Field Updates go Here
		component.set("v.simpleRecord.Trigger_OSP__c", true);    // THIS IS WHERE I WANT TO UPDATE A FIELD BASED ON A FIELD NAME PASSED IN AS A PARAMATER TO THE COMPONENT //
        
         //Standard way to save a record template using Lightning Data Service
        component.find("recordEditor").saveRecord($A.getCallback(function(saveResult){
            if(saveResult.state === "SUCCESS" || saveResult.state === "DRAFT"){
                console.log("Save completed successfully.");
                $A.get("e.force:closeQuickAction").fire();
            }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));
            }
        }));
	},
    
    cancel : function(component, event, helper){
        $A.get("e.force:closeQuickAction").fire();
    }
})


 
I want to use a existing look up field in a visual flow screen, but as it is not directly available I created a lightning component.
The lightning component workd fine when I embed it into a lightning app, but when I try using it in the flow as a lightning component it prompts with the following error

This page has an error. You might just need to refresh it. Error in $A.getCallback() [An internal server error has occurred Error ID: 1616352317-51606 (-582529140)] Callback failed: aura://ComponentController/ACTION$getComponent Failing descriptor: {flowruntime:flowRuntime}

My component code is as below

<aura:component implements="lightning:availableForFlowScreens" access="global">
    <aura:attribute name="objInfo" type="Contact" 
               default="{ 'sobjectType': 'Contact' }" access = "public"/>
    <force:inputField aura:id="accountid" 
                 value="{!v.objInfo.AccountId}"/>
</aura:component>

Can anyone advice how can we resolve it ?

 
I want to make my own Custom Page Layout Template for my Account page.
The layout is already how I want it, it' s nothing special.
But now I want the top component / Header to be pinned just like the standard one with a Pinned header and 3 Columns.

Here is the code that I used to make the Custom Page Layout.
 
----Accounts.cmp----

<aura:component implements="lightning:recordHomeTemplate" description="One header with 2 column's. The left one is 4 and right is 8">
    
    <aura:attribute name="header" type="Aura.Component[]"/>
    <aura:attribute name="left" type="Aura.Component[]"/>
    <aura:attribute name="right" type="Aura.Component[]"/>

    <div>
            <Lightning:Layout >
                <Lightning:layoutItem size="12" padding="around-small">
                    {!v.header}
                </Lightning:layoutItem>
            </Lightning:Layout>
                        
            <Lightning:Layout >
                <Lightning:layoutItem size="4" padding="horizontal-small">
                    {!v.left}
                </Lightning:layoutItem>
                
                <Lightning:layoutItem size="8" padding="horizontal-small">
                    {!v.right}
                </Lightning:layoutItem>
            </Lightning:Layout>      
    </div>
</aura:component>
----Accounts.cmp----
 
----Accounts.Design----

<design:component >
    <flexipage:template >
        <flexipage:region name="header" defaultWidth="Medium"> 
        </flexipage:region>
        
        <flexipage:region name="left" defaultWidth="Medium"> 
        </flexipage:region>
        
        <flexipage:region name="right" defaultWidth="Medium"> 
        </flexipage:region>        

    </flexipage:template>
</design:component>
----Accounts.Design----

 
Salesforce classic had dedicated URL to "Choose Priceook" but not in  Lightning. We have custom VF page to add products and wondering what is best way to route users to select pricebook if one does not exist in Lightning.

Flow
- Click custom "Add Products" button
- Check if Pricebook is attached to opportunity
- Redirect to "Choose Pricebook"
- User selects the pricebook and then redirect back to custom VF page

Above flow is working in classic and need to make it workin in Lighrning. 
I'd like to re-open the discussion of SortOrder on the OpportunityLineItem object. A thread from 3.5 years ago can be located here:
http://community.salesforce.com/sforce/board/message?board.id=general_development&message.id=3154

Looks like people from SF were going to look into it but obviously nothing has come to fruition. The reason I have put this in the Visualforce board is that we have have a few VF applications that could really take advantage of access to this field. Visualforce has also opened up new possibilities to UI design where the ability to manage SortOrder could be useful.

Also, no offense to salesforce.com, but the tool for sorting OpportunityLineItems is not that useful when there are multiple products with the same name. I have actually built a pretty slick sorting application but this is currently useless.

A lot of the concerns were about error handling. What happens if you have 3 line items but sort order is defined as, 1, 2, 2. Or 1, 2, 4. How about just throwing a sortOrder exception and force the developers to write good code?

Ideas? Thoughts?
http://ideas.salesforce.com/article/show/10092062/OpportunityLineItem_SortOrder_to_be_CreatableUpdatable

-Jason


Message Edited by TehNrd on 09-05-2008 01:22 PM
  • September 03, 2008
  • Like
  • 1
Hi all,
I have been struggling this for a while. I have a simple component using Lightning Data Service which basically lists out accounts with Similar ratings on the Current Account page. It loads fine but when I edit the Account Rating on the same page, it doesnt update/refresh the Lightning Component. I tried using force:refresh event. It didnt work. I am not sure how can I use Custom events for this since the Save is standard. May be I am not handling the recordUpdated correctly.
here is my code:

SimilarRatingsController.js
({
	doInit : function(component, event, helper) {
        var eventParams = event.getParams();
        if(eventParams.changeType === "LOADED"){
            console.log('Record loaded');
        //get a list of accounts
        var action = component.get("c.getSimilarRatings");
        action.setParams({
            accrating: component.get("v.account.fields.Rating.value")
            
        });
        action.setCallback(this, function(response){
            var state = response.getState();
            if(component.isValid() && state === "SUCCESS"){
                var similarRatings = response.getReturnValue();
                console.log("Accounts "+similarRatings);
                var lenAccts = similarRatings.length;
                for(var i=0; i<lenAccts; i++){
                    console.log(similarRatings[i].Rating);
                }
            	component.set("v.similarRatings", similarRatings);
            }else{
                console.log("Failed with state :"+state);
				console.log("Component is :"+component);
            }
            
            
        });
        $A.enqueueAction(action);
        }else if(eventParams.changeType === "CHANGED"){
            console.log('Record updated');
            
        }
	}
})

SimilarRatings.cmp
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId,force:lightningQuickActionWithoutHeader" access="global" controller="NearByAccount">
    <aura:attribute name="recordId" type="Id"/>
    <aura:attribute name="account" type="Account"/>
    <aura:attribute name="similarRatings" type="Object[]"/>


    
    <!--<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>-->
    <!--<aura:handler event="c:recordUpdated" action="{!c.doInit}"/>-->
    <force:recordData recordId="{!v.recordId}"
                      targetRecord="{!v.account}"
                      targetFields="{!v.simpleAccount}"
                      fields="Id, Name, Rating"
                      
                      recordUpdated="{!c.doInit}"/>
    <lightning:card iconName="standard:account" title="Similar Accounts" class="slds-is-relative">
        <div class="slds-p-left_medium slds-p-right_medium">
            <ul>
            <aura:if isTrue="{!v.nearbyAccounts.length &gt; 0}">
     			<aura:iteration items="{!v.similarRatings}" var="acc">
         			<li class="slds-list__item">
             			<c:NearByAccount account="{!acc}"/>
         			</li>
    	
    			</aura:iteration>
                <aura:set attribute="else">
                	<li class="slds-list__item">
                        <h3 class="slds-text-small slds-text-color_error">No nearby Accounts found.</h3>
                    </li>
                </aura:set>
            </aura:if>
            </ul>
        </div>
    </lightning:card>
</aura:component>
SimilarAccount.cmp
<aura:component >
    <aura:attribute name="account" type="Account"/>
    <!--<aura:registerEvent name="recordUpdated" type="c:recordUpdated"/>-->
    <lightning:recordViewForm aura:id="viewForm" recordId="{!v.account.Id}" objectApiName="Account">
        <div class="slds-tile__detail">
        <div class="slds-grid slds-grid_align-spread slds-has-flexi-truncate">
        	<a onclick="{!c.navToRecord}" >
            	<h3  class="slds-tile__title slds-truncate" title="Salesforce UX">
                
                    {!v.account.Name} 
                   
               
            	</h3>
            </a>
        </div>
    
    </div>
    </lightning:recordViewForm>
    
	
</aura:component>

SimilarAccount.js
({
	 navToRecord : function (component, event, helper) {
        var navEvt = $A.get("e.force:navigateToSObject");
        navEvt.setParams({
            "recordId": component.get("v.account.Id")
        });
        navEvt.fire();
	},
})
SimilarAccount
public with sharing class SimilarAccount {
   
    
    @AuraEnabled
    public static List<Account> getSimilarRatings(String accrating){
        System.debug('Rating '+accrating);
        List<Account> accList = [SELECT Id, Name, Rating FROM Account
                                WHERE Rating = :accrating];
        System.debug('Account '+accList);
        return accList;
    }

}





 
I see that there is a Console page template for Console: Pinned Header and Left Sidebar, but not one for Console: Pinned Header and Right Sidebar.  I was attempting to create my own component, but after much searching and reviewing of documentation, I haven't found anything on pinning columns/headers in a custom template component.   

Has anyone had any luck with this, or is there an example available anywhere that may have some documentation on how they accomplished this with their default console templates?  Thanks.
  • July 11, 2018
  • Like
  • 1
I want to make my own Custom Page Layout Template for my Account page.
The layout is already how I want it, it' s nothing special.
But now I want the top component / Header to be pinned just like the standard one with a Pinned header and 3 Columns.

Here is the code that I used to make the Custom Page Layout.
 
----Accounts.cmp----

<aura:component implements="lightning:recordHomeTemplate" description="One header with 2 column's. The left one is 4 and right is 8">
    
    <aura:attribute name="header" type="Aura.Component[]"/>
    <aura:attribute name="left" type="Aura.Component[]"/>
    <aura:attribute name="right" type="Aura.Component[]"/>

    <div>
            <Lightning:Layout >
                <Lightning:layoutItem size="12" padding="around-small">
                    {!v.header}
                </Lightning:layoutItem>
            </Lightning:Layout>
                        
            <Lightning:Layout >
                <Lightning:layoutItem size="4" padding="horizontal-small">
                    {!v.left}
                </Lightning:layoutItem>
                
                <Lightning:layoutItem size="8" padding="horizontal-small">
                    {!v.right}
                </Lightning:layoutItem>
            </Lightning:Layout>      
    </div>
</aura:component>
----Accounts.cmp----
 
----Accounts.Design----

<design:component >
    <flexipage:template >
        <flexipage:region name="header" defaultWidth="Medium"> 
        </flexipage:region>
        
        <flexipage:region name="left" defaultWidth="Medium"> 
        </flexipage:region>
        
        <flexipage:region name="right" defaultWidth="Medium"> 
        </flexipage:region>        

    </flexipage:template>
</design:component>
----Accounts.Design----