0

I need to process the data received from the websocket connection. In the data model, I have to run 2 timers to count the connection time. Below is an example of my implementation:

var socket = io.connect('http://localhost:3000');

window.onload = function () {

    var vm = new Vue({
        el: '#indication',
        data: {
            incomingData: []
        },
        methods: {
            updateB: function (i, num) {
                this.incomingData[i].b_number += " (" + num + ")";
            },
            updateWaitTime: function (i) {
                ++this.incomingData[i].wait_time;
            },
            updateTalkTime: function (i) {
                ++this.incomingData[i].talk_time;
            }
        }
    });

    socket.on("message", function (msg) {
        message = JSON.parse(msg);
        console.log(message)
        if (message.status === "NewChannel") {
            var now = new Date()
            var pos = vm.incomingData.push({
                id: message.id, count_of_day: ++counter,
                a_number: message.callernum, b_number: message.number, date: now.toLocaleString(), talk_time: 0, wait_time: 0
            });
            for (var i = 0; i < vm.incomingData.length; i++) {
                if (vm.incomingData[i].id === message.id) {
                    console.log("start NCTimer for " + message.id);
                    timersNC[message.id] = setInterval(function () {
                        vm.updateWaitTime(i);
                    }, 1000);
                    break;
                }
            }
            return false;
        } else if (message.status === "bridge") {
            for (var i = 0; i < vm.incomingData.length; i++) {
                if (vm.incomingData[i].id === message.id) {
                    console.log("bridge for " + message.id);
                    vm.updateB(i, message.operator_ext);
                    console.log("STOPPING TALT_TIME HERE");
                    clearInterval(timersNC[message.id]);
                    delete timersNC[message.id];
                    break;
                }
            }
            return false;
        }

        else if (message.status === "hangup") {
            for (var i = 0; i < vm.incomingData.length; i++) {
                if (vm.incomingData[i].id === message.id) {
                    for (var id in timersNC){
                        if (id === message.id){
                            clearInterval(timersNC[message.id]);
                            delete timersNC[message.id];
                            console.log("DELETED NC FROM HANGUP!!!!")
                            break;
                        }
                    }
                    for (var id in timersBR){
                        if (id === message.id){
                            clearInterval(timersBR[message.id]);
                            delete timersBR[message.id];
                            console.log("DELETED BR FROM HANGUP!!!!")
                            break;
                        }
                    }
                    console.log("hangup for " + message.id);
                    vm.incomingData.splice(i, 1);
                    break;
                }
            }
            return false;
        }
        else return;
    })
};

The data is updated in the following table:

<div id="indication">
        <table class="rtable">
            <thead>
                <tr>
                    <th>...</th>
                    <th>...</th>
                    <th>...</th>
                    <th>...</th>
                    <th>...</th>
                    <th>...</th>
                    <th>...</th>
                    <th>...</th>
                    <th>...</th>
                    <th>...</th>
                </tr>
            </thead>

            <tbody id="dynamic_row">
                <tr v-for="d in incomingData" :key='d.id'>
                    <td>{{d.b_number}}</td>
                    <td>{{d.queue_number}}</td>
                    <td>{{d.count_of_day}}</td>
                    <td>{{d.date}}</td>
                    <td>{{d.a_number}}</td>
                    <td>{{d.mobile_operator}}</td>
                    <td>{{d.status}}</td>
                    <td>{{d.category}}</td>
                    <td>{{d.wait_time}}</td>
                    <td>{{d.talk_time}}</td>
                </tr>
            </tbody>
        </table>
    </div>

This circuit works until a certain point when the following error occurs:

index.js:62 Uncaught TypeError: Cannot read property 'wait_time' of undefined
    at Vue$3.updateWaitTime (index.js:62)
    at Vue$3.boundFn [as updateWaitTime] (vue@2.4.2:188)
    at index.js:83

I do not understand why this is happening and how to make it work. I apologize in advance if the error is stupid, I'm an absolute beginner in vuejs. I understand that the problem is in the asynchronous deletion and addition of elements, but I do not know how to solve it

1 Answers1

0

It's because the for loop has already finished by the time the setInterval() callbacks run. This means i has been incremented to the same value as vm.incomingData.length by the time vm.updateWaitTime(i) runs and i then points to non-existing item in the array.

What you need to do is to scope i to each iteration. If you're able to use ES6 syntax you can do this by writing your for loop like this:

for (let i = 0; i < vm.incomingData.length; i++) {

I.e. using let instead of var. If ES6 is not an option, you have to create a new function scope within each iteration that creates a scoped copy of i. This can be accomplished by writing your setInterval() expression like this:

timersNC[message.id] = setInterval((function (idx) {
                    return function() {
                      vm.updateWaitTime(idx);
                    };
                }(i)), 1000);

...or alternatively:

timersNC[message.id] = setInterval((function (idx) {
                    vm.updateWaitTime(idx);
                }).bind(null, i), 1000);
Lennholm
  • 7,205
  • 1
  • 21
  • 30