5

It's possible to have actions for each row in a data table that change depending on the contents of the rows (that are changed by those very actions). For example:

enter image description here

enter image description here

The component reference provides the following example code (activate/deactivate contacts):

Controller

({
     init: function (cmp, event, helper) {
         var actions = helper.getRowActions.bind(this, cmp);
         cmp.set('v.mycolumns', [
             // Other column data here
             { label: 'State', fieldName: 'active', type: 'text' },
             { type: 'action', typeAttributes: { rowActions: actions } }
         ]);
         // Fetch or set your data
     },
     handleRowAction: function (cmp, event, helper) {
        var action = event.getParam('action');
        var row = event.getParam('row');
        switch (action.name) {
            case 'activate':
                helper.activateContact(cmp, row)
                break;
            case 'deactivate':
                helper.deactivateContact(cmp, row)
                break;
        }
    }
})

Helper

({
    getRowActions: function (cmp, row, doneCallback) {
        var actions = [];
        if (row['isActive']) {
            actions.push({
                'label': 'Deactivate',
                'iconName': 'utility:block_visitor',
                'name': 'deactivate'
            });
        } else {
            actions.push({
                'label': 'Activate',
                'iconName': 'utility:adduser',
                'name': 'activate'
            });
        }
        // simulate a trip to the server
        setTimeout($A.getCallback(function () {
            doneCallback(actions);
        }), 200);
    },
    activateContact: function (cmp, row) {
        var rows = cmp.get('v.data');
        var rowIndex = rows.indexOf(row);
        rows[rowIndex]['isActive'] = true;
        rows[rowIndex]['active'] = 'Active';
        cmp.set('v.data', rows);
    },
    deactivateContact: function (cmp, row) {
        var rows = cmp.get('v.data');
        var rowIndex = rows.indexOf(row);
        rows[rowIndex]['isActive'] = false;
        rows[rowIndex]['active'] = 'Inactive';
        cmp.set('v.data', rows);
    }
})

Of special note is this line in the reference's explanation, right before the code:

When you click the dropdown menu, an asynchronous call is made to determine which actions to display for the particular row.

It also says, the logic that determines which action to display can be created on initialization, but doesn't indicate how. This is probably the key to a solution.

I'm pretty sure that's the root of the reason my attempt hasn't worked yet, as my version is not using action drop downs.

I'm trying to do something similar, only with button icons. I was tasked with attempting to replicate, via a lightning:datatable, what was previously accomplished in a component with HTML:

enter image description here

enter image description here

When you click a utility:add buttonIcon, it gets replaced with utility:check; the prevous utility:check is replaced with a utility:add. Utility:add does other things on the back end, but I'm only interested in the UI change.

I tried following the reference's pattern, but I haven't been successful yet. However, I'm hoping I'm on the right track. The button icons are blank when the page loads and nothing happens when I click them. Below is my code so far:

Controller

init : function(component, event, helper) {
    var icon = helper.getIcon.bind(this, component);
    component.set('v.caseColumns', [
        {type: 'button-icon', typeAttributes: {name: 'addToCase', iconName: icon, alternativeText: 'Add the Pet to the Case'}},
        {label: 'Pet Name', fieldName: 'linkName', type: 'url', typeAttributes: {label: { fieldName: 'Name' }, target: '_blank'}},
        {label: 'Type', fieldName: 'Type__c', type: 'text'},
        {label: 'Breed', fieldName: 'Breed__c', type: 'text'},
        {label: 'Age', fieldName: 'Age__c', type: 'number'},
        {label: 'Active', fieldName: 'Active__c', type: 'boolean'}
    ]);

    helper.runInitProcess(component);                   
},

handleRowAction : function(component, event, helper) {
    var rowAction = event.getParam('action');
    var row = event.getParam('row');        

    switch (rowAction.iconName) {
        case 'utility:check':
              break;
        case 'utility:add': 
              helper.addToCase(component, row)
              break;
    }       
},

Helper

