I have a problem with DataTables - I want to use the responsive add-on to hide columns on smaller screen sizes, unfortunately the responsive add-on is hiding columns on larger screen sizes when it really doesn't need to.
Here is my javascript code:
var table = $('#peopleTable').DataTable({
responsive: true,
ajax: {
dataType: 'text',
type: 'POST',
url: apiUrl,
dataSrc: function (json) {
return $.parseJSON(json);
}
},
columns: [
{
data: 'name',
responsivePriority: 1,
width: '5%',
render: function (data, type, row) {
return '<img class="icon" title="' + row.people_type + '" src="<?php echo $localPath; ?>/webimg/people-type/b/' + row.people_type_id + '.png">' + row.main_contact + ' # ' + row.name + '';
}
},
/*{
data: 'main_contact',
responsivePriority: 1,
width: '5%'
},*/
{
data: 'add1',
responsivePriority: 1,
width: '5%',
render: function (data, type, row) {
var output = [];
if (row.add1) { output.push(row.add1); }
if (row.add2) { output.push(row.add2); }
if (row.add3) { output.push(row.add3); }
if (row.town) { output.push(row.town); }
var outputStr = output.join(', ');
return '<span class="address-trunc" title="' + outputStr + '">' + outputStr + '</span>';
}
},
{
data: 'phone',
responsivePriority: 1,
width: '5%'
},
/*{
data: 'email',
responsivePriority: 1,
width: '5%',
render: function (data, type, row) {
return '' + row.email + '';
}
},*/
{
data: 'id',
orderable: false,
responsivePriority: 1,
width: '5%',
render: function (data, type, row) {
var url = '<?php echo $localPath;?>/people/person.php?id=' + row.id;
return 'View '
<?php if ($activeUser->can('delete')) { ?>
+ 'Delete'
<?php } ?>
;
}
}
]
});
As you can see I have been playing about with the code in order to make all the columns appear on a large screen size.
When I started off I had more columns in play (they are now commented out), I had all the widths adding up to 100%, and I have all the responsivePrioritys set to correct values (instead of them all being 1).
Reducing the number of columns, setting lower widths, altering responsivePrioritys - doing all of these things had no effect, on a large screen the responsive add-on was still insisting on hiding at least 1 column.
How do I stop this? I still want to use the add-on as it is very useful on smaller screens, but I don't want it force the hiding of columns when it doesn't need to.
To show you what is happening, here is a screen shot - you can see the huge almost-empty columns where there is plenty of room for another column - and yet DataTables is insisting on hiding a column behind the + symbol on the far left.
Responsive extension has many classes to configure when columns should be visible/hidden.
You could use desktop class to specify columns shown for window width greater than or equal to 1024 px.
See this example for code and demonstration.
Why not just use
var table = $('#peopleTable').DataTable({
responsive: window.innerWidth < 1000 ? true : false,
...
})
I mean simply not initialize the responsive extension when it is not needed. 1000 is just a suggestion, "larger screen sizes" is relative :)
demo -> http://jsfiddle.net/8vtqsf7z/
I'm trying to create a custom grid with columns for Feature Predecessors and Successors.
I've managed to extract the data and display the relevant formatted IDs of the pre+suc in clear text. Now I would like to format these as "standard" FormattedIDs with QDP/click options.
My display looks like this, is this the right path, what should I return in order to have correct formatting?
var myGrid = Ext.create('Ext.Container', {
items: [
{
xtype: 'rallygrid',
columnCfgs: [
'FormattedID',
'Name',
{ // Column 'Successors'
xtype: 'templatecolumn',
tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate'),
dataIndex: 'Successors',
renderer: function(value, metaData, record) {
//console.log('Display in renderer: ', record.successorStore);
var mFieldOutputSuc = '';
var i;
var mDependency;
for (i = 0; i < record.successorStore.getCount(); i++) {
mDependency = record.successorStore.getAt(i);
console.log('mDependency = ', mDependency);
mFieldOutputSuc = mFieldOutputSuc + mDependency.get('FormattedID') + '<br>'; // Correct return value?
}
return mFieldOutputSuc;
}, //renderer: function(value, metaData, record) {
}, // Column 'Successors'
I'd check out this utility method: https://help.rallydev.com/apps/2.1/doc/#!/api/Rally.nav.DetailLink-method-getLink
You should be able to just put that in there where you have your //Correct return value? comment:
mFieldOutputSuc += Rally.nav.DetailLink.getLink({
record: mDependency
});
There are some more config options you can pass as well, to customize the link further, but I think that should get you started...
I'm using Dojo GridX with many modules, including filter:
grid = new Grid({
cacheClass : Cache,
structure: structure,
store: store,
modules : [ Sort, ColumnResizer, Pagination, PaginationBar, CellWidget, GridEdit,
Filter, FilterBar, QuickFilter, HiddenColumns, HScroller ],
autoHeight : true, autoWidth: false,
paginationBarSizes: [25, 50, 100],
paginationBarPosition: 'top,bottom',
}, gridNode);
grid.filterBar.applyFilter({type: 'all', conditions: [
{colId: 'type', condition: 'equal', type: 'Text', value: 'car'}
]})
I've wanted to access the items, that are matching the filter that was set. I've travelled through grid property in DOM explorer, I've found many store references in many modules, but all of them contained all items.
Is it possible to find out what items are visible in grid because they are matching filter, or at least those that are visible on current page? If so, how to do that?
My solution is:
try {
var filterData = [];
var ids = grid.model._exts.clientFilter._ids;
for ( var i = 0; i < ids.length; ++i) {
var id = ids[i];
var item = grid.model.store.get(id);
filterData.push(item);
}
var store = new MemoryStore({
data : filterData
});
} catch (error) {
console.log("Filter is not set.");
}
I was able to obtain filtered gridX data rows using gridX Exporter. Add this Exporter module to your grid. This module does exports the filtered data. Then, convert CSV to Json. There are many CSV to Json conversion javasripts out there.
this.navResult.grid.exporter.toCSV(args).then(this.showResult, this.onError, null)
Based on AirG answer I have designed the following solution. Take into account that there are two cases, with or without filter and that you must be aware of the order of rows if you have applied some sort. At least this works for me.
var store = new Store({
idProperty: "idPeople", data: [
{ idPeople: 1, name: 'John', score: 130, city: 'New York', birthday: '31/02/1980' },
{ idPeople: 2, name: 'Alice', score: 123, city: 'WÃĄshington', birthday: '07/12/1984' },
{ idPeople: 3, name: 'Lee', score: 149, city: 'Shanghai', birthday: '8/10/1986' },
...
]
});
gridx = new GridX({
id: 'mygridx',
cacheClass: Cache,
store: store,
...
modules: [
...
{
moduleClass: Dod,
defaultShow: false,
useAnimation: true,
showExpando: true,
detailProvider: gridXDetailProvider
},
...
],
...
}, 'gridNode');
function gridXDetailProvider (grid, rowId, detailNode, rendered) {
gridXGetDetailContent(grid, rowId, detailNode);
rendered.callback();
return rendered;
}
function gridXGetDetailContent(grid, rowId, detailNode) {
if (grid.model._exts.clientFilter._ids === undefined || grid.model._exts.clientFilter._ids === 0) {
// No filter, with or without sort
detailNode.innerHTML = 'Hello ' + grid.row(grid.model._cache._priority.indexOf(rowId)).item().name + " with id " +
grid.row(grid.model._cache._priority.indexOf(rowId)).item().idPeople;
} else {
// With filter, with or without sort
detailNode.innerHTML = 'Hello ' + grid.row(grid.model._exts.clientFilter._ids.indexOf(rowId)).item().name + " with id " +
grid.row(grid.model._exts.clientFilter._ids.indexOf(rowId)).item().idPeople;
}
}
Hope that helps,
Santiago Horcajo
function getFilteredData() {
var filteredIds = grid.model._exts.clientFilter._ids;
return grid.store.data.filter(function(item) {
return filteredIds.indexOf(item.id) > -1;
});
}
I am implementing server side paging & sorting for jqGrid in MVC 4. I am passing view model object as postData to jqGrid url action method. have a look at grid definition.
var isGridDefined = false;
$(document).ready(function () {
function DefineGrid(Year, Month) {
var mygrid = $("#RptUpload");
mygrid.jqGrid({
loadonce: false,
async: false,
datatype: 'json',
postData: { bReload: true, Year: Year, Month: Month },
url: '#Url.Action("DMEUploadDetailsList", "Reports")',
jsonReader: { repeatitems: false, root: "DataRows" },
colNames: ['#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_OrderID',
'#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_CompanyName',
'#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_PatientID',
'#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_PatientName',
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_DOB",
'#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_Insurance',
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_UploadDate"
],
colModel: [
{ name: 'ReadingID', index: 'ReadingID', width: 55, fixed: true, sorttype: 'integer', align: 'center' },
{
name: 'CompanyName', index: 'CompanyName', align: 'center', width: 200,
cellattr: function (rowId, tv, rawObject, cm, rdata) { return 'style="white-space: normal!important;' },
},
{ name: 'PatientID', index: 'PatientID', width: 55, fixed: true, sorttype: 'integer', align: 'center' },
{
name: 'PatientName', index: 'PatientName', align: 'center', width: 200,
cellattr: function (rowId, tv, rawObject, cm, rdata) { return 'style="white-space: normal!important;' },
},
{
name: 'DOB', index: 'DOB', width: 80, fixed: true, sorttype: 'date', formatter: 'date', formatoptions: { srcformat: 'm/d/Y', newformat: 'm/d/Y' },
align: 'center'
},
{ name: 'InsuranceType', index: 'InsuranceType', align: 'center', width: 150, cellattr: function (rowId, tv, rawObject, cm, rdata) { return 'style="white-space: normal!important;' }, },
{
name: 'UploadDate', index: 'UploadDate', width: 80, fixed: true, sorttype: 'date', formatter: 'date', formatoptions: { srcformat: 'm/d/Y', newformat: 'm/d/Y' },
align: 'center'
}
],
rowNum: 20,
rowList: [20, 50, 100, 200],
pager: '#UploadPager',
caption: '#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_Title',
viewrecords: true,
height: 'auto',
width: 770,
hidegrid: false,
shrinkToFit: true,
scrollOffset: 0,
headertitles: true,
loadError: function (xhr, status, error) {
alert(status + " " + error);
},
//onPaging: function (pgButton) {
// $("#RptUpload").jqGrid("setGridParam", { postData: { bReload: false } });
//},
loadCompete: function () {
$("#RptUpload").jqGrid("setGridParam", { datatype: 'json', postData: { bReload: false } });
}
});
mygrid.navGrid('#UploadPager', { edit: false, add: false, del: false, search: false, refresh: false });
isGridDefined = true;
}
$("#rptRefresh").click(function (e) {
e.preventDefault();
var Form = $("form[id='FrmDMEUploadDetails']");
Form.validate();
if (Form.valid()) {
RemoveValidatioMessages();
$("#gridContainer").show();
var Year = $("#Year").val();
var Month = $("#Month").val();
if (!isGridDefined)
DefineGrid(Year, Month);
else
$("#RptUpload").jqGrid("setGridParam", { datatype: "json", page: 1, postData: { bReload: true, Year: Year, Month: Month } }).trigger("reloadGrid");
}
else {
$("#RptUpload").clearGridData();
$("#gridContainer").hide();
}
$(".chzn-select-deselect").trigger("liszt:updated");
return false;
});
});
& my action method is as follows
public ActionResult DMEUploadDetailsList(bool bReload, string Year, string Month, string nd, int rows, int page, string sidx, string sord, string filters)
{
DataSet SearchResult = null;
List<ReportData> ResultRows = new List<ReportData>();
JQGridResult Result = new JQGridResult();
if (bReload)
{
SearchResult = DB.ExecuteDataset("ConnectionString", "pc_GetUploadDetail",
new SqlParameter("#Year", Year),
new SqlParameter("#Month", Month));
Common.SetSession(SearchResult, null, "DMEUploadByMonth");
}
else
SearchResult = SessionManager.GetSession().GetAttribute("DMEUploadByMonth") as DataSet;
if (SearchResult != null)
{
DataTable dtSearchResult = SearchResult.Tables[0];
# region Handle server side Filtering, sorting and paging
int totalRecords = dtSearchResult.Rows.Count; //before paging
int totalPages = (int)Math.Ceiling((decimal)totalRecords / (decimal)rows); //--- number of pages
int startIndex = ((page > 0 ? page - 1 : 0) * rows);
if (sidx != "")
{
dtSearchResult.DefaultView.Sort = sidx + " " + sord;
dtSearchResult = dtSearchResult.DefaultView.ToTable();
}
# endregion
for (int i = startIndex; i < dtSearchResult.Rows.Count; i++)
{
ResultRows.Add(new ReportData()
{
ReadingID = Convert.ToInt32(dtSearchResult.Rows[i][0]),
CompanyName = Convert.ToString(dtSearchResult.Rows[i][1]),
PatientID = Convert.ToInt32(dtSearchResult.Rows[i][2]),
PatientName = Convert.ToString(dtSearchResult.Rows[i][3]),
DOB = (dtSearchResult.Rows[i][4] != DBNull.Value ? Convert.ToDateTime(dtSearchResult.Rows[i][4]) : (DateTime?)null),
InsuranceType = Convert.ToString(dtSearchResult.Rows[i][5]),
UploadDate = (dtSearchResult.Rows[i][6] != DBNull.Value ? Convert.ToDateTime(dtSearchResult.Rows[i][6]) : (DateTime?)null)
});
if (ResultRows.Count == rows) break;
}
Result.DataRows = ResultRows;
Result.page = page;
Result.total = totalPages;
Result.records = totalRecords;
}
return Json(Result, JsonRequestBehavior.AllowGet);
}
The problem with current implementation is that my action method DMEUploadDetailsList is not getting called though view model object is getting passed to request successfuly.
& This implementation were working fine when used client side paging & sorting.
Please suggest me If I am missing anything or correct my mistakes to get server side paging & sorting working.
This grid is defined or reloaded on refresh button. Now what I want is to identify whether action method is called on refresh button click or paging & sorting operation?
[ Now I would like to describe the last two sentence of problem statement. It specifies that when my page is loaded grid is not defined. As soon as I select filter & clicks refresh button my grid is defined for first time & reloaded for subsequent clicks of refresh. If you go through the action method code you will see that i am trying to use bReload bit variable for, when it is true [in case of refresh button click] I would like to query data from SQL otherwise from dataset stored in session [in case of paging or sorting request]. Now If you looked at the postData parameter in definition or in reload call I am passing breload as true. Where as I am not aware of how can I override this parameter to false when user request for sorting & paging. Or else if there is any another simple way with which in action method I can get whether this request is of load data or paging & sorting.]
Sorry, but I don't see any implementation of paging in your code. You calculate the number of records which need be skipped and save it in startIndex, but you don't use startIndex later. Your current code just get data from DataTable and returns all items of the table. You need to skip startIndex items. For example you can start for loop from i = startIndex instead of i = 0.
In general it would be more effective to construct SELECT statement in SqlCommand which uses TOP construct or use STORED PROCEDURE like described in the answer (see another answer too). In the way your server code will get from the SQL server only one page of data instead of fetching all records of data and returning only one page.
UPDATED: I would rewrite your client code to something like the following
$(document).ready(function () {
var templateDate = {
width: 80,
fixed: true,
sorttype: "date",
formatter: "date",
formatoptions: { srcformat: "m/d/Y", newformat: "m/d/Y" }
},
templateInt = { width: 55, fixed: true, sorttype: "integer" },
templateText = {
width: 200,
cellattr: function () {
return 'style="white-space: normal!important;'
}
},
mygrid = $("#RptUpload");
// create the grid without filling it (datatype: "local")
mygrid.jqGrid({
datatype: "local", // to revent initial loading of the grid
postData: {
bReload: true,
Year: function () { return $("#Year").val(); },
Month: function () { return $("#Month").val(); }
},
url: '#Url.Action("DMEUploadDetailsList", "Reports")',
jsonReader: { repeatitems: false, root: "DataRows" },
colNames: [ "#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_OrderID",
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_CompanyName",
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_PatientID",
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_PatientName",
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_DOB",
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_Insurance",
"#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_UploadDate"
],
colModel: [
{ name: "ReadingID", template: templateInt },
{ name: "CompanyName", template: templateText },
{ name: "PatientID", template: templateInt },
{ name: "PatientName", template: templateText },
{ name: "DOB", template: templateDate },
{ name: "InsuranceType", width: 150, template: templateText },
{ name: "UploadDate", template: templateDate }
],
cmTemplate: { align: "center" },
rowNum: 20,
rowList: [20, 50, 100, 200],
pager: "#UploadPager",
caption: "#VirtuOxAdmin.DMEUploadDetails_Grid_RptUpload_Title",
viewrecords: true,
height: "auto",
width: 770,
hidegrid: false,
headertitles: true,
loadError: function (xhr, status, error) {
alert(status + " " + error);
}
});
mygrid.navGrid("#UploadPager",
{ edit: false, add: false, del: false, search: false, refresh: false });
mygrid.closest(".ui-jqgrid").hide(); // hide the grid
$("#rptRefresh").click(function (e) {
var Form = $("form[id=FrmDMEUploadDetails]");
e.preventDefault();
Form.validate();
if (Form.valid()) {
RemoveValidatioMessages();
mygrid.jqGrid("setGridParam", { datatype: "json" })
.trigger("reloadGrid", [{page: 1}])
.closest(".ui-jqgrid").show(); // show the grid;
} else {
mygrid.clearGridData();
mygrid.closest(".ui-jqgrid").hide(); // hide the grid
}
$(".chzn-select-deselect").trigger("liszt:updated");
return false;
});
});
The grid will be created with datatype: "local", so the url and postData will be ignored. After that it seems to me the usage of bReload property in postData and on the server side seems me unneeded. Nevertheless I included bReload still in the JavaScript code till you remove it from the server code.
Additionally I simplified the colModel by usage of column templates (cmTemplate option of jqGrid and template property of colModel). See the old answer for more information. I removed also some unneeded options of jqGrid which values are default (see "Default" column in the documentation of options).
About usage of new versions of STORED PROCEDURE (pc_GetUploadDetail in your code) you can consider to introduction new version (like pc_GetUploadDetailPaged) which supports more parameters. It will not break existing code which uses the old procedure, but you can still use sorting and paging of data on SQL Server instead of getting all query results to web server and implementing sorting and paging in C#.
I solved my initial problem of jqGrid url not getting called by removing Form.serialize() as postData parameter in jqGrid definition & reload calles. This problem was not related to server side sorting & paging. This was caused due to my previous postData parameter definition as Form.serialize(). Instead I used pass individual parameters to the postData array.
My next problem was related to sorting & paging at server side. In which I want to fetch data from session dataset when user page through the grid or want to sort the grid data; otherwise reload new data by querying SQL server.
According to Oleg answer I must have adopted the simplified way of doing paging & sorting at SQL end instead of in c#. But I was not allowed to add new version of stored procedure as per Oleg suggestion. So I stick to use extra parameter in postData array named operCode like this in grid definition.
postData: {
operCode: "Reload",
Year: function () { return $("#Year").val(); },
InsuranceID: function () { return $("#InsuranceType").val(); },
CustomerID: function () { return $("#CompanyName").val(); }
},
Now I added onPaging & onSortCol event to override operCode postData parameter value like this
onPaging: function (pgButton) {
mygrid.jqGrid("setGridParam", { datatype: 'json', postData: { operCode: "Paging" } });
},
onSortCol: function (index, iCol, sortorder) {
mygrid.jqGrid("setGridParam", { datatype: 'json', postData: { operCode: "Sorting" } });
}
Now whenever user clicks refresh button operCode is sent as Reload, on paging as "Paging" & on sorting as "Sorting"
My server side action method code is as follows
public ActionResult DMEUploadDetails(string operCode, string Year, string Month, string nd, int rows, int page, string sidx, string sord, string filters)
{
DataSet SearchResult = null;
List<ReportData> ResultRows = new List<ReportData>();
JQGridResult Result = new JQGridResult();
if (operCode == "Reload")
{
SearchResult = DB.ExecuteDataset("ConnectionString", "pc_GetUploadDetail",
new SqlParameter("#Year", Year),
new SqlParameter("#Month", Month));
Common.SetSession(SearchResult, null, "POXMonthlyUploads");
}
else
SearchResult = (SessionManager.GetSession().GetAttribute("POXMonthlyUploads") as System.Web.UI.WebControls.GridView).DataSource as DataSet;
if (SearchResult != null)
{
DataTable dtSearchResult = SearchResult.Tables[0];
# region Handle server side Filtering, sorting and paging
int totalRecords = dtSearchResult.Rows.Count; //before paging
int totalPages = (int)Math.Ceiling((decimal)totalRecords / (decimal)rows); //--- number of pages
int startIndex = ((page > 0 ? page - 1 : 0) * rows);
if (sidx != "" && operCode == "Sorting")
{
dtSearchResult.DefaultView.Sort = sidx + " " + sord;
dtSearchResult = dtSearchResult.DefaultView.ToTable();
SearchResult.Tables.RemoveAt(0);
SearchResult.Tables.Add(dtSearchResult);
Common.SetSession(SearchResult, null, "POXMonthlyUploads");
}
# endregion
for (int i = startIndex; i < dtSearchResult.Rows.Count; i++)
{
ResultRows.Add(new ReportData()
{
//code to fill data to structure object
});
if (ResultRows.Count == rows) break;
}
Result.DataRows = ResultRows;
Result.page = page;
Result.total = totalPages;
Result.records = totalRecords;
}
return Json(Result, JsonRequestBehavior.AllowGet);
}
Very much Thanks to Oleg for giving me some extra knowledge about jqGrid & giving me good idea about server side paging & sorting.
I created a View extend Ext.grid.Panel and also attach a tbar to it, in the toolbar I got 2 buttons [Add] and [Remove] in this question I am focus on the [Remove] command only.
As usual I want to get hold to current selected record in the grid which I want to delete.
so in the controller:
init: function() {
this.control({
'extendgridlist button[action=remove]': {
click: this.removeCurrentRow;
}
});
}
removeCurrentRow: function(t){
// how do i get current selected record
}
removeCurrentRow: function(t){
var grid = t.up('gridpanel');
var arraySelected =grid.getSelectionModel().getSelection();
//assuming you have a single select, you have the record at index 0;
var record = arraySelected[0]
}
The answer by 'nscrob' should work just fine, I just wanted to point out an alternate method. Every Ext component can have an 'id' field. So, if you gave your grid a config option like the following when it was created:
id:'my_grid_id'
Then, from anywhere including inside your removeCurrentRow function, you could do the following:
var grid = Ext.getCmp('my_grid_id');
var rows = grid.getSelectionModel().getSelection();
if(!rows.length)
{ //in case this fires with no selection
alert("No Rows Selected!");
return;
}
var row = rows[0];
As I said, similar to other answers, but just another way of accessing the grid.
In case grid is to selType = "cellModel" use code below:
var grid = Ext.getCmp('id-of-grid');
var recid = grid.getSelectionModel().getCurrentPosition();
if(recid && recid.row){
var r = grid.getStore().getAt(recid.row)
alert(r.data.anyofgridfieldid)
}
more details: http://as400samplecode.blogspot.com/2012/01/extjs-grid-selected-row-cell.html
...
xtype: 'button',
text: 'Edit',
handler: function() {
onEdit(this.up('theGrid')); // alias: 'widget.theGrid' in definition
}
...
function onEdit(theGrid) {
if (theGrid.getSelectionModel().hasSelection()) {
var rows = theGrid.getSelectionModel().getSelection();
var row = rows[0];
console.log('Count Rows Selected : ' + rows.length);
console.log('The Row : ' + row); // columns: 'id', 'name', 'age'
console.log('Student Id: ' + row.get('id'));
console.log('Student Name: ' + row.get('name'));
console.log('Student Age: ' + row.get('age'));
}
else {
console.log('No Row Selected.');
}
}