You need to sign in to do that
Don't have an account?
Mike Tol 1
Can't delete row in table with modal
Hi!
I have a contacts table and I need to delete a row using a modal window with two buttons: Cancel and Delete. The first button works, but the second doesn't. Here is mistake:
Please tell me what is wrong. Here is my code:
Parent:
HTML
<template>
<lightning-card title="Contact Table">
<lightning-layout multiple-rows="true" vertical-align="end">
<lightning-layout-item size="4" padding="around-small">
<!-- lightning input -->
<lightning-input class="text" type="text" label="Search by name" value={key} onchange={updateKey}></lightning-input>
</lightning-layout-item>
<lightning-layout-item size="2" padding="around-small">
<!-- lightning button -->
<lightning-button label="filter" onclick={handleSearch} variant="brand"></lightning-button>
</lightning-layout-item>
<lightning-layout-item size="12" padding="around-small">
<!--lightning table -->
<lightning-datatable key-field="id" data={contacts} columns={columns}
onrowaction={handleRowAction} row-number-offset={rowOffset}>
</lightning-datatable>
</lightning-layout-item>
</lightning-layout>
</lightning-card>
<c-modal-delete
title='Delete Contact'
message='“Are you sure?”'
confirm-label='Delete'
cancel-label='Cancel'
visible={isDialogVisible}
original-message={originalMessage}
name="confirmModal"
ondeletecontact={handleClick}
record-id={recordId}
selected-row={selectedRow}
></c-modal-delete>
</template>
JS
import {LightningElement, api, track, wire} from 'lwc';
import getContacts from '@salesforce/apex/ContactTableWithDeleteButton.getContacts';
import searchContacts from '@salesforce/apex/ContactTableWithDeleteButton.searchContacts';
import {deleteRecord} from 'lightning/uiRecordApi';
import {ShowToastEvent} from 'lightning/platformShowToastEvent';
import {NavigationMixin} from 'lightning/navigation';
import {refreshApex} from "@salesforce/apex";
const columns = [
{ label: 'Contact FirstName', fieldName: 'FirstName', type: 'text' },
{ label: 'Contact LastName', fieldName: 'LastName', type: 'text' },
{ label: 'Phone', fieldName: 'Phone', type: 'text' },
{ label: 'Email', fieldName: 'Email', type: 'Email' },
{ label: "Account Name", fieldName: "recordLink", type: "url",
typeAttributes: {label: {fieldName: "AccountName"}, tooltip: "Name", target: "_blank", linkify: true} },
{ label: 'Created Date', fieldName: 'CreatedDate', type: 'date',
typeAttributes: {day: 'numeric', month: 'numeric', year: 'numeric', hour: '2-digit', minute: '2-digit', hour12: true} },
{ type: 'button-icon', label: 'Delete', initialWidth: 75,
typeAttributes: {iconName: 'action:delete', title: 'Delete', name: 'delete_contact', variant: 'border-filled', alternativeText: 'Delete'} }
];
export default class contactTable extends LightningElement {
data;
columns = columns;
contacts;
searchValue = '';
error;
refreshData;
@api recordId;
@api objectApiName;
@api AccountId;
@api ContactId;
@track data = {};
@track record = {};
@track currentRecordId;
@track rowOffset = 0;
@track columns = columns;
@track isDialogVisible = false;
@track originalMessage;
@track displayMessage = 'Click on the \'Open Confirmation\' button to test the dialog.'
_wiredResult;
error;
@wire(getContacts)
wiredContacts(value) {
this.refreshData = value;
const {error, data} = value;
if (data) {
let contactData = JSON.parse(JSON.stringify(data));
contactData.forEach(record => {
if (record.AccountId) {
record.recordLink = "/" + record.AccountId;
record.AccountName = record.Account.Name;
}
});
this.contacts = contactData;
} else if (error) {
this.error = error;
}
}
handleRowAction(event) {
console.log('handleRowAction ', event);
if (event.detail.action.name === 'delete_contact') {
this.selectedRow = event.detail.row;
this.isDialogVisible = true;
}
}
handleClick(event) {
console.log("handleClick");
this.originalMessage = event.currentTarget.dataset.id;
if (event.target.name === 'confirmModal') {
if (event.detail.status === 'confirm') {
let selectedRow = event.detail.selectedRow;
this.deleteContacts(selectedRow);
this.isDialogVisible = false;
} else if (event.detail.status === 'cancel') {
this.isDialogVisible = false;
}
this.isDialogVisible = false;
}
}
deleteContacts(event) {
console.log('deleteContacts = ', event);
const action = event.detail.action;
console.log('action = ', JSON.stringify(action));
const row = event.detail.row;
console.log('row = ', JSON.stringify(row));
if (action.name === 'delete_contact') {
console.log('Done = ', row.Id);
deleteRecord(row.Id)
.then(() => {
const rows = this.data;
return refreshApex(this.refreshData);
})
}
}
updateKey(event){
this.searchValue = event.target.value;
}
handleSearch(){
searchContacts({searchKey: this.searchValue})
.then(result => {
let contactData = JSON.parse(JSON.stringify(result));
contactData.forEach(record => {
if (record.AccountId) {
record.recordLink = "/" + record.AccountId;
record.AccountName = record.Account.Name;
}
});
this.contacts = contactData;
})
.catch(error => {
console.log('Error:', error);
});
}
}
Child
HTML
<template>
<lightning-card if:true={visible}>
<div class="slds-container_small">
<section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
<div class="slds-modal__container">
<header class="slds-modal__header">
<button class="slds-button slds-button_icon slds-modal__close slds-button_icon-inverse" name="cancel" onclick={handleRowAction}>
<lightning-icon icon-name="utility:close"
alternative-text="close"
variant="inverse"
size="small">
</lightning-icon>
<span class="slds-assistive-text">Close</span>
</button>
<h2 data-id="title" class="slds-text-heading_medium slds-hyphenate">{title}</h2>
</header>
<div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
<p data-id="message">{message}</p>
</div>
<footer class="slds-modal__footer">
<lightning-button variant="neutral"
name="cancel"
label={cancelLabel}
title={cancelLabel}
onclick={handleRowAction}>
</lightning-button>
<lightning-button class="slds-m-left_x-small"
variant="brand"
name="confirm"
label={confirmLabel}
title={confirmLabel}
onclick={handleRowAction}>
</lightning-button>
</footer>
</div>
</section>
<div class="slds-backdrop slds-backdrop_open"></div>
</div>
</lightning-card>
</template>
JS
import {LightningElement, api, track} from 'lwc';
export default class ConfirmationDialogDelete extends LightningElement {
@api visible = false; //used to hide/show dialog
@api title = ''; //modal title
@api name; //reference name of the component
@api message = ''; //modal message
@api confirmLabel = ''; //confirm button label
@api cancelLabel = ''; //cancel button label
@api originalMessage; //any event/message/detail to be published back to the parent component
@api recordId;
@api deleteContacts;
@track isDialogVisible = false;
@track contactId;
//handles button clicks
@api selectedRow;
handleRowAction(event) {
//creates object which will be published to the parent component
let finalEvent = {
originalMessage: this.originalMessage,
status: event.target.name,
selectedRow: this.selectedRow
};
//dispatch a 'click' event so the parent component can handle it
this.dispatchEvent(new CustomEvent('deletecontact', {detail: finalEvent}));
}
}
Apex
public with sharing class ContactTableWithDeleteButton {
@AuraEnabled(cacheable=true)
public static List<Contact> getContacts() {
return [
SELECT Id, FirstName, LastName, Phone, Email, Account.Name, AccountId, CreatedDate
FROM Contact
];
}
@AuraEnabled(cacheable=true)
public static List<Contact> searchContacts(String searchKey) {
String searchKeyword = '%' + searchKey + '%';
List<Contact> contacts = [
SELECT Id, FirstName, LastName, Phone, Email, Account.Name, AccountId, CreatedDate
FROM Contact
WHERE Name LIKE :searchKeyword
];
return contacts;
}
}
I have a contacts table and I need to delete a row using a modal window with two buttons: Cancel and Delete. The first button works, but the second doesn't. Here is mistake:
Please tell me what is wrong. Here is my code:
Parent:
HTML
<template>
<lightning-card title="Contact Table">
<lightning-layout multiple-rows="true" vertical-align="end">
<lightning-layout-item size="4" padding="around-small">
<!-- lightning input -->
<lightning-input class="text" type="text" label="Search by name" value={key} onchange={updateKey}></lightning-input>
</lightning-layout-item>
<lightning-layout-item size="2" padding="around-small">
<!-- lightning button -->
<lightning-button label="filter" onclick={handleSearch} variant="brand"></lightning-button>
</lightning-layout-item>
<lightning-layout-item size="12" padding="around-small">
<!--lightning table -->
<lightning-datatable key-field="id" data={contacts} columns={columns}
onrowaction={handleRowAction} row-number-offset={rowOffset}>
</lightning-datatable>
</lightning-layout-item>
</lightning-layout>
</lightning-card>
<c-modal-delete
title='Delete Contact'
message='“Are you sure?”'
confirm-label='Delete'
cancel-label='Cancel'
visible={isDialogVisible}
original-message={originalMessage}
name="confirmModal"
ondeletecontact={handleClick}
record-id={recordId}
selected-row={selectedRow}
></c-modal-delete>
</template>
JS
import {LightningElement, api, track, wire} from 'lwc';
import getContacts from '@salesforce/apex/ContactTableWithDeleteButton.getContacts';
import searchContacts from '@salesforce/apex/ContactTableWithDeleteButton.searchContacts';
import {deleteRecord} from 'lightning/uiRecordApi';
import {ShowToastEvent} from 'lightning/platformShowToastEvent';
import {NavigationMixin} from 'lightning/navigation';
import {refreshApex} from "@salesforce/apex";
const columns = [
{ label: 'Contact FirstName', fieldName: 'FirstName', type: 'text' },
{ label: 'Contact LastName', fieldName: 'LastName', type: 'text' },
{ label: 'Phone', fieldName: 'Phone', type: 'text' },
{ label: 'Email', fieldName: 'Email', type: 'Email' },
{ label: "Account Name", fieldName: "recordLink", type: "url",
typeAttributes: {label: {fieldName: "AccountName"}, tooltip: "Name", target: "_blank", linkify: true} },
{ label: 'Created Date', fieldName: 'CreatedDate', type: 'date',
typeAttributes: {day: 'numeric', month: 'numeric', year: 'numeric', hour: '2-digit', minute: '2-digit', hour12: true} },
{ type: 'button-icon', label: 'Delete', initialWidth: 75,
typeAttributes: {iconName: 'action:delete', title: 'Delete', name: 'delete_contact', variant: 'border-filled', alternativeText: 'Delete'} }
];
export default class contactTable extends LightningElement {
data;
columns = columns;
contacts;
searchValue = '';
error;
refreshData;
@api recordId;
@api objectApiName;
@api AccountId;
@api ContactId;
@track data = {};
@track record = {};
@track currentRecordId;
@track rowOffset = 0;
@track columns = columns;
@track isDialogVisible = false;
@track originalMessage;
@track displayMessage = 'Click on the \'Open Confirmation\' button to test the dialog.'
_wiredResult;
error;
@wire(getContacts)
wiredContacts(value) {
this.refreshData = value;
const {error, data} = value;
if (data) {
let contactData = JSON.parse(JSON.stringify(data));
contactData.forEach(record => {
if (record.AccountId) {
record.recordLink = "/" + record.AccountId;
record.AccountName = record.Account.Name;
}
});
this.contacts = contactData;
} else if (error) {
this.error = error;
}
}
handleRowAction(event) {
console.log('handleRowAction ', event);
if (event.detail.action.name === 'delete_contact') {
this.selectedRow = event.detail.row;
this.isDialogVisible = true;
}
}
handleClick(event) {
console.log("handleClick");
this.originalMessage = event.currentTarget.dataset.id;
if (event.target.name === 'confirmModal') {
if (event.detail.status === 'confirm') {
let selectedRow = event.detail.selectedRow;
this.deleteContacts(selectedRow);
this.isDialogVisible = false;
} else if (event.detail.status === 'cancel') {
this.isDialogVisible = false;
}
this.isDialogVisible = false;
}
}
deleteContacts(event) {
console.log('deleteContacts = ', event);
const action = event.detail.action;
console.log('action = ', JSON.stringify(action));
const row = event.detail.row;
console.log('row = ', JSON.stringify(row));
if (action.name === 'delete_contact') {
console.log('Done = ', row.Id);
deleteRecord(row.Id)
.then(() => {
const rows = this.data;
return refreshApex(this.refreshData);
})
}
}
updateKey(event){
this.searchValue = event.target.value;
}
handleSearch(){
searchContacts({searchKey: this.searchValue})
.then(result => {
let contactData = JSON.parse(JSON.stringify(result));
contactData.forEach(record => {
if (record.AccountId) {
record.recordLink = "/" + record.AccountId;
record.AccountName = record.Account.Name;
}
});
this.contacts = contactData;
})
.catch(error => {
console.log('Error:', error);
});
}
}
Child
HTML
<template>
<lightning-card if:true={visible}>
<div class="slds-container_small">
<section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
<div class="slds-modal__container">
<header class="slds-modal__header">
<button class="slds-button slds-button_icon slds-modal__close slds-button_icon-inverse" name="cancel" onclick={handleRowAction}>
<lightning-icon icon-name="utility:close"
alternative-text="close"
variant="inverse"
size="small">
</lightning-icon>
<span class="slds-assistive-text">Close</span>
</button>
<h2 data-id="title" class="slds-text-heading_medium slds-hyphenate">{title}</h2>
</header>
<div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
<p data-id="message">{message}</p>
</div>
<footer class="slds-modal__footer">
<lightning-button variant="neutral"
name="cancel"
label={cancelLabel}
title={cancelLabel}
onclick={handleRowAction}>
</lightning-button>
<lightning-button class="slds-m-left_x-small"
variant="brand"
name="confirm"
label={confirmLabel}
title={confirmLabel}
onclick={handleRowAction}>
</lightning-button>
</footer>
</div>
</section>
<div class="slds-backdrop slds-backdrop_open"></div>
</div>
</lightning-card>
</template>
JS
import {LightningElement, api, track} from 'lwc';
export default class ConfirmationDialogDelete extends LightningElement {
@api visible = false; //used to hide/show dialog
@api title = ''; //modal title
@api name; //reference name of the component
@api message = ''; //modal message
@api confirmLabel = ''; //confirm button label
@api cancelLabel = ''; //cancel button label
@api originalMessage; //any event/message/detail to be published back to the parent component
@api recordId;
@api deleteContacts;
@track isDialogVisible = false;
@track contactId;
//handles button clicks
@api selectedRow;
handleRowAction(event) {
//creates object which will be published to the parent component
let finalEvent = {
originalMessage: this.originalMessage,
status: event.target.name,
selectedRow: this.selectedRow
};
//dispatch a 'click' event so the parent component can handle it
this.dispatchEvent(new CustomEvent('deletecontact', {detail: finalEvent}));
}
}
Apex
public with sharing class ContactTableWithDeleteButton {
@AuraEnabled(cacheable=true)
public static List<Contact> getContacts() {
return [
SELECT Id, FirstName, LastName, Phone, Email, Account.Name, AccountId, CreatedDate
FROM Contact
];
}
@AuraEnabled(cacheable=true)
public static List<Contact> searchContacts(String searchKey) {
String searchKeyword = '%' + searchKey + '%';
List<Contact> contacts = [
SELECT Id, FirstName, LastName, Phone, Email, Account.Name, AccountId, CreatedDate
FROM Contact
WHERE Name LIKE :searchKeyword
];
return contacts;
}
}
Thank You!
All Answers
Can you please refer these following examples which might help you to solve it :-
https://stackoverflow.com/questions/58786572/delete-rows-using-modal-confirmation
https://sfdcmonkey.com/2017/08/09/add-delete-rows-dynamic/
https://www.w3schools.com/howto/howto_css_delete_modal.asp
https://www.w3web.net/edit-save-and-remove-rows-dynamically-in-lightning-component/
Thanks
Thank You!
Now the button DELETE works. But unfortunately the contact is not deleted immediately, but only after the page is reloaded. And the button CANCEL doesn't work… Could you please suggest how to fix this?