Handsontable makes it very easy to send table values from a server an array:
$('#dataTable').handsontable( data: serverdataarray )
So far, so good. However, I would like to format some of the columns in the array.
If I have a fixed number of columns I can easyly do this:
$('#dataTable').handsontable({
data: serverdataarray ,
columns: [
{ data: "Entity", type: 'text', renderer: orangeFF9900 },
{ data: "Geography", type: 'text', renderer: orangeFF9900 },
{ data: "Description", type: 'text', renderer: orangeFF9900 },
{ data: "cost_month1", type: 'numeric' },
{ data: "cost_month1", type: 'numeric' }
]
});
My problem is that the data sent from the server will have a varying number of columns depending on a number of factors. Thus, I would like to be able to generate the columns formating array dynamicaly on the server and send it as an array too. I.e.:
var cols = [
{ data: "Entity", type: 'text', renderer: orangeFF9900 },
{ data: "Geography", type: 'text', renderer: orangeFF9900 },
{ data: "Description", type: 'text', renderer: orangeFF9900 },
{ data: "cost_month1", type: 'numeric' },
{ data: "cost_month1", type: 'numeric' }
]; // Strictly speaking this would be a string sent form the server, but you catch my drift
$('#dataTable').handsontable({
data: serverdataarray ,
columns: cols
});
However, on doing so, I end up with the following error TypeError: method is not a function jquery.handsontable-0.9.9-full.js Line: 3028
The line in question (3028) is the return line of the following function:
Handsontable.TableView.prototype.applyCellTypeMethod = function (methodName, td, row, col) {
var prop = this.instance.colToProp(col)
, cellProperties = this.instance.getCellMeta(row, col)
, method = Handsontable.helper.getCellMethod(methodName, cellProperties[methodName]); //methodName is 'renderer' or 'editor'
return method(this.instance, td, row, col, prop, this.instance.getDataAtRowProp(row, prop), cellProperties);
};
Handsontable actualy manages to render correct number of columns on screen, although they are blank, unformatted and there is only one row so I'm gessing it is infering this much form the serverdataarray and not cols.
Any suggestions on how to achive what I am looking for?
I am open to changing the Handsontable sourcecode if need be.
Thanks
This answer is just intended as an expansion on #PostureOfLearning 's correct response:
It turns out the problem was caused by the following mistake and the fact that I simplified the code in the hope of making the post more readable:
var orangeFF9900= function (instance, td, row, col, prop, value, cellProperties) {
Handsontable.TextCell.renderer.apply(this, arguments);
$(td).css({
background: '#ff9900'
});
};
$.post('/AJAX/columns', function (data) {
var cellData = JSON.parse(data.Cells);
var colsData = JSON.parse(data.Cols);
$('#dataTable').handsontable({
data: cellData ,
columns: colsData
});
});
Now the colsData array looks like described above (or perhaps more precisely as):
[
{ "data": "Entity", "type": "text", "renderer": "orangeFF9900" },
{ "data": "Geography", "type": "text", "renderer": "orangeFF9900" },
{ "data": "Description", "type": "text", "renderer": "orangeFF9900" },
{ "data": "cost_month1", "type": "numeric" },
{ "data": "cost_month1", "type": "numeric" }
]
Now, because of the way text is transmitted in JSON via quote marks " ", orangeFF9900 is resolved as a string and not a function call.
Fortunately however, it appears we can teach HandOnTable to recognise a renderer function name passed as a string by using the following line:
Handsontable.cellLookup.renderer.orangeFF9900 = finction(…) {…};
Thus our final code can look like:
Handsontable.cellLookup.renderer.orangeFF9900 = function (instance, td, row, col, prop, value, cellProperties) {
Handsontable.TextCell.renderer.apply(this, arguments);
$(td).css({
background: '#ff9900'
});
};
$.post('/AJAX/columns', function (data) {
var cellData = JSON.parse(data.Cells);
var colsData = JSON.parse(data.Cols);
$('#dataTable').handsontable({
data: cellData ,
columns: colsData
});
});
Hope this helps someone in the future
Cheers
I don't see anything wrong with your approach.
In one of my projects, I'm successfully using:
var myCols = [...];
$('#dataTable').handsontable({
data: serverdataarray,
columns: myCols
});
In you sample code, the comment line "// Strictly speaking ...": At the beginning of the line you seem to have too many closing brackets. var cols = [...]}); should just be var cols = [...];
I'm assuming its a typo.
Except for that I suggest checking that the the columns data is set to exactly the same ID/name as the column has from the server and not i.e. what you want as a heading. Example:
var cols = [{ data: "RefNum" }, { data: "Qty"}];
Add headers using:
colHeaders: ["Reference", "Quantity"]
The last thing I can think of is that there is something wrong with the renderer. Try removing the renderer for each column and see if it works first. Its kind of hard to help without more code on this.
Related
I've created a kendo grid, and need to insert kendo drop down into one of the columns. I need to get the data for the drop down from another data source. It kind of works, however, the problem is when I have chosen a value from the drop down and the drop down closes, instead of displaying that value it goes into editable mode. Only when I click outside of the dropdown, it displays the correct value. Here is a gif of the issue:
https://media2.giphy.com/media/KyMGB7FmFQMVTChFA7/giphy.gif
How could this issue be solved?
I have successfully created a kendo grid with a drop down list already. The only difference seems to be that there only one data source is used, but here two are used. Here is some of the code for the drop down:
title: "Type",
field: "productType.name", //this property is from the data source used for grid
template: "<kendo-drop-down-list k-value=\"dataItem.productType.id\"
k-options=\"productTypeOptions\" ng-change=\"productTypeChanged(dataItem, 'productType')\"
ng-model=\"dataItem.productType.id\"></kendo-drop-down-list>"
}...];
$scope.productTypes = {
data: [{ name: "Value 1", id: "1" }, { name: "Value 2", id: "2" }]
}
$scope.productTypeDataSource = new kendo.data.DataSource({
schema: {
data: "data",
model: {
fields: {
id: { type: "number" },
name: { type: "string" }
}
}
},
data: $scope.productTypes,
serverPaging: true,
serverSorting: true,
serverFiltering: true
});
$scope.productTypeOptions = {
dataSource: $scope.productTypeDataSource,
dataTextField: "name",
dataValueField: "id"
};
$scope.productTChanged = function (dataItem, field, productArray, dataSource) {
var index = dataSource.indexOf(dataItem);
var c = productArray.data[index];
if (c == null) return;
c[field] = dataItem[field];
return c;
};
$scope.productTypeChanged = function (dataItem, field) {
$scope.productTChanged(dataItem, field, $scope.products, $scope.productDataSource);
};```
I have two DataTables on the same web page with the same number of columns that are sourced from DIFFERENT APIs. If I add the class "grid" to one or the other the table displays with the correct data for that table. However, if I add the class "grid" to both, the data for the first table shows up on BOTH tables.
The class "grid" is a very complex DataTable that involves quite a bit of configuration but here is how "grid" is initialized:
var t = $(".grid").DataTable({
iDisplayLength: 10,
columnDefs: [{
"searchable": false,
"orderable": bOrderBy,
"targets": 0
}],
order: [[0, orderDir]],
ajax: {
url: src,
dataSrc: ""
},
columns: [
{
data: f1
},
{
data: f2
},
{
data: f3
},
{
data: f4
},
{
data: f5,
. . . "blah, blah, blah"
});
t.on('post-body.bs.table', function () {
$('[data-toggle="tooltip"]').tooltip({
container: 'body',
placement: 'top'
});
});
if (autoNum == "Y") {
t.on('order.dt search.dt', function () {
t.column(0, { search: 'applied', order: 'applied' }).nodes().each(function (cell, i) {
cell.innerHTML = i + 1;
});
}).draw();
}
How do I fix this?
Right now, it is applying the same DataTable instance to anything selected in your .grid selector which is why they are coming back the same. If the table options are the same, you can save this into a obj and then pass it to each call. Name the 2 tables with different id's or different classes
var dtOptions = {
iDisplayLength: 10,
columnDefs: [{
"searchable": false,
"orderable": bOrderBy,
"targets": 0
}],
order: [[0, orderDir]],
ajax: {
url: src,
dataSrc: ""
},
columns: [
{
data: f1
},
{
data: f2
},
{
data: f3
},
{
data: f4
},
{
data: f5,
. . . "blah, blah, blah"
};
$("#mytable1).DataTable(dtOptions);
$("#mytable2).DataTable(dtOptions);
You may need to change the ajax src for the 2nd table as you said they are coming from separate api's. You could possibly copy the options object and modify the ajax src if needed.
var dtOptions2= $.extend(true, {}, dtOptions);
dtOptions2.ajax.url = "somthing-else...";
$("#mytable2).DataTable(dtOptions2);
I currently have a simple extJS Grid which is pulling data from a server and presenting it to the viewer. I would like to grab the value of the selected row, and then pass it to another PHP script for processing in order to display the results in another grid.
var roleInformationStore = Ext.create('Ext.data.Store', {
autoLoad: true,
autoSync: true,
model: 'RoleInformation',
proxy: {
type: 'ajax',
url: 'data.php',
reader: {
type: 'array',
},
writer: {
type: 'json'
}
}
});
var roleInformationGrid = Ext.create('Ext.grid.Panel', {
store: roleInformationStore,
width: '100%',
height: 200,
title: 'Roles',
columns: [
{
text: 'Name',
flex: 1,
width: 100,
sortable: false,
hideable: false,
dataIndex: 'role'
}
],
listeners: {
cellclick: function(view, td, cellIndex, record, tr, rowIndex, e, eOpts) {
roleInformationStore.proxy.extraParams = record.get('role');
//Ext.Msg.alert('Selected Record', 'Name: ' + record.get('role'));
}
}
});
Using the listener in the current grid, I am able to get the value and show it using the alert method. Any suggestions on how to accomplish this?
Thanks
For this to work, extraParams has to be an object of key-value string pairs, because an URI has to be something like data.php?key1=value1&key2=value2.
Style-wise, Sencha advises to use getters and setters, whenever possible.
Together, you get:
var store = Ext.getStore("roleInformationStore");
store.getProxy().setExtraParam("myRoleParamKey",record.get('role'));
store.load();
In PHP, you would get the parameter then using
$role = $_GET['myRoleParamKey'];
You can of course substitute myRoleParamKey for any alphanumeric literal you want, but make sure you use the same key on both server and client side. ;-)
Docs: setExtraParam
I have a kendo scheduler and I'm having a problem with move event. I can move only one event at a time and then I can't even grab any event afterwards. I think there's something wrong with the dates but I really can't figure out why. I tried dataSource with 2-3 events and it's working but when I put that exact same data in php and return it as json. It's not working.
Any help would be appreciated.
$("#scheduler").kendoScheduler({
date: new Date(),
startTime: new Date(today2()),
timezone: "Etc/UTC",
currentTimeMarker: false,
height: 800,
views:
[
"week",
{ type: "month", selected: true, eventHeight: 60}
],
dataSource:
{
transport:
{
read:
{
url: "tasks.php",
dataType: "json"
},
batch: true,
parameterMap: function (options, operation)
{
if (operation === "read") {
var scheduler = $("#scheduler").data("kendoScheduler");
var result =
{
start: scheduler.view().startDate(),
end: scheduler.view().endDate()
}
return kendo.stringify(result);
}
return kendo.stringify(options);
}
},
schema:
{
model:
{
id: "taskId",
fields:
{
taskId: { type: "number", from: "TT_CODE" },
start: { type: "date", from: "TT_START_DATETIME"},
end: { type: "date", from: "TT_END_DATETIME"},
title: { from: "TT_EDIT"}
}
}
}
}
});
php file with json data:
$json[0]['TT_CODE'] = 1;
$json[0]['TT_START_DATETIME'] = "2016-01-16 15:00:00";
$json[0]['TT_END_DATETIME']= "2016-01-16 16:00:00";
$json[0]['TT_EDIT'] = "Fast and furious 6";
echo json_encode($json);
Since you specified start and end as date in your model, the scheduler is expecting to received properly formatted date. While JSON passes date as string, javascript still expect the date string to be formatted.
In your case, it would be:
$json[0]['TT_CODE'] = 1;
$json[0]['TT_START_DATETIME'] = "2016-01-16T15:00:00.000Z";
$json[0]['TT_END_DATETIME']= "2016-01-16T16:00:00.000Z";
$json[0]['TT_EDIT'] = "Fast and furious 6";
You could also leave date as is and handle the string with a custom logic in the parameterMap function.
As a side note, if you have a doubt about the type formatting, go in the browser console and have a look at the network tab. You'll be able to compare the data sent by the working service to the data sent by PHP and see where is the difference.
I am using jquery's DataTables which is really working great. Then only problem I got is, that I am facing (in non-edit-view) the value of the select-field (which is an id). The user of course doesn't want to see the id of course.
Therefore I am looking for a possibility to configure that column in a way to show always the value of label property.
Here a some snippets:
$(document).ready(function() {
var table = $('#overviewTable').DataTable({
dom: "Tfrtip",
ajax: "/Conroller/GetTableData",
columns: [
{ data: "Id", className: "readOnly", visible: false },
{
data: "LoanTransactionId",
className: "readOnly readData clickable",
"fnCreatedCell": function(nTd, sData, oData, iRow, iCol) {
$(nTd).html("<a href='#'>" + oData.LoanTransactionId + "</a>");
}
},
{ data: "Id", className: "readOnly" },
{ data: "property_1", className: "readOnly" },
{ data: "Priority" },
{ data: null, className: "action readOnly", defaultContent: 'Info' }
],
order: [1, 'asc'],
tableTools: {
sRowSelect: "os",
sRowSelector: 'td:first-child',
aButtons: []
}
});
// data reload every 30 seconds
setInterval(function() {
table.ajax.reload();
}, 30000);
editor = new $.fn.dataTable.Editor({
ajax: "PostTable",
table: "#overviewTable",
fields: [
{
label: "Id",
name: "Id"
},
{
label: "Column 1",
name: "property_1"
},
{
label: "Priority",
name: "Priority",
type: "select",
options: [
{ label: "low", value: 0 },
{ label: "mid", id: 1 },
{ text: "high", id: 2 }
]
}
]
});
// Inline Edit - only those who are not readOnly
$('#overviewTable').on('click', 'tbody td:not(:first-child .readOnly)', function(e) {
editor.inline(this, {
submitOnBlur: true
});
});
How it looks in the display mode
How it looks in the edit mode
See the documentation on columns.render
You want to modify your column options for priority
Preferred Option: Your data source has a field with the priority as a string
This is the best option, as you don't want to have two places with this business logic. Keep it out of the client code.
Also, you will want to modify the editor as well so that the options used have been retrieved dynamically from the server to keep this business logic out of the client too. This is left as an exercise for the reader.
Since you don't provide details on what your data structure looks lik, I'm assuming it is an object, and it has an attribute priorityAsString so use the string option type for render.
columns: [
...
{
data: "Priority" ,
render: "priorityAsString",
},
Option 2) You write a function to map priority to string
Do this if you can't get the data from the server. But remember you will need to update many places when the priority list changes.
columns: [
...
{
data: "Priority" ,
render: renderPriorityAsString,
},
...
function renderPriorityAsString(priority) {
const priorityToString = {
0: 'low',
1: 'med',
2: 'high',
};
return priorityToString[priority] || `${priority} does not have a lookup value`;
}
"render": function ( data, type, full ) { return label;}