
lwcコンポーネント内で、datatableにナビゲーション項目を配置したいことはよくあると思います。ナビゲーションURLを生成するために、NavigationMixinが標準で用意されていますので、それを使います。
//customSearch.js import { LightningElement, track } from 'lwc'; import { NavigationMixin } from "lightning/navigation"; import search from "@salesforce/apex/CustomAccountSearch.search"; export default class CustomSearch extends NavigationMixin(LightningElement) { columns = [ { label: "取引先", fieldName: "url", type: "url", typeAttributes: { label: { fieldName: 'Name' } } }, { label: "業種", fieldName: "Industry", } ]; @track accounts; async onSearch() { const found = await search(); const converted = await Promise.all(found.map(async (a) => { const url = await this.makeUrl(a); return { ...a, url }; })); this.accounts = converted.slice(0, 100); } async makeUrl(account) { return this[NavigationMixin.GenerateUrl]({ type: "standard__recordPage", attributes: { objectApiName: 'Account', recordId: account.Id, actionName: "view" } }); } }
/* customSearch.html */ <template> <lightning-button onclick={onSearch} label="search"></lightning-button> <div class="slds-scrollable" style="height:10rem"> <lightning-datatable key-field="Id" columns={columns} data={accounts} ></lightning-datatable> </div> </template>
//CustomAccountSearch.cls public with sharing class CustomAccountSearch { @AuraEnabled(cacheable=false) public static List<Account> search() { return [ SELECT Id, Name, Industry FROM Account ORDER BY Name Asc ]; } }
これで目的は達成できますが、GenerateUrlをonSearchで待ってしまっています。

GenerateUrlは非同期でURLを生成させようとしていますので、従いましょう。
type=”navigate”な列を受け付けるように、datatableを拡張します。今回はオブジェクトページへのナビゲーション項目を作成したいので、レコードのIdをvalueとして、別途必要なラベルとオブジェクト名はlabelとobjectとして渡せるようにします。
//customDatatable.js import LightningDatatable from "lightning/datatable"; import navigateCell from "./navigateCell.html"; export default class CustomDatatable extends LightningDatatable { static customTypes = { navigate: { template: navigateCell, typeAttributes: ["label", "object"] } }; }
/* navigateCell.html */ <template> <c-custom-datatable-navigate-cell value={value} label={typeAttributes.label} object={typeAttributes.object} ></c-custom-datatable-navigate-cell> </template>
navigateを実装します。GenerateUrlによるURLの生成は、ここまで遅延されます。Id、ラベル、オブジェクト名が渡ってきているので、それを元にURLを生成し、lightning-formatted-urlを使用してリンクを作ります。
//customDatatableNavigateCell.js import { LightningElement, api, track } from "lwc"; import { NavigationMixin } from "lightning/navigation"; export default class CustomDatatableNavigateCell extends NavigationMixin(LightningElement) { @api value; @api label; @api object; @track url; async connectedCallback(){ this.url = await this.generateRecordPageUrl(this.object, this.value); } generateRecordPageUrl(objectApiName, recordId) { return this[NavigationMixin.GenerateUrl]({ type: "standard__recordPage", attributes: { objectApiName: objectApiName, recordId: recordId, actionName: "view" } }); } }
/* customDatatableNavigateCell.html */ <template> <lightning-formatted-url value={url} label={label} ></lightning-formatted-url> </template>
type=”navigate”な列を受け付けるc-custom-datatableができました。
//customSearchAsync.js import { LightningElement, track } from 'lwc'; import search from "@salesforce/apex/CustomAccountSearch.search"; export default class CustomSearchAsync extends LightningElement { columns = [ { label: "取引先", fieldName: "Id", type: "navigate", typeAttributes: { label: { fieldName: "Name" }, object: 'Account' } }, { label: "業種", fieldName: "Industry", }, ]; @track accounts; async onSearch() { const found = await search(); this.accounts = found.slice(0, 100); } }
/* customSearchAsync.html */ <template> <lightning-button onclick={onSearch} label="search (customSearchAsync)"></lightning-button> <div class="slds-scrollable" style="height:10rem"> <c-custom-datatable key-field="Id" columns={columns} data={accounts} ></c-custom-datatable> </div> </template>

見た目変わらず、生成を遅延させることができました。さらに、生成ロジックをセルにお任せすることができたので、トップレベルでその実装をする必要がなくなりました。
onSearchの処理の長さが解決できました。
