We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date

How to add a button (custom action) to rows?

Hi,


I was unable to find a 'how to' in the documentation nor the forum/ (I was looking for something like this https://demos.telerik.com/kendo-ui/grid/custom-command)
I'm using plain javascript in an asp.net web page.

I have a grid in which I've added a custom (template) column:

script id="actionTemplate" type="text/x-template"
    button type='button' Action /button
/script

var gridColumns = [
   {
      headerText: 'Action',
      template: '#actionTemplate' 
   },
   { field: 'Type', headerText: 'Type', width: 50 },
   { field: 'Description', headerText: 'Name' },
   .....
   .....
];

var grid = new ej.grids.Grid({
                dataSource: data,                
                columns: gridColumns,
                ....
                ...

How can I bound it to make an action when clicked, for the column's data where it was clicked?
Do I have access to the grid's dataSource's "current row"? Or I can only see the grid's columns like ${Description}? Do I need to add 'hidden' columns with the row's data I need? If so, how? 
Can I make the 'action' button an EJ2 button, bind its events as such, and  style it like this https://ej2.syncfusion.com/16.1.37/documentation/button/types-and-styles.html?lang=es5#icons?

I'm sorry about the basic questions, but I find the documentation rather poor. The 'API' documentation doesn't says anything (e.g. https://ej2.syncfusion.com/16.1.37/documentation/grid/api.html?lang=es5). At least one example usage for each property or method would help a lot.


Thanks


13 Replies

PS Pavithra Subramaniyam Syncfusion Team June 4, 2018 12:23 PM UTC

Hi Horacio, 

We have checked your query and you can achieve our requirement by using ‘column.template’ property. You can add the click action for the ‘column.template’ by defining the ‘onClick’ event of the template and you can access the current row data in that click event by using ‘getRowObjectFromUID()’ method of Grid component.  

Another way: 
You can also achieve the same by using command column feature of Essential JavaScript 2 Grid component. You can assign the command buttons in the ‘column.commands’ property. By default, Essential JavaScript 2 Grid command column has 4 built-in command buttons which are used for CRUD operations. You can also define the custom buttons in command columns and the click action for that button. Please refer to the below code example, documentation link and sample link. 

[index.chtml] 
<script> 
var onClick = function(args){  // click event of button 
    var rowObj = grid.getRowObjectFromUID(ej.base.closest(args.target, '.e-row').getAttribute('data-uid'));  // method to get current row object 
    var data = rowObj.data; 
    alert(JSON.stringify(data)); 
} 
 
    var grid = new ej.grids.Grid({ 
    dataSource: employeeData, 
    editSettings: { allowEditing: true, allowDeleting: true }, 
    columns: [ 
              {headerText: 'Action',template: '#actionTemplate',width: 125},  // using column.template 
       .  .  . 
       { headerText: 'Commands', width: 120, commands: [{ buttonOption: { content: 'Details', cssClass: 'e-primary', click: onClick } }]}      // using custom command button 
    ], 
    height: 310 
}); 
grid.appendTo('#Grid'); 
 
</script> 
<script id="actionTemplate" type="text/x-template"> 
    <input type='button' value='Action' onClick="onClick(event);"> 
</script> 



Query #2: Can I make the 'action' button an EJ2 button, bind its events as such, and  style it like   
  
You can add the Style to the custom command buttons, by adding the required predefined class names in the ‘cssClass’ property. Please refer to the below code example and sample link. 
 
[index.chtml] 
<script> 
var onClick = function(args){ 
    var rowObj = grid.getRowObjectFromUID(ej.base.closest(args.target, '.e-row').getAttribute('data-uid')); 
    var data = rowObj.data; 
    alert(JSON.stringify(data)); 
} 
 
    var grid = new ej.grids.Grid({ 
    dataSource: employeeData, 
    editSettings: { allowEditing: true, allowDeleting: true }, 
    columns: [ 
       .  .  . 
       { headerText: 'Commands', width: 120, commands: [{ buttonOption: { content: 'Details', cssClass: 'e-primary', click: onClick } }]} 
    ], 
    height: 310 
}); 
grid.appendTo('#Grid'); 
 
</script> 


Regards, 
Pavithra S. 




HO horacioj June 6, 2018 12:32 AM UTC

Awesome, thanks!


PS Pavithra Subramaniyam Syncfusion Team June 6, 2018 01:25 PM UTC

Hi Horacio, 
 
Thanks for your update. 
 
We are glad to hear that the issue has been resolved. 
 
Please contact us if you have any queries. 
 
Regards, 
Pavithra S. 



HO horacioj June 6, 2018 10:10 PM UTC

Hi again,

This should be easy..., but I tried everything I could think of without any luck.

In the "var onClick = function(args){ ..." I may end up updating / deleting data in the remote data source.
I was unable to make the grid refresh its data.
I tried everything I could find in the documentation:
grid.dataBind();
grid.refreshColumns();
grid.refresh();

None of these methods (even the three of them in that order) refreshed the grid's data. E.g. deleted rows were still showing up.
I neither couldn't find any suitable API call to do this in the data source itself, which is a DataManager:  data = new ej.data.DataManager({.....

Thanks

PS:
Any idea why I'm not getting email notifications about updates in forum posts I've created?
For example, I didn't get any notification about yesterday's update at https://www.syncfusion.com/forums/137904/how-to-globalize-and-localize-ej-2-components-using-plain-javascript-in-asp-net
This happened for other posts too. I don't see a "subscribe" checkbox either..  I get notifications about my own posts and edits, though.



PS Pavithra Subramaniyam Syncfusion Team June 7, 2018 12:56 PM UTC

Hi Horacio, 

We have checked your query but we could not reproduce the issue at our end. We have prepared a simple sample based on your query in which we have bind Grid with remoteData and performed CRUD operation. Please refer to the below sample link. 


Could you please provide below information about your issue that will be helpful for us to provide a better solution as early as possible. 

  1. Share the Adaptor type You are using in your application.
  2. Share the details how you are handling the CRUD actions in your sample.
  3. Share your Grid sample code if possible.
  4. Share your Server side code for perform CRUD operations.
  5. Share the stack trace if you have any errors on console.

Regards, 
Pavithra S.


HO horacioj June 7, 2018 07:32 PM UTC

Hi Pavithra,

The server side code is fine. Actually, everything is working fine except I'm unable to make the grid to refresh its data. i.e. make the DataManager get the current data from the server. If I reload the page, I see the deleted row gone. 

var data = new ej.data.DataManager({
url: sbaseServiceSubscriptions + 'SubscriptionServices/GetMySubscriptions',
adaptor: new ej.data.WebApiAdaptor(),
headers: requestHeaders,
offline: true
}, new ej.data.Query().addParams('ModuleId', parmModuleId));


var onClick = function (args) {

$.dnnConfirm({
text: Localize('RemoveSubscription'),

callbackTrue: function () {

var rowObj = grid.getRowObjectFromUID(ej.base.closest(args.target, '.e-row').getAttribute('data-uid'));
var gdata = rowObj.data;

grid.showSpinner();

$.ajax({
type: "POST",
async: true,
url: sbaseServiceSubscriptions + 'SubscriptionServices/UnSubscribe',
beforeSend: ssf.setModuleHeaders,
data: {
"ModuleId": gdata.ModuleId,
"ItemId": gdata.ItemId
}
})
.done(function () { // (response) {
// THIS DOESN'T WORK, THERE IS NO ERROR, BUT THE GRID ISN'T UPDATED (UNLESS I DO A FULL PAGE REFRESH)
grid.dataBind();
grid.refreshColumns();
grid.refresh();
})
.fail(function(jqXhr, exception) {
processException(jqXhr, exception, "Error processing subscription");
})
.always(function() {
grid.hideSpinner();
});
}
});
}

var gridColumns = [
{ field: 'Type', headerText: 'Type', width: 50 },
{ field: 'Description', headerText: 'Name' },
{ field: 'Path', headerText: 'Path (in the module)' },
{ field: 'CreatedOnDate', headerText: 'Created', format: { type: 'date', skeleton: 'medium' }, width: 100 },

{ headerText: '', width: 30, commands: [{ buttonOption: { content: '<i class="fas fa-envelope fa-lg">i>',
cssClass: 'e-primary e-small', click: onClick } }] }
];

var grid = new ej.grids.Grid({
dataSource: data,
columns: gridColumns,
toolbar: ['ExcelExport', 'Search'],
allowExcelExport: true,
allowSorting: true,
allowFiltering: true,
allowResizing: true,
filterSettings: { type: 'Menu' },
allowPaging: true,
pageSettings: { pageCount: 5, pageSize: 50, pageSizes: [5, 10, 50, 100] },
editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Dialog' },
actionFailure: (e) => {
var span = document.createElement('span');
grid.element.parentNode.insertBefore(span, grid.element);
span.style.color = "#FF0000";
var err = '';
if (e.error.responseText !== undefined) err = e.error.responseText;
if (err !== '') {
span.innerHTML = "Server exception: " + err;
console.error("Error: ", err);
}
}
});


grid.toolbarClick = function(args) {
if (args['item'].id === 'Grid_excelexport') {
grid.excelExport();
}
}

grid.appendTo('#' + 'SubscriptionsGrid' + smoduleId);



Other issue:
Regarding the custom column / command:
{ headerText: '', width: 30, commands: [{ buttonOption: { content: '<i class="fas fa-envelope fa-lg">i>',
cssClass: 'e-primary e-small', click: onClick } }] }

The title is rendered as the content. I don't want "'i class="fas fa-envelope fa-lg'" to show up as the button's Tooltip. I want to set a proper title. I tried adding a "title: 'my title'" to the buttonOptions, but it is ignored. Is there any way to solve this?



Thanks,
Horacio


PS Pavithra Subramaniyam Syncfusion Team June 8, 2018 12:54 PM UTC

Hi Horacio, 

Query #1:  everything is working fine except I'm unable to make the grid to refresh its data. i.e. make the DataManager get the current data from the server. 
 
We have checked your code example but we could not reproduce the issue at our end. We have prepared a sample in which all Grid actions are done in client side and edited data is sent to the server through AJAX request to update the Server data. Please refer to the below sample link. 
 
 
If you are still facing the issue Could you please provide below information that will be help full for us to provide a better solution as early as possible. 
 
  1. Share the Essential JavaScript 2 package version you are using.
  2. Share the response in network tab after AJAX call sent.
  3. Share the stack trace if any script error thrown.
  4. Please reproduce the issue in the provided sample if possible.

Query #2:  I want to set a proper title. 
You can achieve your requirement by using queryCellInfo event of Grid component which will be triggered for every cell access. In that event you can set the ‘title’ property for the button component. Please refer to the below code example and Documentation link. 

[index.chtml] 
var grid = new ej.grids.Grid({ 
        dataSource: data, 
        columns: gridColumns, 
        queryCellInfo: queryCellInfo, 
        .  .  . 
    }); 
 
   function queryCellInfo(e){ 
       if (e.cell.classList.contains('e-unboundcell')) { 
           e.cell.getElementsByClassName('e-primary')[0].title = 'My title'; 
       } 
    } 
 
    grid.appendTo('#Grid'); 


Regards, 
Pavithra S. 



HO horacioj June 18, 2018 12:00 AM UTC

Hi,

query 2: 
Thanks, solved.

query 1: 
Your sample project isn't doing the same thing. It isn't changing the data set. It is always returning the same data. 
In my case, the ej.data.DataManager gets the data from the server, and clicking the button in the row may end in one or more records (grid's rows) being deleted. 
grid.dataBind() and/or  grid.refreshColumns() and/or grid.refresh() should get fresh data from the ej.data.DataManager, reload the grid an one or more rows (depending on the AJAX server process) should have been gone. This isn't happening. The data (managed by the ej.data.DataManager) isn't being refreshed.

If I remove the "offline: true" from the ej.data.DataManager, then "grid.refresh()" is enough to see the grid working properly. The problem is, I don't want/need to implement sorting, filtering, paging, etc. at server site. I want to rely in the grid doing all of this by its own (built-in) at client side.
So, the problem/question can be reworded as: How can I make the "grid.refresh()" to get fresh data from the ej.data.DataManager when it is set for "offline: true"? Shouldn't "grid.refresh()" bee doing its thing despite the "offline: true" configuration? What method should be called to make the ej.data.DataManager get fresh data despite its "offline" setting being true?

Share the Essential JavaScript 2 package version you are using. 
     => 16.1.0.37
 
Share the response in network tab after AJAX call sent. 
     => the problem isn't making the AJAX call work. This (AJAX call) was always working fine. The problem is what happens in the grid after the call. The call is removing one row from the data set, but even after trying one or all of the following commands (grid.dataBind(); and/or  grid.refreshColumns(); and/or grid.refresh();), the grid is still showing the deleted record.

Share the stack trace if any script error thrown.
     => there is nothing. No error, no nothing. What happens is that grid.dataBind() and/or  grid.refreshColumns() and/or grid.refresh() aren't refreshing the grid's rows at all.

 
Thanks


PS Pavithra Subramaniyam Syncfusion Team June 18, 2018 12:13 PM UTC

Hi Horacio, 

In Essential JavaScript 2 Grid component, If we set DataManager offline property as true, then Grid will sent the server side request only once for loading the data at initialization. After that all actions will be done based on the loaded data in the client side only. So Making changes in Sever data will not be affected in Grid unless you load the Grid again. This is the default behavior of Grid component. From your query We have understood that you want to do grid operation like sorting ,filtering  in client side and CRUD actions in server side. To achieve your requirement, we suggest you use the RemoteSaveAdaptor to achieve your requirement. This adaptor helps to binding local data and performs all DataManager queries in client-side. Also interacts with server-side only for CRUD operations to pass the modified records.  

So, we have achieved your requirement using Grid load event. In this event, we can fetch the whole data from WebAPI service using AJAX and bound the Grid data source with remoteSave adaptor like as follows, 

[index.chtml] 
var grid = new ej.grids.Grid({ 
        load:load, 
        toolbar: ['Add','Delete', 'Edit','Update','Cancel'], 
        allowExcelExport: true, 
        allowSorting: true, 
        .  .  . 
    }); 
 
   function load(args) { 
        let ajaxObj = new ej.base.Ajax(); 
        ajaxObj.url = 'api/Orders'; 
        ajaxObj.type = 'GET'; 
        ajaxObj.send().then(function (value) { 
 
            //bind the Grid data in AJAX success function 
            var gridObject = document.querySelector("#Grid").ej2_instances[0]; //grid object 
            var data = JSON.parse(value); 
 
            gridObject.dataSource = new ej.data.DataManager({ 
                    json: data.Items, 
                adaptor: new ej.data.RemoteSaveAdaptor, //remote save adaptor 
                insertUrl: '/Home/Insert', 
                updateUrl: '/Home/Update', 
                removeUrl: '/Home/Delete' 
            });  
        });        
    } 
    grid.appendTo('#Grid'); 



Regards, 
Pavithra S. 



HO horacioj June 18, 2018 03:50 PM UTC

Hello Pavithra,

So, "grid.refresh();" does nothing when offline=true?

Thanks for the new example code, but it is nothing like what I'm trying to do.
I need to send custom headers and a paramenter, same as what I was doing before. 
Which is the right way to do this using the grid's load event?
This was already solved and working fine when using :  
var data = new ej.data.DataManager({.... headers: requestHeaders }, new ej.data.Query().addParams('ModuleId', parmModuleId));

Should I do this using ajaxObj.beforeSend = ... and ajaxObj.data = ... ?
I couldn't find any code example in the documentation (https://ej2.syncfusion.com/16.1.37/documentation/base/api-ajax.html) or forums.

Also, I'm not using (and don't want to use) the toolbar. I want to keep the button on each row, as it is now (the code send before). The button may or may not do one or more actions affecting the rows (e.g. delete some). 


Thanks


PS Pavithra Subramaniyam Syncfusion Team June 19, 2018 01:24 PM UTC

Hi Horacio, 

Query #1: "grid.refresh();" does nothing when offline=true? 
 
In Essential JavaScript 2 Grid, if DataManager offline property is set to true, Grid will send the server request only for initialization. Other actions including refresh are done in client side. So in Server data base changes after Grid initialization will not be affected with offline true. 
 
Query #2: I need to send custom headers and a parameter, same as what I was doing before.  
 
You can set the custom headers and send parameters by using DataManager’s headers property and query.addParams() method in the load event of Grid component. Please refer to the below code example , Documentation link and sample link.. 
 
In that sample we have used command column buttons to perform CRUD operations instead of toolbar.  
 
[index.chtml] 
var gridColumns = [ 
        { field: 'OrderID',isPrimaryKey:true, headerText: 'Type', width: 50 }, 
        { field: 'EmployeeID', headerText: 'Name' },   
        { headerText: 'Commands', width: 120, commands: [{ type: 'Edit', buttonOption: { cssClass: 'e-flat', iconCss: 'e-edit e-icons' } }, 
            { type: 'Delete', buttonOption: { cssClass: 'e-flat', iconCss: 'e-delete e-icons' } }, 
            { type: 'Save', buttonOption: { cssClass: 'e-flat', iconCss: 'e-update e-icons' } }, 
            { type: 'Cancel', buttonOption: { cssClass: 'e-flat', iconCss: 'e-cancel-icon e-icons' } }] 
        } 
    ]; 
 
    var grid = new ej.grids.Grid({ 
        columns: gridColumns, 
        load:load, 
        .  .  . 
    }); 
 
    function load(args) { 
 
        new ej.data.DataManager({ 
            url: '/Home/GridDatasource', 
            adaptor: new ej.data.UrlAdaptor(), 
            headers: [{ 'Authenticcation': 'bearer123' }]    
        }).executeQuery(new ej.data.Query().addParams('ModuleId', 2)).then((e) = 
        function (e) { 
            var gridObject = document.querySelector("#Grid").ej2_instances[0]; //grid object 
            gridObject.dataSource = new ej.data.DataManager({ 
                json: e.result, 
                adaptor: new ej.data.RemoteSaveAdaptor, //remote save adaptor 
                insertUrl: '/Home/Insert', 
                updateUrl: '/Home/Update', 
                removeUrl: '/Home/Delete', 
                headers: [{ 'Authenticcation': 'bearer123' }] 
            });    
        }); 
    }      
    grid.appendTo('#Grid'); 




Regards, 
Pavithra S. 



HO horacioj June 19, 2018 11:30 PM UTC

You are my hero!

This is my working code, using the custom button the way I thought. Despite this being working fine (apparently), am I doing things wrong?


var onClick = function (args) {
var rowObj =
grid.getRowObjectFromUID(ej.base.closest(args.target, '.e-row').getAttribute('data-uid'));
var data = rowObj.data;

grid.showSpinner();
$.ajax({
type: "POST",
async: true,
url: sbaseServiceSubscriptions + 'TheServices/TheAction',
beforeSend: ssf.setModuleHeaders,
data: {
"ModuleId": data.ModuleId,
"IsFolder": data.IsFolder,
"ItemId": data.ItemId,
"ItemName": data.Description,
"ItemPath": data.Path,
"DoSubscribe": false
}
})
.done(function (response) {
if (response.dataWasUpdated) loadData();
})
.fail(function (jqXhr, exception) {
console.error('fail..');
})
.always(function () {
grid.hideSpinner();
});
};

var gridColumns = [
{ field: 'Type', headerText: 'Type', width: 50 },
{ field: 'Description', headerText: 'Name', width: 100 },
{ field: 'Path', headerText: 'Path (in the module)', width: 100 },
{ field: 'CreatedOnDate', headerText: 'Created', format: { type: 'date', skeleton: 'medium' }, width: 60 },
{
headerText: '', width: 30, commands: [{
buttonOption:
{
content: '<i class="fas fa-envelope fa-lg"></i>',
cssClass: 'e-primary e-small',
click: onClick
}
}]
}
];

function queryCellInfo(e) {
if (e.cell.classList.contains('e-unboundcell')) {
e.cell.getElementsByClassName('e-primary')[0].title = 'The Title';
}
}

var grid = new ej.grids.Grid({
mid: smoduleId,
//dataSource: data,
load: gridLoad,
columns: gridColumns,
queryCellInfo: queryCellInfo,
toolbar: ['ExcelExport', 'Search'],
allowExcelExport: true,
allowSorting: true,
allowFiltering: true,
allowResizing: true,
filterSettings: { type: 'Menu' },
allowPaging: true,
pageSettings: { pageCount: 5, pageSize: 50, pageSizes: [5, 10, 50, 100] },
editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Dialog' },
actionFailure: (e) => {
var span = document.createElement('span');
grid.element.parentNode.insertBefore(span, grid.element);
span.style.color = "#FF0000";
var err = '';
if (e.error.responseText !== undefined) err = e.error.responseText;
if (err !== '') {
span.innerHTML = "Server exception: " + err;
console.error("Error: ", err);
}
}
});

var parmModuleId = getQueryStringParameter('ModuleId');
if (parmModuleId === undefined || parmModuleId === null || parmModuleId === 0) parmModuleId = -1;

var afValue = ssf.getAntiForgeryValue();
var tabId = ssf.getTabId();
var moduleId = ssf.getModuleId();
var requestHeaders = [];
if (tabId > -1) {
requestHeaders.push({ "ModuleId": moduleId });
requestHeaders.push({ "TabId": tabId });
}
if (afValue) {
requestHeaders.push({ "RequestVerificationToken": afValue });
}

function loadData() {
var data = new ej.data.DataManager({
url: sbaseServiceSubscriptions + 'SubscriptionServices/GetMySubscriptions',
adaptor: new ej.data.UrlAdaptor(),
headers: requestHeaders
//,offline: true
});

data.executeQuery(new ej.data.Query().addParams('ModuleId', parmModuleId))
.then((e) = function (e) {
var gridObject = document.querySelector('#grid').ej2_instances[0];
gridObject.dataSource = e.result.Items;
});
}

function gridLoad(args) {
loadData();
};

grid.toolbarClick = function (args) {
if (args['item'].id === 'grid' + '_excelexport') {
grid.excelExport();
}
};

grid.appendTo('#grid');


Thanks!


PS Pavithra Subramaniyam Syncfusion Team June 20, 2018 12:55 PM UTC

Hi Horacio, 

We have checked your query and if you don’t want to use RemoteSaveAdaptor which is used for perform only the CRUD operations in server side, then you can reload the data in the Ajax success method. Please contact us if you have any queries. We are always happy to assist you. 

Regards, 
Pavithra S 


Loader.
Live Chat Icon For mobile
Up arrow icon