jQWidgets Forums
jQuery UI Widgets › Forums › Grid › Inline editing and knockout
Tagged: inline edit knockout
This topic contains 16 replies, has 3 voices, and was last updated by Peter Stoev 12 years, 11 months ago.
-
Author
-
Hi!
I’m struggling with jqxGrid inline editing with knockout for a couple of days now.
Data in jqxGrid is displayed ok but when I double click on the cell and change the value knockout does not update value in a separate html table (jsFiddle – in this fiddle there is only html table for input and output – I don’t know how to add jqxGrid to jsfiddle, so imagine that I’m using jqxGrid for the input :)).
Is inline editing with knockout supported? If it is, can you please provide me with the sample (it would be great if it’s based on Example – Cell Editing
Thank you for your help.
Hi jqWizard,
Could you please provide the code which you use to bind the jqxGrid?
Looking forward to your reply.
Best Regards,
Peter StoevjQWidgets team
http://www.jqwidgets.comI forgot to mention, I’m using:
– jQuery 1.7.2
– jqWidgets 2.0
– Knockout 2.1.0
– Knockout mapping plugin 2.1.2
– Chrome v19
***************************************
* JSON data I receive from the server *
***************************************{
"objectA": {
"date": "08.04.2009",
"year": 2008,
"code": 0,
"name": "John",
"surname": "Doe",
"note": null
},
"arrayA": [{
"dateFrom": "07.03.2008",
"dateTo": "07.06.2008",
"duration": null,
"text": null,
"code": 633,
"currency": 70.5
}],
"arrayB": [{
"number1": 56,
"numberText1": null,
"number2": 2006,
"numberText2": null
}],
"arrayC": [{
"dateFrom": "07.01.2008",
"dateTo": "07.03.2008",
"duration": 361,
"text": null,
"code": 233,
"currency": 3670.5
}],
"arrayD": [],
"arrayE": [],
"arrayF": [],
"myCode": null
}*******
* jsp *
*******<div id="gridTest"></div>
<table>
<thead>
<tr>
<th>Date from</th>
<th>Date to</th>
</tr>
</thead>
<tbody data-bind="foreach: myData.arrayA">
<tr>
<td><span data-bind="text: dateFrom"></span></td> <!-- knockout not updating when I change the value in jqxGrid -->
<td><span data-bind="text: dateTo"></span></td> <!-- knockout not updating when I change the value in jqxGrid -->
</tr>
</tbody>
</table>**************
* javascript *
**************
// on ready
jQuery(document).ready(function() {
try {
var self = this,
request = null;// initial data load
request = jQuery.ajax({
url : URL + '/dataFromServer/' + id,
headers : {
guid: GUID
},
async : false,
success : function(data) {
self.data = data; // JSON is defined at the top of the reply
},
error: function (xhr, textStatus, errorThrown) {
showMessage(errorThrown);
}
});request.done(function() {
// initialize
self.model = new GridViewModel(self.data);// load
self.model.displayGridData();ko.applyBindings(self.model);
});request.fail(function() {
// initialize
self.model = new GridViewModel(self.data);ko.applyBindings(self.model);
});
} catch (e) {
alert('Error[ready, ' + e.name + ']: ' + e.message);
}
});// viewModel
var GridViewModel = function(data) {
var self = this,
source = {},
dataAdapter = null;if (data) {
self.myData = ko.mapping.fromJS(data); // 1) if I only use this then jqxGrid displays "function c() ..." instead of data// 2) if I unmap arrays and redefined them as observableArray then jqxGrid displays data ok - is there any better way for mapping?
self.myData.arrayA = ko.observableArray(ko.mapping.toJS(data.arrayA));
self.myData.arrayB = ko.observableArray(ko.mapping.toJS(data.arrayB));
self.myData.arrayC = ko.observableArray(ko.mapping.toJS(data.arrayC));
self.myData.arrayD = ko.observableArray(ko.mapping.toJS(data.arrayD));
self.myData.arrayE = ko.observableArray(ko.mapping.toJS(data.arrayE));
self.myData.arrayF = ko.observableArray(ko.mapping.toJS(data.arrayF));
}this.loadData = function(theme) {
source = {
localdata: self.myData.arrayA,
datatype: 'local'
};
dataAdapter = new jQuery.jqx.dataAdapter(source);// grid
jQuery('#gridTest').jqxGrid({
width : 885,
source : dataAdapter,
pageable : true,
autoheight : true,
editable : true,
selectionmode : 'singlecell',
pagesize : 5,
pagesizeoptions : ['5', '10'],
columns: [{
text : 'Date from',
datafield : 'dateFrom',
width : 110,
columntype : 'datetimeinput',
cellsformat : 'dd.MM.yyyy',
initeditor : function (row, cellvalue, editor) {
editor.jqxDateTimeInput({
culture : 'sl-SI',
showDelay : 0,
hideDelay : 0
});
}
}, {
text : 'Date to',
datafield : 'dateTo',
width : 110,
columntype : 'datetimeinput'
}, {
text : 'Duration',
datafield : 'duration',
width : 120
}, {
text : 'Some text',
datafield : 'text',
width : 140
}, {
text : 'Code',
datafield : 'code',
width : 90,
cellsalign : 'right'
}, {
text : 'Currency',
datafield : 'currency',
width : 170,
cellsalign : 'right'
}]
});
};
}Hi jqWizard,
When a cell is edited, the updaterow callback is called. You can update your model inside the function’s body.
For example:
source = { localdata: self.myData.arrayA, datatype: 'local', updaterow: function(row, rowdata) { var observableArray = self.myData.arrayA; observableArray.replace(observableArray()[row], rowdata); }};
The Grid responds to changes in the Model, but it will not update it when the user changes the value of a cell. In addition, the current version of jQWidgets is 2.2. I suggest you to download it and upgrade the Grid in your project.
Best Regards,
Peter StoevjQWidgets Team
http://www.jqwidgets.comI’m using jqWidgets v2.1 and not v2.0.
With your code html table is not updated and if I change value for column “Some text” into “test”, the value in a cell becomes an array of characters (text: [0: “t”, 1: “e”, 2: “s”, 3: “t”]) instead of string (text: “test”).
Then I tried with mapping for rowdata and changes are visible in the html table but inside the jqxGrid I see only text “function c(){if(0” and not the actual values like date, “test”, etc.
updaterow: function(row, rowdata) {
var observableArray = self.myData.arrayA;
observableArray.replace(observableArray()[row], ko.mapping.fromJS(rowdata));
}
Is this a problem with the v2.1 or is it something else?
Here’s a modification of your code which works fine on my side with jQWidgets 2.2. I haven’t tested with previous versions.
<!DOCTYPE html><html lang="en"><head> <link rel="stylesheet" href="../../jqwidgets/styles/jqx.base.css" type="text/css" /> <script type="text/javascript" src="../../scripts/jquery-1.7.2.min.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxcore.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxdata.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxbuttons.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxscrollbar.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxmenu.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxgrid.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxgrid.edit.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxgrid.selection.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxlistbox.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxdropdownlist.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxcheckbox.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxcalendar.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxnumberinput.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxdatetimeinput.js"></script> <script type="text/javascript" src="../../jqwidgets/globalization/jquery.global.js"></script> <script type="text/javascript" src="../../scripts/gettheme.js"></script> <script type="text/javascript" src="../../scripts/knockout-2.1.0.js"></script> <script type="text/javascript" src="../../scripts/knockout-mapping-2.0.0.js"></script> <script type="text/javascript" src="generatedata.js"></script> <script type="text/javascript"> $(document).ready(function () { var theme = getTheme(); var data = { "objectA": { "date": "08.04.2009", "year": 2008, "code": 0, "name": "John", "surname": "Doe", "note": null }, "arrayA": [{ "dateFrom": "07.03.2008", "dateTo": "07.06.2008", "duration": null, "text": "abc", "code": 633, "currency": 70.5 }], "arrayB": [{ "number1": 56, "numberText1": null, "number2": 2006, "numberText2": null }], "arrayC": [{ "dateFrom": "07.01.2008", "dateTo": "07.03.2008", "duration": 361, "text": null, "code": 233, "currency": 3670.5 }], "arrayD": [], "arrayE": [], "arrayF": [], "myCode": null }; var self = this; self.data = data; // viewModel var GridViewModel = function (data) { var self = this, source = {}, dataAdapter = null; if (data) { self.myData = ko.mapping.fromJS(data); // 1) if I only use this then jqxGrid displays "function c() ..." instead of data // 2) if I unmap arrays and redefined them as observableArray then jqxGrid displays data ok - is there any better way for mapping? self.myData.arrayA = ko.observableArray(ko.mapping.toJS(data.arrayA)); self.myData.arrayB = ko.observableArray(ko.mapping.toJS(data.arrayB)); self.myData.arrayC = ko.observableArray(ko.mapping.toJS(data.arrayC)); self.myData.arrayD = ko.observableArray(ko.mapping.toJS(data.arrayD)); self.myData.arrayE = ko.observableArray(ko.mapping.toJS(data.arrayE)); self.myData.arrayF = ko.observableArray(ko.mapping.toJS(data.arrayF)); } this.loadData = function (theme) { source = { localdata: self.myData.arrayA, datatype: 'local', updaterow: function(row, rowdata) { var observableArray = self.myData.arrayA; observableArray.replace(observableArray()[row], rowdata); } }; dataAdapter = new jQuery.jqx.dataAdapter(source); // grid $('#jqxgrid').jqxGrid({ width: 885, source: dataAdapter, pageable: true, autoheight: true, editable: true, selectionmode: 'singlecell', pagesize: 5, pagesizeoptions: ['5', '10'], columns: [{ text: 'Date from', datafield: 'dateFrom', width: 110, columntype: 'datetimeinput', cellsformat: 'dd.MM.yyyy', initeditor: function (row, cellvalue, editor) { } }, { text: 'Date to', datafield: 'dateTo', width: 110, columntype: 'datetimeinput' }, { text: 'Duration', datafield: 'duration', width: 120 }, { text: 'Some text', datafield: 'text', width: 140 }, { text: 'Code', datafield: 'code', width: 90, cellsalign: 'right' }, { text: 'Currency', datafield: 'currency', width: 170, cellsalign: 'right' }] }); }; } self.model = new GridViewModel(self.data); self.model.loadData(); ko.applyBindings(self.model); }); </script></head><body class='default'> <div id='jqxWidget'> <div id="jqxgrid"> </div> </div> <table> <thead> <tr> <th> Date from </th> <th> Date to </th> </tr> </thead> <tbody data-bind="foreach: myData.arrayA"> <tr> <td> <span data-bind="text: dateFrom"></span> </td> <!-- knockout not updating when I change the value in jqxGrid --> <td> <span data-bind="text: dateTo"></span> </td> <td> <span data-bind="text: text"></span> </td> <!-- knockout not updating when I change the value in jqxGrid --> </tr> </tbody> </table></body></html>
Regards,
Peter StoevjQWidgets Team
http://www.jqwidgets.comHi!
I’m using this code that you posted here and jqWidgets v2.2.
When I double click on the cell and change the value knockout updates value. That’s OK.
But when I would like to update value on cell with code it doesn’t work. Code below works only for the first time before I manually edit cell on grid.My code:
this.updateRow = function() {
self.myData.arrayA()[0].Code(3);
}
Thank you for your help.
To update a value with code, get a record from the observable array, update it, and replace it. :
For example:
var item = self.model.myData.arrayA()[0]; item.text = "My New Text"; self.model.myData.arrayA.replace(self.model.myData.arrayA()[0], item);
Here’s the full source code:
<!DOCTYPE html><html lang="en"><head> <link rel="stylesheet" href="../../jqwidgets/styles/jqx.base.css" type="text/css" /> <script type="text/javascript" src="../../scripts/jquery-1.7.2.min.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxcore.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxdata.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxbuttons.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxscrollbar.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxmenu.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxgrid.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxgrid.edit.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxgrid.selection.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxlistbox.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxdropdownlist.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxcheckbox.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxcalendar.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxnumberinput.js"></script> <script type="text/javascript" src="../../jqwidgets/jqxdatetimeinput.js"></script> <script type="text/javascript" src="../../jqwidgets/globalization/jquery.global.js"></script> <script type="text/javascript" src="../../scripts/gettheme.js"></script> <script type="text/javascript" src="../../scripts/knockout-2.1.0.js"></script> <script type="text/javascript" src="../../scripts/knockout-mapping-2.0.0.js"></script> <script type="text/javascript" src="generatedata.js"></script> <script type="text/javascript"> $(document).ready(function () { var theme = getTheme(); var data = { "objectA": { "date": "08.04.2009", "year": 2008, "code": 0, "name": "John", "surname": "Doe", "note": null }, "arrayA": [{ "dateFrom": "07.03.2008", "dateTo": "07.06.2008", "duration": null, "text": "abc", "code": 633, "currency": 70.5 }], "arrayB": [{ "number1": 56, "numberText1": null, "number2": 2006, "numberText2": null }], "arrayC": [{ "dateFrom": "07.01.2008", "dateTo": "07.03.2008", "duration": 361, "text": null, "code": 233, "currency": 3670.5 }], "arrayD": [], "arrayE": [], "arrayF": [], "myCode": null }; var self = this; self.data = data; // viewModel var GridViewModel = function (data) { var self = this, source = {}, dataAdapter = null; if (data) { self.myData = ko.mapping.fromJS(data); // 1) if I only use this then jqxGrid displays "function c() ..." instead of data // 2) if I unmap arrays and redefined them as observableArray then jqxGrid displays data ok - is there any better way for mapping? self.myData.arrayA = ko.observableArray(ko.mapping.toJS(data.arrayA)); self.myData.arrayB = ko.observableArray(ko.mapping.toJS(data.arrayB)); self.myData.arrayC = ko.observableArray(ko.mapping.toJS(data.arrayC)); self.myData.arrayD = ko.observableArray(ko.mapping.toJS(data.arrayD)); self.myData.arrayE = ko.observableArray(ko.mapping.toJS(data.arrayE)); self.myData.arrayF = ko.observableArray(ko.mapping.toJS(data.arrayF)); } this.loadData = function (theme) { source = { localdata: self.myData.arrayA, datatype: 'local', updaterow: function (row, rowdata) { var observableArray = self.myData.arrayA; observableArray.replace(observableArray()[row], rowdata); } }; dataAdapter = new jQuery.jqx.dataAdapter(source); // grid $('#jqxgrid').jqxGrid({ width: 885, source: dataAdapter, pageable: true, autoheight: true, editable: true, selectionmode: 'singlecell', pagesize: 5, pagesizeoptions: ['5', '10'], columns: [{ text: 'Date from', datafield: 'dateFrom', width: 110, columntype: 'datetimeinput', cellsformat: 'dd.MM.yyyy', initeditor: function (row, cellvalue, editor) { } }, { text: 'Date to', datafield: 'dateTo', width: 110, columntype: 'datetimeinput' }, { text: 'Duration', datafield: 'duration', width: 120 }, { text: 'Some text', datafield: 'text', width: 140 }, { text: 'Code', datafield: 'code', width: 90, cellsalign: 'right' }, { text: 'Currency', datafield: 'currency', width: 170, cellsalign: 'right' }] }); }; } self.model = new GridViewModel(self.data); self.model.loadData(); ko.applyBindings(self.model); var item = self.model.myData.arrayA()[0]; item.text = "My New Text"; self.model.myData.arrayA.replace(self.model.myData.arrayA()[0], item); }); </script></head><body class='default'> <div id='jqxWidget'> <div id="jqxgrid"> </div> </div> <table> <thead> <tr> <th> Date from </th> <th> Date to </th> </tr> </thead> <tbody data-bind="foreach: myData.arrayA"> <tr> <td> <span data-bind="text: dateFrom"></span> </td> <!-- knockout not updating when I change the value in jqxGrid --> <td> <span data-bind="text: dateTo"></span> </td> <td> <span data-bind="text: text"></span> </td> <!-- knockout not updating when I change the value in jqxGrid --> </tr> </tbody> </table></body></html>
Best Regards,
Peter StoevjQWidgets Team
http://www.jqwidgets.comHi!
I tried to use your code to update a value with code. If I use sample posted here it works. But if I use this code in fuction addRow, does not work. It updates value in jqxGrid but not in knockout separate HTML table. Did I miss something?
My code:
this.loadData = function (theme) {
source = {
localdata: self.myData.arrayA,
datatype: 'local',
addrow: function (row, rowdata) {
var observableArray = self.myData.arrayA;
observableArray.push( {dateFrom: null, dateTo:null, duration:null, text: null, code:null, currency:null} );
}
updaterow: function (row, rowdata) {
var observableArray = self.myData.arrayA;
observableArray.replace(observableArray()[row], rowdata);
}
};
dataAdapter = new jQuery.jqx.dataAdapter(source);// grid
$('#jqxgrid').jqxGrid({
width: 885,.......
............
............
});this.addRow = function() {
var datarow = {},
paginginformation = null,
pagescount = -1,
item = self.model.myData.arrayA()[0];
item.text = "My New Text";
self.model.myData.arrayA.replace(self.model.myData.arrayA()[0], item);
$('#jqxgrid').jqxGrid('addrow', null, datarow);
paginginformation = $('#jqxgrid').jqxGrid('getpaginginformation');
pagescount = paginginformation.pagescount;
$('#jqxgrid').jqxGrid('gotopage', pagescount);
};Thank you for your help.
Hi damc,
You can take a look at this sample for adding/removing rows in jqxGrid with Knockout: knockoutjs.htm
Best Regards,
Peter StoevjQWidgets Team
http://www.jqwidgets.comHi Peter,
I need your help. I have two questions.
1. I use your code from post to update row, when a cell is edited in jqxGrid. My complete code is the same like yours (code you posted on June 3, 2012 at 2:56 pm #4552). I have a problem, when I manually edit the data in cell and update it, all the data properties becomes not observable (ko.isObservable(self.myData.arrayA()[0].Code)) returns false). If data in grid cells are not modified, properties are observable (ko.isObservable(self.myData.arrayA()[0].Code)) returns true).
2. I have save function where I post data to the server. Function save returns new data. Problem is that jqxGrid is not responding to changes in model (new data).
My code:
this.save = function() {
jQuery.ajax({
url : URL + '/myData,
type : 'POST',
async : false,
data : JSON.stringify(ko.mapping.toJS(self.myData)),
contentType : 'application/json',
dataType : 'json',
success : function(data) {
ko.mapping.fromJS(data, self.myData);
},
error : function (xhr, text, errorThrown) {
// code
}
});
};Thank you for your help and time.
Hi damc,
1. The properties in the code I posted here are not observable properties. ArrayA is an observable array but its properties are not observables. In addition, the Grid edits only the cell values in the Grid. When a value is edited, the ‘updaterow’ function is called passing as params the updated record’s index and data. It depends on the developer’s implementation how the DB or model is updated.
2. To fully update the Grid’s source, you need to call its ‘updatebounddata’ method or set its ‘source’ property again.
Best Regards,
Peter StoevjQWidgets Team
http://www.jqwidgets.comHi Peter,
Thank you four your answer, it is helpful.
But I still have problems to manually update data in cell and that the properties remains observable. I am using knockout mapping plugin to map fetched data into a view model with the observables. If I test arrayA properties before I edit value in grid, they are observable. As soon as I change the value in cell – when the updaterow callback function is called, properties are no longer observable.
I don’t know how to solve updaterow function that properties in array remain observable.My code:
$(document).ready(function () {
var theme = getTheme();var data =
{
"objectA": {
"date": "08.04.2009",
"year": 2008,
"code": 0,
"name": "John",
"surname": "Doe",
"note": null
},
"arrayA": [{
"dateFrom": "07.03.2008",
"dateTo": "07.06.2008",
"duration": null,
"text": "abc",
"code": 633,
"currency": 70.5
}],
"arrayB": [{
"number1": 56,
"numberText1": null,
"number2": 2006,
"numberText2": null
}],
"arrayC": [{
"dateFrom": "07.01.2008",
"dateTo": "07.03.2008",
"duration": 361,
"text": null,
"code": 233,
"currency": 3670.5
}],
"arrayD": [],
"arrayE": [],
"arrayF": [],
"myCode": null
};var self = this;
self.data = data;
// viewModel
var GridViewModel = function (data) {
var self = this,
source = {},
dataAdapter = null;if (data) {
self.myData = ko.mapping.fromJS(data);
}this.loadData = function (theme) {
source = {
localdata: self.myData.arrayA,
datatype: 'local',
updaterow: function (row, rowdata) {
var observableArray = self.myData.arrayA;
observableArray.replace(observableArray()[row], rowdata);
}
};
dataAdapter = new jQuery.jqx.dataAdapter(source);// grid
$('#jqxgrid').jqxGrid({
width: 885,
source: dataAdapter,
pageable: true,
autoheight: true,
editable: true,
selectionmode: 'singlecell',
pagesize: 5,
pagesizeoptions: ['5', '10'],
columns: [{
text: 'Date from',
datafield: 'dateFrom',
width: 110,
columntype: 'datetimeinput',
cellsformat: 'dd.MM.yyyy',
initeditor: function (row, cellvalue, editor) {}
}, {
text: 'Date to',
datafield: 'dateTo',
width: 110,
columntype: 'datetimeinput'
}, {
text: 'Duration',
datafield: 'duration',
width: 120
}, {
text: 'Some text',
datafield: 'text',
width: 140
}, {
text: 'Code',
datafield: 'code',
width: 90,
cellsalign: 'right'
}, {
text: 'Currency',
datafield: 'currency',
width: 170,
cellsalign: 'right'
}]
});
};
}
self.model = new GridViewModel(self.data);
self.model.loadData();
ko.applyBindings(self.model);
});You can change the ‘updaterow’ function to:
updaterow: function (row, rowdata) { var record = self.myData.arrayA()[row]; for(var obj in record) { record[obj] = ko.observable(rowdata[obj]); } }
The above will update only the observables.
Best Regards,
Peter StoevjQWidgets Team
http://www.jqwidgets.comHi Peter,
Thanks for code for update observables. It works fine.
I have another problem.
If I change value in cell – for example in column test into “abc” then ‘updaterow’ function updates cell value into array of characters String { 0=”a”, 1=”b”, 2=”c”} instead of “abc”. Grid shows value as string “abc” – it’s OK. But if I write it in console or display JSON before post it to server it is an array of characters String { 0=”a”, 1=”b”, 2=”c”} . I watch on debug parameter ‘rowdata’ value and there is also for column test value an array of characters String { 0=”a”, 1=”b”, 2=”c”} .
updaterow: function (row, rowdata) {
var record = self.myData.arrayA()[row];
for(var obj in record)
{
record[obj] = ko.observable(rowdata[obj]);
}
console.log(self.myData.arrayA()[row].text()); // (text: [0: "a", 1: "b", 2: "c", 3: "d"]).
}
Thank you for your help.
-
AuthorPosts
You must be logged in to reply to this topic.