
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の処理の長さが解決できました。
