VUE 3 array not updating reactively but array[index] is - javascript

So I am having this issue when I am trying to link an updating array of objects to a konva circle. The issue isnt getting the circles to appear, but what seems to be happening is that within this for loop to update the players locations based on the "tick" I am setting the array[index].x to a specific value. When I console.log these values they are updating properly. However, when I console.log(array) itself it logs the very last calculated value of the loop.
The players array is defined as such
export default {
data() {
return {
roundNumber: 1,
players: [],
and these values are pushed on setup for each player in the json
let tempObj = round.teamCT[id]
tempObj.x = 0;
tempObj.y = 0;
tempObj.team = "CT"
this.players.push(tempObj)
how I am editing values
console.log(this.players);
console.log(this.players[index]);
this.players[index]['x'] = (x-info.x0)*k/info.scale;
this.players[index]['y'] = (info.y0-y)*k/info.scale;
console.log(this.players);
console.log(this.players[index]);
You can see in this screenshot that the array itself is updating very differently then the array[index]:
Ive tried adding a watch: on the array itself and that only toggled once, not every time it updates.
Ive looked into Vue.set but that was removed in vue3 and seems to be the best answer so far.
Any help is appreciated!

Since Vue.set doesn't exist anymore, you can do this
const clone = JSON.parse(JSON.stringify(this.players));
clone[index].x = "foo";
this.players = clone;

Related

javascript remove previous filter on an object before applying new one

I have a series of buttons that apply filters to an object using a function similar to this:
isNew(type) {
//need to reset filter first
this.results = this.results.filter(function(type) {
return type.has_user_viewed === true
})
console.log('isNew');
}
The problem I have is if one filter is applied by the user clicking, and then another filter applied, the filtered array is filtered again. What I need to do with the above is reset the object to it's original state before applying a new filter. Not sure how to "reset" a filter here?
Just save the unfiltered data to a variable. filter creates a new array object (shallow copying elements) each time, so your code overwrites the original data with the filtered data:
this.data = [...whatever the source is]
isNew(type) {
//need to reset filter first
this.results = this.data.filter(function(type) {
return type.has_user_viewed === true
})
console.log('isNew');
}
You'll probably need to store the result of the filter somewhere other than this.results if you want to access the original list of results for additional filtering later. Note that this change will likely force you to change other code.
An example of what I'm recommending:
this.filteredResults = this.results.filter(function(type) {
return type.has_user_viewed === true
})
I would suggest that you google immutability, as understanding it will help you greatly when you need to solve similar problems in the future.

ES6 class getter, temporary return or alternative solution

I am trying to solve a problem I am seeing when rendering a list of items in my ui that is coming out of a es6 class I have created. The model is working great, however I am using animations that are listening to (in react) mount, onEnter, and onLeave of the items.
When I apply my filters and sorting via the model and spit back the new list of items via the getter, the animations do not apply to some items because the list is just being re sorted, not necessarily changed.
So my getter just grabs this.products of the class and returns it and applies a sort order to it. And if filters are applied (which are tracked by this._checkedList in the class), the this.products is reduced based on which filters are selected then sorted. So that getter looks like so :
get productList() {
if (this._checkedList.length > 0) {
const filteredProducts = _.reduce(this.filterMap, reduceFilters, []);
const deDuped = _.uniq(filteredProducts, 'id');
return this.applySort(deDuped);
}
const deDuped = _.uniq(this.products, 'id');
return this.applySort(deDuped);
}
What I am trying to figure out, is a way to to temporarily send back an empty array while the filters or sorting run. The reason being the ui would receive an empty array (even if for a split second) and react would register the new sorted/filtered list as a new list and fire the enter/leave/mount animations again.
My attempt was to set a local property of the class like -
this._tempReturn = false;
then in the functions where the sort or filter happen, I set it to true, then back to false when the function is done like this -
toggleFilter(args) {
this._tempReturn = true;
...toggle logic
this._tempReturn = false;
}
Then changed the getter to check for that property before i do anything else, and if it's true, send back an empty array -
get productList() {
if (this._tempReturn) {
return [];
}
...
}
However, this does not seem to work. Even putting a console.log in the if (this._tempReturn) { didn't show any logs.
I also tried sending back a new list with lodash's _.cloneDeep like so :
get productList() {
if (this._checkedList.length > 0) {
const filteredProducts = _.reduce(this.filterMap, reduceFilters, []);
const deDuped = _.uniq(filteredProducts, 'id');
return _.cloneDeep(this.applySort(deDuped));
}
const deDuped = _.uniq(this.products, 'id');
return _.cloneDeep(this.applySort(deDuped));
}
this did not work either. So it seems the empty array return might be a better approach.
I am wondering if there is some way to achieve this - I would like to have the array be return empty for a second perhaps while the filters and sort are applying.
Very stuck on how to achieve, perhaps I am even looking at this problem from the wrong angle and there is a much better way to solve this. Any advice would be welcomed, thanks for reading!
In order to force a re-render of items in a list when updating them you just need to make sure that each items has a unique key property.
Instead of rendering the list, then rendering it as empty, then re-rendering a changed list make sure each child has a unique key. Changing the key property on a child in an array will always cause it to re-render.

How Do I Make an Array of Objects a Reactive Data Source?

I have an array of objects. Say
var
sidelist = [
{
name:"asdf",
id:1234,
types:[...]
}
];
Every object is turned into a box on the page using this construct
Template.global.side = function(){
var obj = [], m;
m = 1;
for (var i in sides){
obj.push({
index : m,
object : sides[i]
});
}
return obj;
}
The HTML:
{{#each side}}
<div class="span{{this.index}}" id={{this.object.id}}>
<div class="side-head">{{this.object.name}}</div>
</template>
There is a function that creates and pushes a new object into the array. How do I make the row of boxes reactively update on the page when the array they depend on changes?
So when I add a new object a new box should appear.
If you want to use Dependencies, it can look like this:
var sidelist = ...;
var sidelist_dep = new Deps.Dependency;
Template.global.side = function(){
sidelist_dep.depend();
// Do your stuff here;
return ...;
};
// Important: call this every time you change sidelist,
// AFTER the change is made.
sidelist_dep.changed();
See: http://docs.meteor.com/#deps
In almost all cases, you should put the objects in a Meteor Collection instead of an array that is part of a reactive object. There are many reasons for this, including the following
Adding, removing, searching, and updating will all be faster
The reactivity will be on the element level instead of the array
Meteor won't re-render the whole set of objects when something is added or deleted - just the change
You can define a sort order on the collection, making it much more flexible than a fixed sequence
Take a look at Andrew Wilcox's isolate-value smart package:
https://atmosphere.meteor.com/package/isolate-value
The README contains the exact example of selectively rerendering relevant templates when values are added/removed from an array stored in a Session varaible.

Changing the variables of a class in OOP in javascript

I have defined a function called Node which stores the properties of nodes in a graph data structure. The function is something like this:
function Node(){
...
this.outEdges = [];
this.inEdges = [];
...
}
where the inEdges and outEdges store elements of type Edge which is another function I have defined. During the program these arrays are filled with elements.
At some point in my code I need to reset these two arrays so I write:
nodes[i].outEdges.length = 0;
nodes[i].inEdges.length = 0;
where nodes is an array of elements of type Node and I am accessing an element in a for loop.
The problem is, after setting outEdges and inEdges to 0, I expected them to be [] in the nodes[i] property list. However, when I output nodes[i] into console, the outEdges and inEdges still have the elements in them. The stranger thing is that when I output nodes[i].outEdges to console, it prints [] , which is correct, but clicking on [ ] again opens the list of the elements! I can't really figure out why the nodes[i] variables don't change?
That happens (probably) because the browser prints out the empty array but by the time you check it, it has content again. So when you click to expand the browser shows the actual content.
As you can see the values [1,3,7] were added after the command console.log(o) but they are shown on the screen (even though the length shown is 0).
You're not supposed to set the length field. Just re-initialize them:
nodes[i].outEdges = [];
nodes[i].inEdges = [];
Edit: My bad, setting the length should work. It does work for me on Chrome at least. However, I still think it's safer and better style to re-init.
Just create a new object with the same name
nodes[i].outEdges = new Array();

Javascript resetting an array

I'm having with some very strange behaviour when I try to reset an array; eg:
data.length=0;
where data is an array. I'll try and include only the relevant code here but basically what I;m doing is on each iteration of my program I'm populating the array with updated values and the array then is used in another function. But when I reset the array the function appears to get the values on the first iteration but none afterwards.
However when I don't reset the array then the function gets the values, but also the older values. I don't want this, as I only want the new updated values only. This is a code snippet:
var buffer = [['1',[0]],['2',[0]],['3',[0]],['4',[0]]];
var dataset = [];
ws.onmessage = function(evt){
dataset.length=0;
var distances = JSON.parse(evt.data);
console.log(distances);
for(var i=0; i<buffer.length; i++) {
if(buffer[i][0] == distances.miles) {
buffer[i][1][0]++;
}
//console.log(buffer);
dataset.push(buffer[i][1][0]);
draw();
//console.log(dataset);
}
}
The function uses the dataset array to redraw a chart.
I've tried to keep it simple here, but the full function is here.
I really don't know what's causing this unexpected behaviour.
EDIT:
console.log(dataset) shows the new updated values, but somehow dataset.length=0; is preventing the updated array to be used by the draw() function. As without the resetting of the array the array can be used by the draw() function.
EDIT:
I've tried to not reset the array but instead get the last 4 elements and put them in a new array and then send them to the draw(), but still the same odd behaviour:
x = dataset.slice(-4);
console.log(x);
draw();
But if I don't do that or don't clear the array, then draw() render a 'wrong' chart. I can't see what is wrong.
THE problem somehow seems to reside with the resetting of the array and that because of this it means the draw() function appears to be called only once at the first iteration.
Please, Please help
You don't need to set length at all. To clear a list of all value, just set it to an empty list:
dataset = [];
Looking at your code, I'm not sure, but why do you even have dataset? You don't ever read anything out of it, and you say you want to clear it every time thru the array.
Do you mean do to something like:
for(var i=0; i<buffer.length; i++) {
if(buffer[i][0] == distances.miles) {
buffer[i][1][0]++;
}
dataset.push(buffer[i][1][0]);
}
draw(dataset); // draw outside the loop, using dataset.

Categories