Cannot set properties of undefined by iteration the nested JSON - javascript

I have a nested JSON, this is structured as follows:
As you can see the JSON is called bwaResult and in this object there are three big groups. These groups are called actBwa, fcBwa and planBwa. These groups contain years and yearlyResults(sums) which also have years. I would like to assign the values to the individual years. That means in 2020 you would have actBwa, fcBwa, planBwa and the yearlyResults values and the same for the other years.
My Code:
const plMonthResults = {};
const plMonth = resp.success ? resp.bwaResult : null; // JSON-DATA
delete resp.success;
if (plMonth && plMonth !== null && Object.keys(plMonth)) {
let count = 0;
for (const bwaType in plMonth) {
const plMonthData = plMonth[bwaType]; // Here I get actBwa, fcBwa, planBwa
if (count === 0) {
for (const yearKey of Object.keys(plMonthData)) {
plMonthResults[yearKey] = {}; // Sort by years
}
}
for (const yearKeyInPlMonth in plMonthData) {
plMonthResults[yearKeyInPlMonth][bwaType] = plMonthData[yearKeyInPlMonth]; // Here then arises the error
}
count += 1;
}
}
When I run the code then I get the following error:
ERROR TypeError: Cannot set properties of undefined (setting 'fcBwa')
I guess since actBwa only has 2020 and the other groups have more years there is a problem finding fcBwa and iterating further or am I seeing this wrong? Can you tell me how to solve this problem?
UPDATE my work in stackblitz: https://stackblitz.com/edit/read-local-json-file-service-udqvck?file=src%2Fapp%2Fapp.component.ts

It seems like you're using count to copy the keys only once, but that means you will only have the keys of the first object (in this case actBwa). You can instead go through the key of each object, but make sure you don't override the existing ones. So remove the count and modify the look like this
for (const yearKey of Object.keys(plMonthData)) {
plMonthResults[yearKey] = plMonthResults[yearKey] ?? {};
}
You can even remove this loop and include the check into the main one:
for (const yearKeyInPlMonth in plMonthData) {
plMonthResults[yearKeyInPlMonth] = plMonthResults[yearKeyInPlMonth] ?? {};
plMonthResults[yearKeyInPlMonth][bwaType] = plMonthData[yearKeyInPlMonth];
}
Let me know if that gives you the result you're after

Related

Weird issue with Vue / Javascript variables

I honestly don't even know how to search for this question (what search param to write) but either way its bit weird issue and I am desperate for help.
So I am trying to do something simple, event sends "form-change" and when it does, we set new value in "this.data" object. Fairly simple. I don't expect this.data to be reactive I just want to update it.
// Find our data object which we want to update/change
if (form.field.includes('.')) {
let find = form.field.split('.'), level = this.data;
for (let index = 0; index < find.length; index++) {
if (level[find[index]] !== undefined) {
level = level[find[index]];
} else {
level = undefined;
}
}
if (level !== undefined)
level = setFieldData();
}
This is fairly simple, we have name of field "inspect.book" and when update comes (Event) we just use dots to split into multi tree and update "this.data.inspect.book" to new value. But it does not work. Value does not change.
But the value from actual this.data.inspect.book comes out just fine using:
console.log(level);
However, if I do this:
this.data[ form.field.split( '.' )[ 0 ] ][ form.field.split( '.' )[ 1 ] ] = setFieldData();
It works fine. So "reference" to variable does not work... how is this possible? Looks like a bug in javascript or is it something with vue/reactivity?
Does anyone have better idea how to get this to work?
So you are trying to update form data using to notation ?
i would do something like that :
_update(fieldName, value) {
// We split segments using dot notation (.)
let segments = fieldName.split(".");
// We get the last one
let lastSegment = segments.pop();
// We start with this.data as root
let current = this.data
if(current) {
// We update current by going down each segment
segments.forEach((segment) => {
current = current[segment];
});
// We update the last segment once we are down the correct depth
current[lastSegment] = val;
}
},
if i take your example :
if (form.field.includes('.')) {
let find = form.field.split('.'), level = this.data;
for (let index = 0; index < find.length - 1; index++) {
if (level[find[index]] !== undefined) {
level = level[find[index]];
} else {
level = undefined;
}
}
if (level !== undefined)
level[find.pop()] = setFieldData();
}
i replaced find.length by find.length - 1
and replaced level = setFieldData() by level[find.pop()] = setFieldData()
you should update the property of the object, without actually overriding the value,
because if you override the value, the original value will not get updated.

How can I find duplicate records from array in JS

