Dynamically update Webix datatable

Hi,

I am looking to update webix datatable dynamically with SSE event values. My aim to create datatree and datatable. When item is dragged from data tree into datatable, it triggers SSE request and gets SSE events from server. I would like to update datatable for that dragged element with values from SSE events.

Can you please show how can we implement it please.

I am able to get SSE events when item is dragged from treeview to datatable. Now i would like to update datatable with SSE events data. can you please show how to dynamically update datatable data.

My code is as below:

<body>
    <!-- <div class='header_comment'>Data Points Explorer</div> -->
    <div class='sample_comment'></div>
    <div id="testA" style="height:95vh;"></div>

    <script type="text/javascript" charset="utf-8">

        EventSource = SSE;
        function sendRestReq(path, tData){

            webix.message(path);
            var payloadData='{"query":[{"path": "'+path+'"}]}';
            var source = new SSE("http://IP_ADDRESS/events?push=1", {payload: payloadData});
            source.onmessage = function(event) {
                payload=JSON.parse(event.data);
                webix.message("data:"+payload["events"][0]["value"]);
            };
            source.stream();
        }

        treeData=[]
        tableData=[];

        webix.ready(function(){
             //loading from file
            webix.ui({
                    type:"space",
                    margin:2,
                    padding:0,
                    autowidth:false,
                    container:"testA",
                    rows:[
                        {
                            view:"toolbar", 
                            height: 50,
                            cols:[
                                // { gravity:5 },
                                {template:"<div class='header_comment'>Data Points Explorer</div>"},
                                // { view:"button", value:"Add", click:function(){
                                //     $$("d1").add({ /* add value here */ });
                                // }},
                                { view:"button", value:"Delete", width:100, click:function(){
                                    $$("datatable1").remove($$("datatable1").getSelectedId());
                                    }
                                }
                            ]
                        },
                            
                        {view:"resizer"},
                        {
                            cols:[
                            {
                                view:"tree",
                                width:400,
                                drag:"source",
                                select:true,
                                data:treeData,
                                on: {
                                    onBeforeDrag: function(context) {
                                      let id = context.start;
                                      const path = [id];
                                      
                                      while (id = this.getParentId(id)){
                                        path.unshift(id);
                                      }
                                 
                                      let fullPath = path.map((id) => {
                                        return this.getItem(id).value;
                                      }).join("/");
                                 
                                      //webix.message(`Full path: ${fullPath}`);
                                      context.path = fullPath;
                                    }
                                  }
                            },
                            {view:"resizer"},
                            {
                                view:"datatable",
                                footer:true,
                                id:"datatable1",
                                css:"webix_data_border webix_header_border webix_dark",
                                scrollX:false,
                                hover:"myhover",
                                select:"cell",
                                multiselect:true,
                                blockselect:true,
                                clipboard:"block",
                                resizeColumn:true, 
                                resizeRow:true,
                                drag:"target",
                                select:"multiselect",
                                columns:eventTable,
                                data:tableData,
                                on:{
                                    onBeforeDrop:function(context, e){
                                        
                                        var item = context.from.getItem(context.source[0]);
                                        var id = this.add({                              
                                          signal1:"/"+context.path,
                                          guid:0,
                                          timestamp:0,
                                          value:0,
                                          type:0,
                                          metaData:0                                  
                                        });
                                        this.refresh()
                                        var tData=updateTable();
                                        sendRestReq("/"+context.path, tData);
                                      return false;
                                    }
                                  }
                            }]
                    }]
            });

            function updateTable(){
                var tData=$$("datatable1").serialize(true);
                alert("Table Rows:"+tData.length);
                return tData
            }

        });
    </script>
</body>
</html>

@Dzmitry @integral Can you please check and give me some hint on it please.

Hello @ganeshkp,

Can you please check and give me some hint on it please.

As previously mentioned, I, personally, do not have any experience with SSE, but from what I understand, SSE is basically a continuous stream of data being sent from the server, and there is no way to communicate with it from the client-side. Now, you could simply update the items that correspond to the data being received from the server, but is that what you are looking for?

Could you please describe the exact way you’d like the SSE to interact with the client-side? Also, what kind of data do you receive as a response?

@Dzmitry Thanks for response.
I would like to give more information on it.

The function sendRestReq() is sending REST request to server and collecting SSE events from it continuously. I just need help in sending these continuous data onto datatable for every one second or continuously whenver data received from server.

The data coming from SSE is json data and it will be like below format:

{‘events’: [{‘guid’: ‘0x000000’, ‘timestamp’: ‘2019-04-15T16:33:23.256800’, ‘value’: 849, ‘type’: ‘1’, ‘meta-data’: ‘0x1’}, {‘guid’: ‘0x000001’, ‘timestamp’: ‘2019-04-15T16:33:23.257799’, ‘value’: 793, ‘type’: ‘1’, ‘meta-data’: ‘0x1’}]}

function sendRestReq() receive this data continuously from server and I would like to update these data onto datatble.

Please let me know if you need any more information please

@Dzmitry I came to know reading existing datatable using serialize() function. Now i am trying to read datatable using that function and update values for specific row with value received from SSE event and send back to datatable. This is what i am trying to do it. Are there any ways to do it using webix or Javascript please

