jQWidgets Forums
jQuery UI Widgets › Forums › TreeGrid › jqxTreeGrid exception when data refreshed
Tagged: #jqxTreeGrid #tree
This topic contains 11 replies, has 2 voices, and was last updated by Hristo 4 years, 4 months ago.
-
Author
-
Hi,
I’m fighting with the code snippet below. Basically I need to render in page a jqxTreeGrid and refresh data every 10 seconds. I would like to refresh the data maintaining the state, so without any collapse or scroll to top position when Ajax call happens.
jQuery(document).ready(function () { var leng = jQuery("#lang").val(); jQuery.get("../../media/system/labels_inth/lang.php", {"lang":leng,"mode":2}, function(data,success){ labels = JSON.parse(data); main_function(); }); }); function main_function(){ id_cliente = jQuery("#id_cliente").val(); sessionStorage.setItem('id_dispositivo',null); nome_disp_selected = ""; var url_get_list = url_php + "?type=LIST" + "&id_cliente=" + id_cliente+"&loggedRole="+jQuery("#loggedRole").val()+"&id_user="+jQuery("#id").val(); var columns_list = [{ text: labels["DSP_COL_NOME"], dataField: 'label', editable:false,width:250 }]; var dataFields_list = [ { name: 'id'}, { name: 'parentid' }, { name: 'label' }, { name: 'icon'} ]; var source_list = { datatype: "json", datafields:dataFields_list, hierarchy:{ keyDataField: { name: 'id' }, parentDataField: { name: 'parentid' } }, id: 'id', url: url_get_list, root: 'devices' }; var dataAdapter_list = new jQuery.jqx.dataAdapter(source_list); jQuery("#jqxTree").jqxTreeGrid({ //width: '100%', height:'500px', source: dataAdapter_list, columns: columns_list, altRows: true, autoRowHeight: false, showHeader: false, icons:true, editSettings: { saveOnPageChange: true, saveOnBlur: true, saveOnSelectionChange: false, cancelOnEsc: true, saveOnEnter: true, editOnDoubleClick: false, editOnF2: false }, //sortable: true, }); setInterval(getListTable,10000); }; function getListTable() { jQuery("#jqxTree").jqxTreeGrid('updateBoundData'); };
When the page is rendered the first time, the jqxTreeGrid is ok, but every Ajax call, I receive the following exception:
Uncaught RangeError: Maximum call stack size exceeded at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7)
What I’m missing? Is it possible to refresh data maintaining the state of the component?
Should be possible obtain the same result also with loading item on demand?Regards,
GiorgioFor the sake of completeness, I post also the output generated from AJAX call:
{ "devices": [ { "id": "1003", "label": "Technodal", "parentid": -1, "icon": "../../images/inthegra/blue_user.png" }, { "id": "108", "label": "Giuseppe Manzulli", "parentid": "1003", "icon": "../../images/inthegra/grey_user.png" }, { "id": "113", "label": "Giovanni Gabriele", "parentid": "1003", "icon": "../../images/inthegra/grey_user.png" }, { "id": "108_12", "label": "s15_003", "parentid": "108", "icon": "../../images/inthegra/connesso_OK_1.gif" }, { "id": "108_51", "label": "s15_040", "parentid": "108", "icon": "../../images/inthegra/connesso_OK_1.gif" }, { "id": "108_52", "label": "s15_041", "parentid": "108", "icon": "../../images/inthegra/connesso_KO_1.gif" }, { "id": "108_62", "label": "s15_050", "parentid": "108", "icon": "../../images/inthegra/connesso_KO_1.gif" }, { "id": "108_63", "label": "s15_051", "parentid": "108", "icon": "../../images/inthegra/connesso_OK_1.gif" }, { "id": "108_67", "label": "s15_055", "parentid": "108", "icon": "../../images/inthegra/connesso_OK_1.gif" }, { "id": "108_68", "label": "s15_056", "parentid": "108", "icon": "../../images/inthegra/connesso_OK_1.gif" }, { "id": "108_69", "label": "s15_057", "parentid": "108", "icon": "../../images/inthegra/connesso_OK_1.gif" }, { "id": "113_12", "label": "s15_003", "parentid": "113", "icon": "../../images/inthegra/connesso_OK_1.gif" }, { "id": "113_51", "label": "s15_040", "parentid": "113", "icon": "../../images/inthegra/connesso_OK_1.gif" }, { "id": "113_52", "label": "s15_041", "parentid": "113", "icon": "../../images/inthegra/connesso_KO_1.gif" }, { "id": "113_62", "label": "s15_050", "parentid": "113", "icon": "../../images/inthegra/connesso_KO_1.gif" }, { "id": "113_63", "label": "s15_051", "parentid": "113", "icon": "../../images/inthegra/connesso_OK_1.gif" }, { "id": "113_67", "label": "s15_055", "parentid": "113", "icon": "../../images/inthegra/connesso_OK_1.gif" }, { "id": "113_68", "label": "s15_056", "parentid": "113", "icon": "../../images/inthegra/connesso_OK_1.gif" }, { "id": "113_69", "label": "s15_057", "parentid": "113", "icon": "../../images/inthegra/connesso_OK_1.gif" } ] }
What I change between AJAX calls, is simply a different icon for an item, but for the rest the json returned from every request is the same, could be that the problem?
If I don’t return the leafs of level 2 from AJAX calls, when I invoke updateBoundData, the call is ok, but the tree collapse totally. Can we prevent this behaviour?Regards,
Giorgio.Hello Giorgio,
The correct approach is to initialize the widget just once and after that update it with its methods.
I mentioned this because I saw that you use a function for the initialization (main_function
function).
About the “virtualmode” option – the data there is loaded on demands and you will need to update the jqxTreeGrid again if you have any changes there.
On the other hand, if you have single a record to update you could use theupdateRow
method.
You could try both of them.
I look forward to hearing from you.Best Regards,
Hristo HristovjQWidgets team
https://www.jqwidgets.comHi Hristo,
Thanks for your reply. I’m a bit confused when you mentioned the one time initialization and the main function, could you show me how to modify my code in order to adhere to the best practices you told above?
Thanks very much,
Giorgio.Hello Giorgio,
Your code looks fine.
About the extra variables that you use to set in the url I would like to suggest you look at this tutorial:
https://www.jqwidgets.com/jquery-widgets-documentation/documentation/jqxgrid/jquery-grid-extra-http-variables.htm
I try to test some of your actions in a new example and it seems to work fine.Best Regards,
Hristo HristovjQWidgets team
https://www.jqwidgets.comHi Hirsto,
I implemented the jqxtreegrid in virtualmode as you suggest me.
Now for requirement, I need to update date every 10 seconds, actually I need to update just the expanded rows (I have a hierarchy of maximum two levels)
How can I do that? Please show me an example if you can.Regards,
GiorgioHi Hirsto, just for your understanding, the code produced is similar to the :
http://jsfiddle.net/jqwidgets/j82VQ/I have a dataAdapter defined into the method virtualModeCreateRecords.
Now if I want to refresh from server every 10 seconds only expanded row, should I use the same dataAdapter with updated functions like formatData, etc in order to parametrize the query parameters to pass to the server?
If I call dataBind and the records returned already exists it will complains for double Error ID right?How can I accomplish just the refresh of the expanded rows?
Regards,
Giorgio.Hello Giorgio,
You should care about the unique records on the server.
The records visualized in the jqxTreeGrid when using thevirtualmode
feature are loaded on demand.
Also, I would like to suggest you look at our forum where has a topic with a similar discussion that could be useful.
Please, take a look at this topic:
https://www.jqwidgets.com/community/topic/editing-with-virtual-mode-ajax/Best Regards,
Hristo HristovjQWidgets team
https://www.jqwidgets.comHi Hirsto,
First of all, the error:Uncaught RangeError: Maximum call stack size exceeded at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7) at V (jqx-all.js:7)
is basically related to the id field: if it contains special characters like ‘_’ or ‘-‘ it generate the error above.
Maybe it is a bug, because in the documentation I don’t have read nothing about this limitation.In order for you to understand maybe what I have to achieve, is better if I share my code. As I told you I need in
virtualmode
, to update from server just the leaf of level 2, that are basically devices, so I need to keep track when a devices is connected or not and change icon accordingly. Because at the moment, I don’t really know how to use the dataAdapter for achieve that, I keep track of the row_expanded of level 1 and the devices_to_update of level 2. I want to invoke the updateRow method just when there are changes of the status, but here I found another problem trying to update the icon: when I invoke the updateRow with the changed icon, nothing happen, but the code is correct because if I try to update label it works. I tried also to update manually the icon updating the DOM, but is a very poor technique.
Below my code:var row_expanded = new Set(); var devices_to_update = new Map(); function main_function(){ var source = { datatype: "json", datafields:[ { name: 'id'}, { name: 'node_id'}, { name: 'parentid' }, { name: 'label' }, { name: 'icon'} ], hierarchy:{ keyDataField: { name: 'node_id' }, parentDataField: { name: 'parentid' } }, id: 'node_id', url: url_php, root: 'devices' }; var dataAdapter = new jQuery.jqx.dataAdapter(source); jQuery("#jqxTreeGrid").jqxTreeGrid({ width: '100%', height:'500px', columns: [{ text: labels["DSP_COL_NOME"], dataField: 'label', width:'auto'}], altRows: true, autoRowHeight: false, showHeader: false, editable: true, selectionMode: 'singlerow', icons:true, editSettings: { saveOnPageChange: true, saveOnBlur: true, saveOnSelectionChange: true, cancelOnEsc: true, saveOnEnter: true, editSingleCell: true, editOnDoubleClick: true, editOnF2: false }, virtualModeCreateRecords: function (expandedRecord, done) { dataAdapter._options = { formatData: function (data) { jQuery.extend(data, { type: "LIST", id_cliente: id_cliente, loggedRole: jQuery("#loggedRole").val(), id_user: jQuery("#id").val(), level: (expandedRecord == null) ? -1 : expandedRecord.level, id_user_selected: (expandedRecord != null && expandedRecord.level == 1) ? expandedRecord.id : null }); return data; }, loadComplete: function() { if(expandedRecord != null && expandedRecord.level == 1 ){ for (let dev of dataAdapter.records) devices_to_update.set(dev.node_id,((({ id, node_id, label, parentid, icon }) => ({ id, node_id, label, parentid, icon }))(dev))); } done(dataAdapter.records); }, loadError: function (xhr, status, error) { done(false); throw new Error(url_php + error.toString()); } } dataAdapter.dataBind(); if (expandedRecord != null && expandedRecord.level == 1) row_expanded.add(expandedRecord.node_id); }, virtualModeRecordCreating: function (record) { if (record.level == 2) { record.leaf = true; } else{ jQuery("#jqxTreeGrid").jqxTreeGrid('lockRow', record.node_id); } } }); jQuery("#jqxTreeGrid").on('rowCollapse', function (event){ var key = event.args.key; var row = event.args.row; row_expanded.delete(key); if (row.level == 1){ for(let r of row.records) devices_to_update.delete(r.node_id) } }); jQuery("#jqxTreeGrid").on('rowExpand', function (event){ var key = event.args.key; var row = event.args.row; row_expanded.add(key); if(row.level == 1){ for (let dev of row.records) devices_to_update.set(dev.node_id,((({id, node_id, label, parentid, icon}) => ({id, node_id, label, parentid, icon}))(dev))); } }); window.setInterval(getListTable, 10000); }; function getListTable() { jQuery.get(url_php, { "type":"UPDATED", "id_user_selected":"('" + Array.from(row_expanded).join("', '") + "')", "id_cliente":jQuery("#id_cliente").val() }, function(data,status){ var devices = JSON.parse(data).devices; for (dev of devices) { if(devices_to_update.has(dev.node_id) && JSON.stringify(dev) !== JSON.stringify(devices_to_update.get(dev.node_id))) { devices_to_update.set(dev.node_id, dev); jQuery('#jqxTreeGrid').jqxTreeGrid('updateRow', dev.node_id, dev); } } }) };
Please, help me to understand what I should have to do for update just the expanded rows every 10 sec, because I really can’t figure out to do that. Should I use the same dataAdapter? If so, how? How can I handle duplicate coming from server?
I saw the post you share me, but seems very different for what I need to do, it talks about inline editing, so updating coming from webpage to server, but this is the opposite: every 10 sec the server give rows that already exist and that can maybe I need to update.Regards,
Giorgio.Hello Giorgio,
If you try to set the record with the same id in the
Set
object it will throw errors.
I would like to suggest you try to create as simple as a possible example to be easier to recognize the issue.
In theloadComplete
callback you should provide the next (inner) records that are unique.
Please, check this one.
To update the jqxTreeGrid you just need to invoke theupdateBoundData
method if the jqxDataAdapter is bound correctly.
The jqxTreeGrid should re-render the content to change the image in the wanted content.
If you still have trouble with this it will be better if you could provide the database (as simple as possible) to reproduce your case.
Also, you could contact the Technical Support Team (support@jqwidgets.com) with these details.Best Regards,
Hristo HristovjQWidgets team
https://www.jqwidgets.comHi Hristo,
And what about update to update the icon using the method
updateRow
when the grid hasicons: true
?
I have invoked the methodupdateRow
andsetCellValue
changing the image but nothing happens.
This maybe rely on the fact that there is no column icon in thecolumns
attribute, because for the label field it works correctly.
Is there any workaround?Regards,
Giorgio.Hello Giorgio,
We already discuss this.
But you could update the source of the jqxTreeGrid with the new image.
Please, take a look at this demo:
http://jsfiddle.net/f0ka6wjv/
Also, you could use the mentioned approach in this topic (that I think is familiar for you):
https://www.jqwidgets.com/community/topic/jqxtreegrid-update-icon-using-updaterow/Best Regards,
Hristo HristovjQWidgets team
https://www.jqwidgets.com -
AuthorPosts
You must be logged in to reply to this topic.