I am trying to find duplicate records from a given array. I have tried the following function, but it did not work as expected, later I come to know I was comparing the same record with itself. I have written the following function.
identifyDupliateRecords(verifiedRecordsAll) {
let duplicateRecords : any;
if(verifiedRecordsAll.length > 1){
const tempDuplicateRecords = []
this.verifiedRecordsAll.forEach((record)=> {
if(verifiedRecordsAll.Some === verifiedRecordsAll.Some ||
verifiedRecordsAll.Gum === verifiedRecordsAll.Gum ||
verifiedRecordsAll.Thing === verifiedRecordsAll.Thing) {
tempDuplicateRecords.push(record);
duplicateRecords = tempDuplicateRecords
}
})
}
return duplicateRecords
}
For finding duplicate records I need to have such a condition that if Some or Gum or Thing property of one record should match the value of another record in the same array, then it should be stored as a duplicate.
I am new to JS and cannot think of any other solution.
Any help would be appreciated. Thank you.
this.verifiedRecordsAll=[] --Array need to add
this.verifiedRecordsAll =this.verifiedRecordsAll.filter((element, i) => i === this.verifiedRecordsAll.indexOf(element))
const yourArray=[]
let duplicatedRecords=[]
for(let k=0;k<array.length;k++){
for(let i=0;i<array.length;i++){
if(k!==i&&array[k]===array[i]){
duplicatedRecords.push(array[k])
}
}
}
duplicatedRecords= [...new Set(duplicatedRecords)]

Unexpected object change

