lwcSalesforce

Maps and Filters in a LWC component, Part 1

This short post shows how we can use Maps to add additional information to an array and then filters to find records. As an example we will do a small table that has some details and then when the user selects a row then we will show more details. Lets build a basic datatable pulling details from the Accounts and then add to it.

So we will have an apex class:

public with sharing class mapsandfiltersController {
  @AuraEnabled(cacheable=true)
  public static List<Account> getAccountList() {
    return [SELECT Id, Name, BillingAddress FROM Account LIMIT 10];
  }
}

A lwc with a html template of:

<template>
  <lightning-card title="Maps and Filters">
    <div class="slds-m-around_small">
      <div style="height: 600px" class="slds-m-around_x-small">
        <lightning-datatable
          key-field="id"
          hide-checkbox-column="true"
          data={accountList}
          columns={columns}
        >
        </lightning-datatable>
      </div>
    </div>
  </lightning-card>
</template>

a design file as

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>55.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

and a javascript file of:

import { LightningElement, wire } from "lwc";
import getAccountList from "@salesforce/apex/mapsandfiltersController.getAccountList";

const actions = [{ label: "Show details", name: "show_details" }];

const columns = [
  { label: "Name", fieldName: "Name" },
  { label: "Billing Address", fieldName: "BillingAddress" },
  {
    type: "action",
    typeAttributes: { rowActions: actions }
  }
];

export default class MapsAndFilters extends LightningElement {
  accountList;

  columns = columns;

  @wire(getAccountList)
  getAccountList({ error, data }) {
    if (data) {
      console.log("--getAccountList --");
      console.log(data);
      this.accountList = data;
    } else if (error) {
      console.log("--error getAccountList --");
      console.log(error);
    }
  }
}

This will present a small table as shown below:

At the moment our Billing Address is not showing which is because BillingAddress returned from the controller is actually an object made up of the Billing Address details for instance BillingStreet, BillingCity etc. We can use a map to look at the information that has come back and set up a new field to display.

So lets’ set up a field called CompleteBillingAddress in the table columns:

const columns = [
  { label: "Name", fieldName: "Name" },
  { label: "Billing Address", fieldName: "CompleteBillingAddress" },
  {
    type: "action",
    typeAttributes: { rowActions: actions }
  }
];

We can now pass through the data returned and create a new field. We will need a new field called CompleteBillingAddress when we set the accountList up. We can use the Map function (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) to pass through each element the data and then add in extra properties, which are set by returning the new object and this forming a new array.

const modifiedData = data.map((item, index) => {
let completeBillingAddress = [];
if (item.BillingAddress) {
  if (item.BillingAddress.street != null) {
      completeBillingAddress.push(item.BillingAddress.street);
      }
  if (item.BillingAddress.city != null) {
      completeBillingAddress.push(item.BillingAddress.city);
      }
  if (item.BillingAddress.city != null) {
      completeBillingAddress.push(item.BillingAddress.city);
      }
  if (item.BillingAddress.state != null) {
      completeBillingAddress.push(item.BillingAddress.state);
      }
  if (item.BillingAddress.postalCode != null) {
      completeBillingAddress.push(item.BillingAddress.postalCode);
      }
 }
   return {
     ...item,
     CompleteBillingAddress: completeBillingAddress.join(", ")
     };
});

this.accountList = modifiedData;

The important parts of the code is the map function which will take our data array and run the arrow function on each item. The return function will return a new object that is added to the modifiedData to form a new array. Using the …item on the return will ensure that all the original fields from the item are included, ply and new objects. The index is not used in the code but this provides the index of the array item so you could do something like returning reference: index in the new object to number the items of the array:

const modifiedData = data.map((item, index) => {
.
.
.
   return {
     ...item,
     CompleteBillingAddress: newData
     };
});

this.accountList = modifiedData;

So we will get a nicely formatted address shown:

We could so something like adding another field to identify if there is a postcode and then giving an address quality flag. So we add a new column to our table called Address Quality and then link it to a fieldName AddressQuality. Then in our map code we can see if there is a postcode and then add the result of the

import { LightningElement, wire } from "lwc";
import getAccountList from "@salesforce/apex/mapsandfiltersController.getAccountList";

const actions = [{ label: "Show details", name: "show_details" }];

const columns = [
  { label: "Name", fieldName: "Name" },
  { label: "Billing Address", fieldName: "CompleteBillingAddress" },
  { label: "Address Quality", fieldName: "AddressQuality" },
  {
    type: "action",
    typeAttributes: { rowActions: actions }
  }
];

export default class MapsAndFilters extends LightningElement {
  accountList;

  columns = columns;

  @wire(getAccountList)
  getAccountList({ error, data }) {
    if (data) {
      console.log("--getAccountList v2--");
      console.log(data);
      const modifiedData = data.map((item, index) => {
        let completeBillingAddress = [];
        if (item.BillingAddress) {
          if (item.BillingAddress.street != null) {
            completeBillingAddress.push(item.BillingAddress.street);
          }
          if (item.BillingAddress.city != null) {
            completeBillingAddress.push(item.BillingAddress.city);
          }
          if (item.BillingAddress.city != null) {
            completeBillingAddress.push(item.BillingAddress.city);
          }
          if (item.BillingAddress.state != null) {
            completeBillingAddress.push(item.BillingAddress.state);
          }
          if (item.BillingAddress.postalCode != null) {
            completeBillingAddress.push(item.BillingAddress.postalCode);
          }
        }
        let addressQuality = "";
        if (item.BillingAddress) {
          addressQuality = item.BillingAddress.postalCode
            ? "Good"
            : "No Postal Code";
        } else {
          addressQuality = "No address provided";
        }
        return {
          ...item,
          CompleteBillingAddress: completeBillingAddress.join(", "),
          AddressQuality: addressQuality
        };
      });
      console.log(JSON.stringify(modifiedData));
      this.accountList = modifiedData;
    } else if (error) {
      console.log("--error getAccountList --");
      console.log(error);
    }
  }
}

In the next post we will add the ability to show more details from the datatable by taking the data and filtering to show more details.

Leave a Reply

Your email address will not be published. Required fields are marked *