jQuery UI Widgets Forums TreeGrid jqxTreeGrid exception when data refreshed

This topic contains 11 replies, has 2 voices, and was last updated by  Hristo 2 weeks, 3 days ago.

Viewing 12 posts - 1 through 12 (of 12 total)
  • Author
  • jqxTreeGrid exception when data refreshed #114057

    ae50042
    Participant

    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,
    Giorgio

    jqxTreeGrid exception when data refreshed #114059

    ae50042
    Participant

    For 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.

    jqxTreeGrid exception when data refreshed #114070

    Hristo
    Participant

    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 the updateRow method.
    You could try both of them.
    I look forward to hearing from you.

    Best Regards,
    Hristo Hristov

    jQWidgets team
    https://www.jqwidgets.com

    jqxTreeGrid exception when data refreshed #114102

    ae50042
    Participant

    Hi 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.

    jqxTreeGrid exception when data refreshed #114122

    Hristo
    Participant

    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 Hristov

    jQWidgets team
    https://www.jqwidgets.com


    ae50042
    Participant

    Hi 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,
    Giorgio


    ae50042
    Participant

    Hi 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.


    Hristo
    Participant

    Hello Giorgio,

    You should care about the unique records on the server.
    The records visualized in the jqxTreeGrid when using the virtualmode 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 Hristov

    jQWidgets team
    https://www.jqwidgets.com


    ae50042
    Participant

    Hi 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.


    Hristo
    Participant

    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 the loadComplete callback you should provide the next (inner) records that are unique.
    Please, check this one.
    To update the jqxTreeGrid you just need to invoke the updateBoundData 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 Hristov

    jQWidgets team
    https://www.jqwidgets.com


    ae50042
    Participant

    Hi Hristo,

    And what about update to update the icon using the method updateRow when the grid has icons: true?
    I have invoked the method updateRow and setCellValue changing the image but nothing happens.
    This maybe rely on the fact that there is no column icon in the columns attribute, because for the label field it works correctly.
    Is there any workaround?

    Regards,
    Giorgio.


    Hristo
    Participant

    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 Hristov

    jQWidgets team
    https://www.jqwidgets.com

Viewing 12 posts - 1 through 12 (of 12 total)

You must be logged in to reply to this topic.