В предыдущей статье мы создавали LWC редактируемую таблицу. Для того, чтобы сделать работу с ней более приятной для пользователей, добавим пару кнопок.
Редактирование записей у нас уже есть, добавим удаление и, соответственно, добавление новых контактов.
У элемента lightning-datatable есть набор чекбоксов, позволяющих отмечать строки таблицы как выбранные. Будем использовать их для удаления контактов, по несколько штук за раз. Количество выделенных строк выведем, как число - просто потому, что почему бы и нет
Итак, кнопка:
<div class="slds-col">
<span><p style="margin-left: 5%">Selected Records: <b style="color:red;">{recordsCount}</b></p></span>
</div>
<div class="slds-col">
<span>
<lightning-button label="Delete"
icon-name="utility:delete"
disabled={isDeleteButtonDisabled}
variant="destructive"
onclick={deleteContacts}
style="margin-left: 40%"></lightning-button>
</span>
</div>
Переменную isDeleteButtonDisabled будем использовать для того, чтобы избавить пользователей от искушения нажать большую красивую кнопку, когда этого делать не нужно.
Также, из новых переменных в нашем .js файле нам пригодятся
@track recordsCount = 0;
и
selectedRecords = [];
При нажатии на чекбоксы, в нашей таблице необходимо понимать, какие же строки были выбраны, чтобы в дальнейшем с ними работать:
getSelectedRecords(event) {
const selectedRows = event.detail.selectedRows;
this.recordsCount = event.detail.selectedRows.length;
let conIds = new Set();
for (let i = 0; i < selectedRows.length; i++) {
conIds.add(selectedRows[i].Id);
}
this.selectedRecords = Array.from(conIds);
if(this.recordsCount > 0){
this.isDeleteButtonDisabled = false;
}
else{
this.isDeleteButtonDisabled = true;
}
}
После того как строки для удаления выбраны, пользователь нажимает кнопку и выполняется метод:
deleteContacts(){
if(this.selectedRecords){
let promises = new Set();
for(let i = 0; i < this.selectedRecords.length; i++){
promises.add(deleteRecord(this.selectedRecords[i])); // deleteRecords - метод из uiRecordApi, его нужно заимпортить в начале
}
Promise.all(promises).then(records =>{
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Contact deleted',
variant: 'success'
})
);
this.selectedRecords = [];
this.isDeleteButtonDisabled = true;
return refreshApex(this.contacts);
}).catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error deleting record',
message: error.body.message,
variant: 'error'
})
);
});
}
}
Выбранные контакты удалены.
С добавлением нового контакта всё несколько интереснее.
С кнопкой всё понятно:
<lightning-button label="Add"
icon-name="utility:add"
variant="brand"
onclick={addContact}></lightning-button>
А вот в контроллере просто взять и создать запись не получится, ведь пользователю нужно каким-от образом ввести данные. Где-то на просторах интернета видел, советовали показывать модальное окно с полями для ввода и отдельной кнопкой “Сохранить”, потом вставлять запись и обновлять таблицу. Но писать всё это ради такого, казалось бы, обыденного функционала мне откровенно лень. К тому же, в нашем распоряжении такая распрекрасная таблица есть
Так добавим же в неё строку, которую можно будет редактировать, как и все остальные, исходя из уже имеющихся свойств таблицы:
addContact(){
let newContact = {Id:"",FirstName:"",LastName:"",Title:"",Phone:"",Email:""}
this.contacts.data = [...this.contacts.data, newContact];
}
В таблицу добавится строка с пустыми значениями, пользователь введёт данные. Обрабатываться они будут по нажатию на кнопку “Save”, как и простое редактирование. Значит метод handleSave, который я приводил в статье, необходимо доработать:
handleSave(event) {
const recordInputs = event.detail.draftValues.slice().map(draft => {
const fields = Object.assign({}, draft);
return { fields };
});
let promises = new Set();
for(let i = 0; i < recordInputs.length; i++){
if(JSON.stringify(recordInputs[i].fields.Id).includes('row-')){
delete recordInputs[i].fields.Id;
recordInputs[i].fields.AccountId = this.recordId;
recordInputs[i].apiName = CONTACT_OBJECT.objectApiName;
promises.add(createRecord(recordInputs[i]))
}
else{
promises.add(updateRecord(recordInputs[i]));
}
}
Promise.all(promises).then(records => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Contacts updated',
variant: 'success'
})
);
this.draftValues = [];
return refreshApex(this.contacts);
}).catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error updating record',
message: error.body.message,
variant: 'error'
})
);
});
}
lightning-datatable при отображении записей на странице оперирует Id этих записей. В нашем случае с созданием новой строки никакого Id записи у нас, естественно, нет. Но lightning-datatable присваивает строке свой уникальный Id в формате: “Id”:“row-Х”, где Х - порядковый номер строки, у которой не оказалось айдишника СФ.
uiRecordApi метод createRecord не принимает объект с параметром Id. В то же время, apiName объекта обязательно нужно указать, что мы и делаем в теле if-а.
Обновление работает как и работало.
Пы.Сы. Стоит обратить внимание на то, что uiRecordApi методы обращаются к серверу, используя общие лимиты организации. Для организаций ниже Unlimited edition-а суточный лимит на вызовы АПИ извне составляет 15000 + (1000 х кол-во лицензий). Каждая запись в нашем примере создаётся/обновляется/удаляется отдельным асинхронным вызовом СФ АПИ.
В качестве альтернативы, можно было бы использовать 1 вызов за раз (ну ладно, 2. Второй - для обновления таблицы), передавая JSON со списком контактов в апекс метод, который бы его распарсил и сделал всё что нужно уже на стороне сервера.