•  

    Maps in LWC

    Hi All,

    Today we will learn to create a new instance of the Map class and populates it with the passed-in list of sObject records. The keys are populated with the sObject IDs and the values are the sObjects. Once that is done we will display the key value pair using a Lightning DataTable.

    Author:Somnath Sharma

    Use Case:Display list of all records that Logged In User Follows in a Lightning Web Componet Tabs with sorting based on Sobject embedded in it.

    After reading this, you’ll be able to:

    • Web componets as Tabs

    • Render  Map<ID,sObject>(List<sObject> recordList)  in LWC

    • Use of spread operators

    • Use of Lightning ComboBox

    • Solve  Invalid mutation: Cannot set "status" on "[object Object]". "[object Object]" is read-only. at ReadOnlyHandler.set   error in LWC while using wire services.

    • Use of refresh Apex

    • Use lightning-navigation service wire adapters .

    • Use Of Header and Row Actions in Lightning DataTable

    • Reading Data when Lighnting DataTable Is In Iteration.

    /**
    
     * @File Name          : SubscriptionDetailsPerUser.cls
    
     * @Description        : 
    
     * @Author             : Somnath Sharma
    
     * @Group              : 
    
     * @Last Modified By   : Somnath Sharma
    
     * @Last Modified On   : 21/1/2020, 10:07:16 pm
    
     * @Modification Log   : 
    
     * Ver       Date            Author             Modification
    
     * 1.0    21/1/2020   Somnath Sharma     Initial Version
    
    **/
    
    
    public with sharing class SubscriptionDetailsPerUser {
    
      //wrapper class
    
         public class EntitySubscriptionWrapper {
    
        //Name of record[ParentId]
    
        @AuraEnabled public String recName{get;set;}
    
        @AuraEnabled public Id entityId{get;set;}   //EntitySubscription Id
    
        @AuraEnabled public String  recObjectType{get;set;}//ParentId object Name
    
        @AuraEnabled public Date  followedDate{get;set;}
    
        @AuraEnabled public String  parentId {get;set;}//user id of the subscriber
    
        @AuraEnabled public String  createdByName {get;set;}
    
        }
    
      /**
    
      * @description: get List of records per object user is following
    
      * @author: Somnath Sharma | 12/17/2019 
    
      * @param :
    
      * @return //Wrapper 
    
      **/
    
        @AuraEnabled(cacheable=true)
    
        public static Map<String,List<EntitySubscriptionWrapper>> getCallerUserfollowings(){
    
            Map<String,List<EntitySubscriptionWrapper>> objectEntitySubscriptionMap=new Map<String,List<EntitySubscriptionWrapper>>();
    
           List<EntitySubscriptionWrapper> entitySubscriptionWrapperList=new List<EntitySubscriptionWrapper>();
    
               for(EntitySubscription entity:[Select Id,CreatedBy.Name,CreatedDate,ParentId,parent.name,
    
                                              subscriber.name,SubscriberId FROM EntitySubscription 
    
                                              where SubscriberId =: UserInfo.getUserId() ORDER BY CreatedDate DESC])
    
                    {    
    
                      //name of the object to which user is subscribed   
    
                     String sObjName = entity.ParentId.getSObjectType().getDescribe().getLabel(); 
    
                      EntitySubscriptionWrapper obj =new EntitySubscriptionWrapper();
    
                      obj.entityId=entity.Id;
    
                      obj.parentId=entity.ParentId;
    
                      obj.recObjectType=sObjName;
    
                      obj.recName=entity.parent.name;
    
                      obj.createdByName=entity.CreatedBy.Name; 
    
                      obj.followedDate=date.newinstance(entity.CreatedDate.year(), entity.CreatedDate.month(), entity.CreatedDate.day());
    
                        entitySubscriptionWrapperList.add(obj); 
    
                     }
    
                     if(entitySubscriptionWrapperList.size()>0){
    
                      objectEntitySubscriptionMap=SubscriptionDetailsPerUser.formGetFollowingMap(entitySubscriptionWrapperList);
    
                     }
    
                    System.debug('EntityValues'+objectEntitySubscriptionMap.values()); 
    
        return objectEntitySubscriptionMap;
    
      }
    
    /**
    
    * @description form that map of list of records that user is following for a particular object
    
    * @author Somnath Sharma | 12/17/2019 
    
    * @param entitySubscriptionWrapperList 
    
    * @return //map 
    
    **/
    
       public static Map<String,List<EntitySubscriptionWrapper>> formGetFollowingMap(List<EntitySubscriptionWrapper> entitySubscriptionWrapperList){   
    
        Map<String,List<EntitySubscriptionWrapper>> objectEntitySubscriptionMap=new Map<String,List<EntitySubscriptionWrapper>>();
    
          for(EntitySubscriptionWrapper entity:entitySubscriptionWrapperList){
    
    //object name is the key
    
                if(objectEntitySubscriptionMap.ContainsKey(entity.recObjectType))
    
                    {   
    
                      objectEntitySubscriptionMap.get(entity.recObjectType).add(entity);     
    
                    }
    
                    else
    
                    {
    
                      objectEntitySubscriptionMap.put(entity.recObjectType,new List<EntitySubscriptionWrapper>{entity}); 
    
                    }
    
          }
    
           System.debug('EntityObjects'+objectEntitySubscriptionMap.keySet());  
    
        return objectEntitySubscriptionMap;
    
       }
    
    
    /**
    
    * @description 
    
    * @author Somnath Sharma | 12/17/2019 
    
    * @param entityIds 
    
    * @return String//
    
    **/
    
    @AuraEnabled
    
    public static String  unSubscribe(List<Id> entityIds) {
    
            List<EntitySubscription> listEntitySub = new List<EntitySubscription>();
    
            listEntitySub = [SELECT Id FROM EntitySubscription WHERE  Id IN:entityIds];
    
            if(listEntitySub.size() > 0) {
    
                delete listEntitySub;
    
                return 'UnSubscribed';
    
            } else {
    
                return 'You are not subscribed to this';
    
            }
        }
    }
    <!--
    
      @File Name          : subscriptioncontainer.html
    
      @Description        : 
    
      @Author             : Somnath Sharma
    
      @Group              : 
    
      @Last Modified By   : Somnath Sharma
    
      @Last Modified On   : 1/8/2020, 10:58:23 AM
    
      @Modification Log   : 
    
      Ver       Date            Author              Modification
    
      1.0    12/17/2019   Somnath Sharma     Initial Version
    
    -->
    
    <template>
    
      <template if:false={showspinner}>
    
        <article class="slds-card" style="margin-bottom: 5px;">
    
          <div class="slds-page-header">
    
            <div class="slds-page-header__row">
    
              <div class="slds-page-header__col-title">
    
                <div class="slds-media">
    
                  <div class="slds-media__figure">
    
                    <lightning-icon icon-name="action:following" alternative-text="Following"></lightning-icon>
    
                  </div>
    
                  <div class="slds-media__body">
    
                    <div class="slds-page-header__name">
    
                      <div class="slds-page-header__name-switcher">
    
                        <div class="slds-dropdown-trigger slds-dropdown-trigger_click">
    
                          <lightning-combobox name="progress" label="What I Follow" value={value}
    
                            placeholder="Select Progress" options={options} onchange={handleChange}>
    
                          </lightning-combobox>
    
                        </div>
    
                      </div>
    
                    </div>
    
                  </div>
    
                </div>
    
              </div>
    
            </div>
    
          </div>
    
        </article>
    
        <div>
    
          <template for:each={allEntityData} for:item="entityKey" for:index="index">
    
            <div class="" key={entityKey.key}>
    
              <div class="slds-summary-detail__title" style="margin-bottom: 5px;">
    
                <div class="slds-grid header-action">
    
                  <div class="slds-col">
    
                    <span class="slds-badge" style="background: #3dcd58;
    
                            color: white;"> {entityKey.key} </span>
    
                  </div>
    
                  <div class="slds-col">
    
                    <span class="slds-float_right">
    
                      <lightning-button variant="destructive" label="UnSubscribe" title={entityKey.key}
    
                        icon-name="standard:unmatched" onclick={unSubscribeChecked}>
    
                      </lightning-button>
    
                    </span>
    
                  </div>
    
                </div>
    
                <lightning-datatable data={entityKey.value} key-field='Id' columns={_entitycolumns}
    
                  onrowaction={handleRowAction} title={entityKey.key}>
    
                </lightning-datatable>
    
              </div>
    
            </div>
    
          </template>
    
        </div>
    
        <article class="slds-card">
    
          <div class="slds-page-header">
    
            <div class="slds-page-header__row">
    
              <div class="slds-page-header__col-title">
    
              </div>
    
            </div>
    
          </div>
    
        </article>
    
      </template>
    
      <template if:true={showspinner}>
    
        <div class="">
    
          <lightning-spinner alternative-text="Loading" size="large"></lightning-spinner>
    
        </div>
    
      </template>
    
    </template>

     

    /**
    
     * @File Name          : subscriptioncontainer.js
    
     * @Description        : 
    
     * @Author             : Somnath Sharma
    
     * @Group              : 
    
     * @Last Modified By   : Somnath Sharma
    
     * @Last Modified On   : 1/9/2020, 10:46:25 AM
    
     * @Modification Log   : 
    
     * Ver       Date            Author             Modification
    
     * 1.0    12/17/2019   Somnath Sharma     Initial Version
    
     **/
    
    import {
    
      LightningElement,
    
      wire,
    
      track
    
    } from 'lwc';
    
    //import method from the Apex Class
    
    import getCallerUserfollowings from '@salesforce/apex/SubscriptionDetailsPerUser.getCallerUserfollowings';
    
    import unSubscribe from '@salesforce/apex/SubscriptionDetailsPerUser.unSubscribe';
    
    // importing to refresh the apex if any record changes the datas
    
    import {
    
      refreshApex
    
    } from '@salesforce/apex';
    
    import {
    
      ShowToastEvent
    
    } from "lightning/platformShowToastEvent";
    
    import {
    
      NavigationMixin
    
    } from 'lightning/navigation';
    
    
    export default class Subscriptioncontainer extends NavigationMixin(LightningElement) {
    
    
      /** Wired Apex result so it can be refreshed programmatically */
    
      wiredEntityWrapper;
    
      @track value = 'All';
    
      @track showspinner = true;
    
      @track options = [{
    
        label: 'All',
    
        value: 'All'
    
      }];
    
      _dataStore = []; //All data
    
      @track error;
    
      //data source property for datatable
    
      @track allEntityData = [];
    
      defaultValue = 'All'
    
      dropDownValueCurrent = 'All';
    
      @wire(getCallerUserfollowings)
    
      wiredAllEntityData(result) {
    
        this.wiredEntityWrapper = result;
    
        //  window.console.log('entityDataRaw', JSON.stringify(result));
    
        if (result.data) {
    
          //  window.console.log('wireServiceData', JSON.stringify(result.data));
    
          //reset when refreshApex called
    
          if (this.allEntityData.length > 0) {
    
            this.allEntityData.length = 0;
    
            this._dataStore.length = 0;
    
            this.options.length = 0;
    
            this.options.push({
    
              label: 'All',
    
              value: 'All'
    
            });
    
          }
    
          for (let key in result.data) {
    
            if (result.data.hasOwnProperty(key)) {
    
              //populate options
    
              this.options.push({
    
                label: key,
    
                value: key
    
              });
    
              this.options.sort();
    
              this.allEntityData.push({
    
                value: result.data[key].map(entitydata => {
    
                  let dupentitydata = {
    
                    ...entitydata
    
                  };
    
                  dupentitydata.Id = dupentitydata.entityId;
    
                  return dupentitydata;
    
                }),
    
                key: key
    
              }); //Here we are creating the array to show on UI.
    
            }
    
          }
    
          this._dataStore = this.allEntityData;
    
          //  window.console.log('wireServiceDataRefined', JSON.stringify(this._dataStore));
    
          this.showspinner = false;
    
          this.error = undefined;
    
        } else if (result.error) {
    
          this.error = result.error;
    
          this.allEntityData = undefined;
    
        }
    
      }
    
      //on row actions datatable
    
      actions = [{
    
        label: 'View',
    
        name: 'View'
    
      }];
    
      // Declaring the columns in  datatable    
    
      _entitycolumns = [{
    
          fieldApi: 'recName',
    
          sortable: false,
    
          label: 'Name',
    
          fieldName: 'recName',
    
          type: 'String',
    
          title: {
    
            fieldName: 'ParentId'
    
          }
    
        },
    
        {
    
          fieldApi: 'followedDate',
    
          sortable: false,
    
          label: 'Follow Date',
    
          fieldName: 'followedDate',
    
          type: 'Date',
    
          title: {
    
            fieldName: 'Follow Date'
    
          }
    
        },
    
        {
    
          type: 'action',
    
          typeAttributes: {
    
            rowActions: this.actions,
    
            menuAlignment: 'auto'
    
          }
    
        }
    
      ];
    
    
      
    
      handleChange(event) {
    
        //  window.console.log('dropdownValue', event.detail.value);
    
        this.dropDownValueCurrent = event.detail.value;
    
        this.showspinner = true;
    
        this.getDataBasedOnKey(event.detail.value);
    
      }
    
      //get data based on drop down value from data store array
    
      getDataBasedOnKey(dropDownValue) {
    
        let matchFound = this._dataStore.find(item => item.key === dropDownValue);
    
        if (matchFound) {
    
          this.allEntityData = [matchFound];
    
        } else {
    
          this.allEntityData = [...this._dataStore];
    
        }
    
        this.showspinner = false;
    
      }
    
    
      unSubscribeChecked(event) {
    
        let toSortEntities = [];
    
        let targetEntity = event.currentTarget.title;
    
    
        window.console.log(event.detail.selectedRows);
    
        //All use case If
    
        if (this.dropDownValueCurrent === this.defaultValue) {
    
          this.template.querySelectorAll("lightning-datatable").forEach(element => {
    
            //simplification of array to be formed
    
            if (element.selectedRows.length > 0) {
    
              element.selectedRows.forEach(individualElements => {
    
                toSortEntities = [...toSortEntities, individualElements];
    
              });
    
    
            }
    
    
          });
    
        } else {
    
          this.getSelected(event.currentTarget.title);
    
    
        }
    
        window.console.log('rowsSelected' + toSortEntities);
    
        if (toSortEntities.length > 0) {
    
          this.sortBasedOnKey(targetEntity, toSortEntities);
    
        }
    
      }
    
      getSelected(selectedEntity) {
    
        let arrayOfEntityIdsSelected = [];
    
        let el = this.template.querySelector('lightning-datatable');
    
        let selectedRowsDetail = el.getSelectedRows();
    
        window.console.log('selectedRowsDetail' + selectedRowsDetail);
    
        if (selectedRowsDetail.length > 0) {
    
          selectedRowsDetail.forEach(row => {
    
            arrayOfEntityIdsSelected = [...arrayOfEntityIdsSelected, row.Id];
    
          });
    
          this.unSubscribeEntities(arrayOfEntityIdsSelected, selectedEntity);
    
        }
    
      }
    
    
      sortBasedOnKey(selectedEntity, allSelectedRows) {
    
        let finalRowsSorted = [];
    
        let rowsBasedOnButtonClicked = this._dataStore.find(item => item.key === selectedEntity);
    
        allSelectedRows.forEach(rowsChecked => {
    
          rowsBasedOnButtonClicked.value.forEach(elementBasedOnKey => {
    
            if (rowsChecked === elementBasedOnKey.Id) {
    
              finalRowsSorted = [...finalRowsSorted, rowsChecked];
    
            }
    
          });
    
    
        });
    
        window.console.log('finalRowsSorted' + finalRowsSorted);
    
    
        if (finalRowsSorted.length > 0) {
    
          this.unSubscribeEntities(finalRowsSorted, selectedEntity);
    
        } else {
    
          this.showToast('info', selectedEntity, 'Error');
    
        }
    
      }
    
      unSubscribeEntities(matchedEntitiesArray, entityName) {
    
    
        const success = 'UnSubscribed';
    
        //pass entityIds arrays
    
        unSubscribe({
    
            entityIds: matchedEntitiesArray
    
          })
    
          .then(result => {
    
            if (result === success) {
    
              this.showspinner = true;
    
              this.showToast('Success', entityName, 'Success');
    
            }
    
            return refreshApex(this.wiredEntityWrapper);
    
          })
    
          .catch(error => {
    
            this.error = error;
    
          });
    
      }
    
    
      showToast(messageType, entityName, msg) {
    
        let message = (messageType === 'Success' ? 'Selected ' + entityName + '-Records Unfollowed' :
    
          'No ' + entityName + ' Records Selected');
    
        const evt = new ShowToastEvent({
    
          title: msg,
    
          message: message,
    
          variant: messageType
    
        });
    
        this.dispatchEvent(evt);
    
      }
    
    
      handleRowAction(event) {
    
        var action = event.detail.action.name;
    
        var row = event.detail.row;
    
        window.console.log('action', JSON.stringify(action));
    
        window.console.log('row', JSON.stringify(row));
    
        switch (action) {
    
          case 'View':
    
            this.viewCurrentRecord(row);
    
            break;
    
    
          default:
    
            /* code */
    
            break;
    
        }
    
      }
    
    
      viewCurrentRecord(currentRow) {
    
        const recordId = currentRow.parentId;
    
        const apiNameObject = currentRow.recObjectAPI;
    
        window.console.log('recordView', JSON.stringify(currentRow));
    
    
        this[NavigationMixin.Navigate]({
    
          type: 'standard__recordPage',
    
          attributes: {
    
            recordId: recordId,
    
            objectApiName: apiNameObject,
    
            actionName: 'view'
    
          }
    
        });
    
      }
    }
    .header-action {
    
      background: rgb(243, 242, 242);
    
      border-top-right-radius: 0.25rem;
    
      border-top-left-radius: 0.25rem;
    
      padding: 0.75rem;
    
    }
    <?xml version="1.0" encoding="UTF-8"?>
    
    <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="subscriptioncontainer">
    
        <apiVersion>46.0</apiVersion>
    
        <isExposed>true</isExposed>
    
        <targets>
    
            <target>lightning__Tab</target>
    
        </targets>
    
    </LightningComponentBundle>

     

     

     

     

Comments

  •  
    icon

    Jason says (Jan 21, 2020):

    There appears to be issues with the APEX class as some of the names don't match up. //import method from the Apex Class import getCallerUserfollowings from '@salesforce/apex/SubscriptionDetailsPerUser.getCallerUserfollowings'; import unSubscribe from '@salesforce/apex/SubscriptionDetailsPerUser.unSubscribe';

  •  
    icon

    Somnath says (Jan 22, 2020):

    Hi Json, That was a mistake while publishing it. I have rectified it.

  •  
    icon

    Vikram says (Jun 30, 2020):

    I tried to do the same, but options are not values in the combo box is not refreshed. However, in the console.log I can see the updated values. Can you help why this is happening.

Post Comments