One more question - since you are trying to update your datatable from a one-way source, are you looking to save the result to a separate server in some way? Or are you simply looking for the client-side updates?

In general, if we are talking about simple client-side modifications, then you could try something like this:

  sendRestReq("/"+context.path, tData, this); //pass on `this` as context
function sendRestReq(path, tData, view){
  var update = webix.DataDriver.json.toObject(event.events); // referring to the "events" property, judging from your example
  var payloadData='{"query":[{"path": "'+path+'"}]}';
  var source = new SSE("http://IP_ADDRESS/events?push=1", {payload: payloadData});
  source.onmessage = function(event) {
    payload = JSON.parse(event.data);
    view.updateItem(update.events.id, update.events) //get the item id from the server and update it using the data received from the server
  };
  source.stream();
}

The function sendRestReq() is sending REST request to server and collecting SSE events from it continuously.

Doesn’t SSE imply that it’s a one-way connection? Basically, you can’t communicate with a SSE server. The functionality you are looking for sounds similar to a component integrated with a WebSocket server. Incidentally, we have a fully fledged article covering this very topic in-depth: Websocket: Real-time Data Updates for Webix Widgets.

@Dzmitry Thanks for information.

Sorry for confusing you…

By clarifying your question: function sendRestReq() sends REST(POST) request with path from datatable one time and receives event data continuously from server.

when function sent POST request to server, it creates a SSE session and continuously sends data to client. I will read existing table using serialize function and get path and compare path with event data received and update corresponding datatable row with new value and send it to datatable.

Sorry this is bit tricky. I request not to worry about SSE if it confuses you. Please give idea on how to update datatable row with new values dynamically with event data please.

I am not storing received events anywhere. I would just need to divert received events to datatable continuously. Yes, it is just client side modification.

First solution seems to be ok. I will work on using it and see the results.

Thanks for information.

@Dzmitry Thank you for solution.

Below code just example i tried. it got worked.

function sendRestReq(path, view){
webix.message(path);
var table=view.serialize(true);
table[0].value=200.5667;
table[1].value=1000.67;
table[2].value=500.9898;
view.updateItem(table)
}

This is what i was looking. I will apply same to SSE events. thank you so much for your help:)

@ganeshkp
what is wrong with basic updateItem?
https://docs.webix.com/api__link__ui.datatable_updateitem.html
is not it possible to get item id from received data and update corresponding item?

@integral Thanks for noticing.

I am not able to get id from server. I receive events data in the following format:

{‘events’: [{‘guid’: ‘0x01619C’, ‘timestamp’: ‘2019-04-15T16:33:31.873471’, ‘value’: 390, ‘type’: ‘1’, ‘meta-data’: ‘0x1’}, {‘guid’: ‘0x0161A0’, ‘timestamp’: ‘2019-04-15T16:33:31.874481’, ‘value’: 286, ‘type’: ‘1’, ‘meta-data’: ‘0x1’}], ‘count’: 2}

My table columns are as below (one more column to show full path):
var eventTable=[
{ id:“signal1”, header:{text:“Signal Name”, css:{“background”:"#AFA"}}, width:200, footer:‘Signal Name’, fillspace:true, sort:“string”},
{ id:“guid”, header:“guid”,width:200, footer:‘guid’, fillspace:true, sort:“int”, css:“tableHeader”},
{ id:“timestamp”, header:“timestamp”, width:200, footer:‘timestamp’, fillspace:true, sort:“string”, css:“tableHeader”},
{ id:“value”, header:“value”,width:200, footer:‘value’, fillspace:true, sort:“int”, css:“tableHeader”},
{ id:“type”, header:“type”,width:200, footer:‘type’, fillspace:true, sort:“int”, css:“tableHeader”},
{ id:“metaData”, header:“meta-data”,width:200, footer:‘meta-data’, fillspace:true, sort:“string”, css:“tableHeader”}
];

I have one more dictionary to map path with guid. i compare values of guid received from event with the one in dictionary and get path and update corresponding row. That is the functionality. it is not straight forward updated event values with table, since there is extra column in table for path.
But events dont give path. it gives guid. Thats why i thought of updating whole table.

Please let me know if you have any ways to update table row for the same please.

@integral Can you please show some small example on updating table by using id with new value please. That will help me allot. You can show just by hard coded values also. That is also fine. I just need information like how to get id of specific row please.

in this case it totally depends on your internal logic.

also you can pass id created by addItem into sendRestReq and use it in onmessage event

var id = this.add({
    signal1:"/"+context.path,
    guid:0,
    timestamp:0,
    value:0,
    type:0,
    metaData:0                                  
});
sendRestReq("/"+context.path, tData, id);
function sendRestReq(path, tData, id){

            webix.message(path);
            var payloadData='{"query":[{"path": "'+path+'"}]}';
            var source = new SSE("http://IP_ADDRESS/events?push=1", {payload: payloadData});
            source.onmessage = function(event) {
                payload=JSON.parse(event.data);
                webix.message("data:"+payload["events"][0]["value"]);
                $$("table").updateItem(id, some_received_data);//or other logic
            };
            source.stream();
        }

@integral Thank you so much.