getIcon : function (component, row, doneCallback) {
     var icon = '';
     if (row['Selected_Pet__c']) {
        icon = 'utility:check';
     } else {
        icon = 'utility:add';
     }
     // simulate a trip to the server
     setTimeout($A.getCallback(function () {
         doneCallback(actions);
     }), 200);       
},

addToCase : function (component, row) {
    var rows = component.get('v.petList');
    var rowIndex = rows.indexOf(row);

    //Server Action

    rows[rowIndex]['Selected_Pet__c'] = true;
    component.set('v.petList', rows);
},

One last clue, the getIcon function doesn't run at all. As a matter of fact, referring to the reference code once again, the comparable getRowActions function only seems to run when you click an action drop down, consistent with the piece of explanation I highlighted earlier.

1
  • I am not sure I understand your question, is it: "How can I add button type columns to lightning:datatable that changes their icon according to a specific case?" Commented Oct 25, 2018 at 6:08

1 Answer 1

3

Forget emulating the data table with dynamic actions. Instead:

Controller

init : function(component, event, helper) {
    component.set('v.caseColumns', [
        {type: 'button-icon', typeAttributes: {name: 'addToCase', iconName: {fieldName: 'iconName'}, disabled: {fieldName: 'disabledValue'}, alternativeText: 'Add the Pet to the Case'}},
        {label: 'Pet Name', fieldName: 'linkName', type: 'url', typeAttributes: {label: { fieldName: 'Name' }, target: '_blank'}},
        {label: 'Type', fieldName: 'Type__c', type: 'text'},
        {label: 'Breed', fieldName: 'Breed__c', type: 'text'},
        {label: 'Age', fieldName: 'Age__c', type: 'number'},
        {label: 'Active', fieldName: 'Active__c', type: 'boolean'}
    ]);

    helper.runInitProcess(component);                   
},

handleRowAction : function(component, event, helper) {
    var row = event.getParam('row');
    helper.addToCase(component, row);
},

Helper

runInitProcess : function(component, event, helper){
    var action = component.get("c.getPets");
    action.setParams({
        recId: component.get("v.recordId")
    });
    action.setCallback(this, function(response) {
        var state = response.getState();
        if(state === "SUCCESS") {
            var records = response.getReturnValue();
            records.forEach(function(record){
                record.linkName = '/'+record.Id;
            });
            component.set("v.petList", records);
            this.setActionIcons(component);             
        }else {
            var errors = response.getError();
            if (errors) {
                var arrayLength = errors.length;
                for (var i = 0; i < arrayLength; i++) {
                    console.log(i);
                }
            } else {
                console.log("Unknown error");
            }
        }
    });
},

addToCase : function (component, row) {
    var rows = component.get('v.petList');
    var rowIndex = rows.indexOf(row);
    var serverAction = component.get("c.addPetToCase"); 

    serverAction.setParams({
        recId: component.get("v.recordId"),
        petId : row.Id
    });
    serverAction.setCallback(this, function(response) {
        var state = response.getState();
        if(state === "SUCCESS") {
            this.changeActionIcons(component, row);
        }else {
            //Do Something
        }
    });
    $A.enqueueAction(serverAction);         
},  

changeActionIcons : function (component, row) {
    var data = component.get('v.petList');
    data = data.map(function(rowData) {
        if (rowData.Id === row.Id) {
            rowData.iconName = 'utility:check';
            rowData.disabledValue = true;
        } else {
            rowData.iconName = 'utility:add';
            rowData.disabledValue = false;
        }
        return rowData;
    });
    component.set("v.petList", data);
},

setActionIcons : function (component) {
    var data = component.get('v.petList');
    data = data.map(function(rowData) {
        if (rowData.Selected_Pet__c === true) {
            rowData.iconName = 'utility:check';
            rowData.disabledValue = true;
        } else {
            rowData.iconName = 'utility:add';
            rowData.disabledValue = false;
        }
        return rowData;
    });
    component.set("v.petList", data);
}

Result

enter image description here

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .