0

I have a code to process some data that comes from an observable, this observable is acquired through a @Input annotation, I subscribe to the observable inside my NgOnInit(), everything was working fine, but I needed to add code to reduce the processing time of the data, which is an array of arrays, my data looks like this:

[ ['id1', object, object], ['id2', object, object] ]

So to reduce the processing time I created a variable that will hold the previous post-processed value of the Observable, and I compare the previous data with the new data and update only the data that changed, my code looks like this:

 private dataSetHolder: Array<any> = [];

constructor() { }


ngOnInit() {
    this.dataSet$.subscribe(data => { //line 43
        console.log('inicio: ', this.dataSetHolder);
        data.forEach(array => {
            const dataNoId = Object.assign([], array);
            const id = array[0];
            dataNoId.shift();
            let pacote: Package = { eixo_x: [], eixo_y: [] };
            if (this.dataSetHolder.length === 0) {
                pacote = this.separaDados(dataNoId, id, pacote);
                this.loadData(pacote);
            } else {
                this.dataSetHolder.forEach(arrayHolder => {
                    if (id === arrayHolder[0]) {
                        if (array.length > arrayHolder.length) {
                            pacote = this.separaDados(dataNoId, id, pacote);
                            this.loadData(pacote);
                        }
                    }
                });
            }
        });
        this.dataSetHolder = data; //line 64
    });
}

When line 64 is executed the current value of data is passed to this.dataSetHolder, when the observable receive a new value, line 43 is executed again, and when line 43 is executed the value of this.dataSetHolder is updated, that shouldn't happen, it should be updated only at line 64.

Does anybody understand what is going on there?

inserir a descrição da imagem aqui

inserir a descrição da imagem aqui

inserir a descrição da imagem aqui

Please note, that from this last image to the next one I have not hit continue on the debug, I am still on line 44

inserir a descrição da imagem aqui

I have also tried changing line 64 to this

            this.dataSetHolder = Object.assign([], data);

Because I thought it could be caused by javascript, because when I do this.dataSetHolder = data; it is not actually passing the object, only the reference, but it still didn't work.

Liam
  • 27,717
  • 28
  • 128
  • 190
  • 2
    I think you're right and it's because you assign by reference. When you do Object.assign([], data); it's copying the first level of your array but the second level is still copied by reference. You would need to do a deep copy to make it work completely, in your case that should work with this : ```this.dataSetHolder = []; data.foreach(dataItem => this.dataSetHolder.push({... dataItem}));``` – bmtheo Jan 30 '20 at 21:42
  • Be careful, if you need a deep clone you can use `let clone = JSON.parse(JSON.stringify(objectToBeCloned));` Object.assign does not work for deep cloning. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign – EM15 Jan 31 '20 at 10:23
  • Please don't add answers into the question. Feel free to add your answer by pressing the answer my question button – Liam Jan 31 '20 at 13:52
  • Sorry, I am new to stackoverflow, but no Liam, it does not answer my question, although the problem was almost the same, as bmtheo explained before, my data was an array of arrays, and the container array was being copied, but the arrays inside the container array were not being copied, they were being referenced, so I had to empty my memory array, and copy each individual sub-array into it. The problem described in this post is the same thing but at only one level, using Object.assign() was my first idea too. – Rodrigo Azevedo Jan 31 '20 at 20:56

1 Answers1

0

My final code looks like this:

    ngOnInit() {
    this.dataSet$.subscribe(data => {
        data.forEach(array => {
            const dataNoId = Object.assign([], array);
            const id = array[0];
            dataNoId.shift();
            let pacote: Package = { eixo_x: [], eixo_y: [] };
            if (this.dataSetHolder.length === 0) {
                pacote = this.separaDados(dataNoId, id, pacote);
                this.loadData(pacote);
            } else {
                this.dataSetHolder.forEach(arrayHolder => {
                    if (id === arrayHolder[0]) {
                        const length = Object.keys(arrayHolder).length;
                        if (array.length > length) {
                            pacote = this.separaDados(dataNoId, id, pacote);
                            this.loadData(pacote);
                        }
                    }
                });
            }
        });
        this.dataSetHolder = [];
        data.forEach(dataItem => this.dataSetHolder.push({... dataItem}));
    });
}

Thanks to the comment of bmtheo I got the problem solved, as he explained, even using Object.assign() to copy the data is not enough, as my data is an array of arrays, when I used Object.assign() I copied the first level of my array, but the second level arrays were not being copied, they were being referenced, that is why the data changing every time a new value was available.

The solution is to empty my array, and copy each sub array to it. in addition to that I had tho change the way I was getting the length of arrayHolder, since it was not being interpreted as an array no more, it was being treated as an object, witch do not influence in the rest of the code, so I added this const length = Object.keys(arrayHolder).length; to my code.