【Salesforce】LWCでデータを表示してソートも可能にする方法

## 実装結果
取引先責任者の詳細ページを開いたら、同じ取引先に紐づく全取引先責任者を表示するようにしました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2640548/aa2770c2-e7bf-114e-0405-c7e6788fc714.png)
同じような内容は取引先の関連から観覧可能ですし、レポートでも作れますが、LWCのlightning-datatableでソートってどうやるんだろうと思ったので、備忘録として記載します

## 実装内容
表示した取引先責任者の取引先をもつ取引先責任者の一覧を取得するためのApex
```GetRelatedContacts.cls
public with sharing class GetRelatedContacts {
    @AuraEnabled(cacheable=true)
    public static List<Contact> getOtherContacts(Id siId) {
        System.debug(siId);
        List<Contact> conList = [
            SELECT Id, Name, AccountId
            FROM Contact
            WHERE Id = :siId
        ];
        System.debug(conList);

        List<Account> accList = [
            SELECT Id
            FROM Account
            WHERE Id = :conList[0].AccountId
        ];
        System.debug(accList);

        return [
            SELECT Id, AccountId, Name, Department, Title, Account.Name
            FROM Contact
            WHERE AccountId IN :accList
        ];
    }
}
```

データの表示を担っているHTML
```showReferenceData.html
<template>
    <lightning-card title="同一取引先の取引先責任者一覧" icon-name="custom:custom11">
        <lightning-datatable 
            data={tableData}
            columns={columns}
            key-field="id"
            sorted-by={sortedBy}
            onsort={onSorting}
            sorted-direction={sortDirection}
        ></lightning-datatable>
    </lightning-card>
</template>

```

```showReferenceData.js
import { api, LightningElement, wire, track } from 'lwc';
import getOtherContacts from '@salesforce/apex/GetRelatedContacts.getOtherContacts';
const columns = [
    { label: 'Id', fieldName: 'Id', type: 'Id', sortable: true },
    { label: '会社名', fieldName: 'AccountName', type: 'text', sortable: true },
    { label: '取引先責任者名', fieldName: 'Name', type: 'text', sortable: true },
    { label: '役職', fieldName: 'Title', type: 'text', sortable: true },
    { label: '部署', fieldName: 'Department', type: 'text', sortable: true },
];

export default class ShowReferenceData extends LightningElement {
    @api recordId;
    @track tableData;
    @track columns = columns;
    @track sortedBy;
    @track sortDirection;

    @wire(getOtherContacts, {siId: '$recordId'})
    gettableData({ error, data }) {
        if (data) {
            // JSON.stringifyで一旦Json形式の文字列に変換している
            // その後、JSON.parseで文字列にしたものをオブジェクト形式に戻している
            // これをしないと、以下のようなエラーとなってしまう
            // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Errors/Cant_define_property_object_not_extensible
            let tmpTableData = JSON.parse(JSON.stringify(data));
            tmpTableData.forEach(contact => {
                contact.AccountName = contact.Account.Name;
            });
            
            this.tableData = tmpTableData;
        }else if(error){
            console.log('Something happened: ' + JSON.parse(JSON.stringify(error)));
        }
    }

    onSorting(event) {
        this.sortedBy = event.detail.fieldName;
        this.sortDirection = event.detail.sortDirection;
        this.doSort(this.sortedBy, this.sortDirection);
    }

    doSort(selectedField, selectedDirection) {
        let targetData = JSON.parse(JSON.stringify(this.tableData));
        // ソートする際の最後の判定に利用
        let isAsc = selectedDirection === 'asc' ? 1: -1;

        // ソート処理
        targetData.sort((x, y) => {

            let xValue = x[selectedField];
            let yValue = y[selectedField];
            // xValue > yValueはTrueだと1、Falesだと0になる
            // ((xValue > yValue) - (yValue > xValue))は
            // xValue > yValueが成立すると1に
            // yValue > xValueが成立すると-1になる
            // isAscで比較結果の符号を変えるか否かを決定
            return isAsc * ((xValue > yValue) - (yValue > xValue));
        });
        this.tableData = targetData;
    }
    


}
```
>sortable: true

フィールドの定義の際にソートを許可する記載をしています

>let tmpTableData = JSON.parse(JSON.stringify(data));


この処理をしないと「TypeError: can't define property "x": "obj" is not extensible」になります

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Errors/Cant_define_property_object_not_extensible

>((xValue > yValue) - (yValue > xValue))

文字列の比較で、xValue > yValueはTrueだと1、Falesだと0になるためこのような記載になっています