I am implementing end of round function for a board game. Each players state is represented with an object that is in turn stored in array playerStates:
const [playerStates, setPlayerStates] = useState(getInitialPlayerStates);
const [playerIndex, setPlayerIndex] = useState(0);
const playerState = playerStates[playerIndex];
function setPlayerState(playerState) {
let tPlayerStates = [...playerStates];
tPlayerStates.splice(playerIndex, 1, playerState);
setPlayerStates(tPlayerStates);
}
End of round function checks whether all players have finished their actions, and if so, resets global state
/** END OF ROUND **/
function handleEndRound() {
let nextPlayerIndex = playerIndex + 1 < GLOBAL_VARS.numOfPlayers ? playerIndex + 1 : 0;
let haveAllFinished = true;
while (playerIndex !== nextPlayerIndex) {
if (!playerStates[nextPlayerIndex].finishedRound) {
haveAllFinished = false;
}
nextPlayerIndex = nextPlayerIndex + 1 < GLOBAL_VARS.numOfPlayers ? nextPlayerIndex + 1 : 0;
}
if (haveAllFinished) {
...
/* reset player states */
let tPlayerStates = [];
for (let i = 0; i < GLOBAL_VARS.numOfPlayers; i++) {
let tPlayerState = {...playerStates[i]};
console.log("RESETTING PLAYER STATE:");
console.log(tPlayerState);
tPlayerState.availableAdventurers = GLOBAL_VARS.adventurers;
/* remove active card */
if (tPlayerState.activeCard !== false) {
tPlayerState.discardDeck.push(tPlayerState.activeCard);
tPlayerState.activeCard = false;
}
/* move cards from hand to discard */
for (let card of tPlayerState.hand) {
tPlayerState = addCardToDiscardDeck(card, tPlayerState);
tPlayerState.hand = [];
}
console.log("tPlayerState before:");
console.log(tPlayerState);
/* draw a new hand */
for (let i = 0; i < GLOBAL_VARS.handSize; i++) {
if (tPlayerState.drawDeck.length === 0) {
console.log("tPlayerState after:");
console.log(tPlayerState);
tPlayerState = addDiscardToDrawDeck(tPlayerState);
}
if (tPlayerState.drawDeck.length > 0) {
tPlayerState = addCardToHand(tPlayerState.drawDeck[0], playerState);
tPlayerState.drawDeck.splice(0, 1);
}
}
...
The problem is that wrong player state is stored, as evidenced by the console outputs:
tPlayerState before: App.js:315
Object { finishedRound: true, ... color: "#FFD41A" }
tPlayerState after: App.js:320
Object { finishedRound: false, ... color: "#2A8CFF" }
The color identifies players, and for some reason state of the first player is exchanged by the state of the second player.
There is a lot going on with deep-nested objects and arrays and that might be the cause - however I do not see why exactly should these two outputs be different. What is the source of the change? How can I prevent it?
The complete code is hosted at https://github.com/faire2/loreHunters/.
Additional information:
The problem is pertinent to JS rather than to React. The problem was related to passing a shallow copy to of a deep object to a function. I still do not understand what exactly was going on: in the end, two strangely fused objects were being pushed by into an array even though I was pushing only one object.
The problem was passing a shallow copy of a deep nested object to a function and back. The problem was resolved by passing a Lodash deep clone of that object:
...
const result = addCardToHand(tPlayerState.drawDeck[0], cloneDeep(tPlayerState));
...
I would still like to understand what was happening, and why the two objects, both dealt with separately in a loop, were being merged into one.
EDIT: so it seems that console.log does not always show the proper state of an object. I used "debugger" to pause the run and check for the real state of the concerned objects, which cleared all the confusion. So the problem itself was caused by a shallow copy, which was remedied by using cloneDeep from Lodash. The correct state can be checked by using the debugger;.

Problems with immutable array

Recently i started working with D3.js to plot a sunburn graph. The data is provided in JSON. For some design stuff i wanted to swap some items (called childrens in D3 doc).
I know in JS arrays are objects...so something like this:
var buffer = myarray[2];
is just a reference. Therefore a buffer for swapping has no effect (?).
Thus i invented a second array (childrens_final) in my code which adopt the items while the swapping process. Its just iterating through every item, a second iteration is looking for an item with the same name to set items with same name in a row. Therefore the swap.
var childrens = response_data.data.data['children'];
var childrens_final = []
for (var child = 0; child < childrens.length; child++) {
var category = childrens[child];
var found = false;
var i = child+1
while (!(found) && (i < childrens.length)) {
if (childrens[i]['name'] == category['name']) {
var childrens = swapArrayElements(childrens, child+1, i);
var one = childrens[child];
var two = childrens[child+1]
found = true;
}
i++;
}
if (found) {
childrens_final.push(one);
childrens_final.push(two);
child++;
}
else {
childrens_final.push(childrens[child])
}
}
response.data.data['children'] = childrens_final;
return response.data.data;
The function swapArrayElements() is just using splice:
function swapArrayElements(list, x, y) {
if (list.length ==1) return list;
list.splice(x, 1, list.splice(y,1, list[x])[0]);
return list;
}
The problem is that there is still no effect from the swap in the graph. But when logging the childrens_final. There is something like that in the console:
Array [ Object, Object, Object, Object, Object, Object, Object, Object, Object ]
The objects are in the right order! But in the array there is still the old order.
Thats actually so basic, but i dont see a solution.
Btw...the code is working under AngularJS.
Found the problem. It's a D3.js problem. D3 is sorting the data itself. You have to set explicitly:
d3.layout.partition.sort(null)
Otherwise every pre sorting process has no effect.

Are there cases in which Array.isArray() doesn't work?

So I've been trying to debug a physics engine I'm writing, and for a multi-dimensional spatial hashmap I'm needing to allocate a 2D array of arrays.
Why does this code give me "Cannot read property 'push' of undefined"? Is there something happening in the line between my if statements and my trying to push on to the array?
EDIT "this" refers to a PhysicsEngine instance, it keeps a reference to the "entities" array as well as a "hashmap" array.
function PhysicsEngine(game) {
this.game = game;
this.entities = [];
this.hashmap = createArray(32, 32);
}
for(var i = 0; i < this.entities.length; i++) {
//Array item may not be a Simulateable Entity
//this.entities[i].simulatePhysics(this);
this.entities[i].ResolveCollisions();
this.entities[i].Move();
hmx = Math.round(Math.abs(this.entities[i].x/32));
hmy = Math.round(Math.abs(this.entities[i].y/32));
if(!logged) {
console.log(this.hashmap);
console.log(this.entities[i]);
console.log(i, hmx, hmy);
console.log(this.hashmap[hmx], this.hashmap[hmy]);
logged = true;
}
if(!Array.isArray(this.hashmap[hmx])) {
this.hashmap[hmx] = [];
if(!Array.isArray(this.hashmap[hmx][hmy])) {
this.hashmap[hmx][hmy] = [];
}
}
this.hashmap[hmx][hmy].push(this.entities[i]);
}
I think that this code:
this.hashmap[hmx] = [];
if(!Array.isArray(this.hashmap[hmx][hmy])) {
this.hashmap[hmx][hmy] = [];
}
is not correct. In particular, the "if" condition tests whether this.hashmap[hmx][hmy] is an array. The problem is that this.hashmap[hmx]=[] (as you have set one line before), so this.hashmap[hmx][hmy] is undefined and javascript throws an error "Undefined is not an object".
Maybe is this the problem?

Categories

Resources