that is suppose to come 1,2,3 but coming 3,3,3, how to fix that ?
Javascript updating automatically
let test = [ { id: 1 } ];
let test2 = [
{ id: 1 },
{ id: 2 },
{ id: 3 }
];
let x = []
test2.forEach(i => {
test[0].id = i.id;
x.push(test[0])
});
console.log(x)
Since you are pushing the same object 3 times and at the end of the loop it will have 3 reference of the same object i.e test[0]
You can use spread syntax to copy all properties of object
let test = [{ id: 1 }];
let test2 = [{ id: 1 }, { id: 2 }, { id: 3 }];
let x = [];
test2.forEach((i) => {
test[0].id = i.id;
x.push({ ...test[0] });
});
console.log(x);
Use the spread operator:
x.push({ ...test[0] })
Basically you need to shallow clone the array because it's an object; forEach will create 3 references to the same test[0] object at the beginning of the call.
You are passing in the same reference to the array everytime. You are updating that same value too i.e., test[0].
So in the end, you have an array with three elements, all 3 pointing to the same object whose id property you have updated to the final value - test2[2].id.
You can directly push in an object with the correct id property. You will not need an extra test array as you are creating your object and pushing them on the go.
let test = [ { id: 1 } ];
let test2 = [
{ id: 1 },
{ id: 2 },
{ id: 3 }
];
let x = []
test2.forEach(i => {
x.push({ id : i.id })
});
console.log(x)
Related
So I currently have a bunch of objects inside an array like below. However, I'm now trying to write a function that allows me to add another key|value into the object that was added last.
My current idea is using the arrayname.length - 1 to work out the position of the object within the array.
Would I need to create a temporary array to store the new object and then set (tempArray = oldArray) at the end of the function or would I concatinate them both?
const state = [
{
userId: 1,
},
{
Name: name,
},
{
age: 52,
},
{
title: "et porro tempora",
}]
this is the current code
let objects = [];
const addParent = (ev) =>{
ev.preventDefault();
// getting the length of the objects array
let arrayLength = objects.length;
// if the length of the array is zero - empty or one then set it to default zero
// else if there is objects stored in the array minus 1 to get the array position
if(arrayLength <= 0){
arrayLength = 0;
}else{
arrayLength = objects.length - 1;
}
//make a temporary array to be able to push new parent into an existing object
var tempObjects = []
for (var index=0; index<objects.length; index++){
}
//create a new parent object key : value
let parent = {
key: document.getElementById('key').value,
value: document.getElementById('value').value
}
//push parent object key and value into object
//objects.push(parent);
}
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('btn1').addEventListener('click', addParent);
});
There are multiple ways to do this.
Try this one
var objects = [{
name: "1"
}];
const addParent = (ev) => {
let parent = {
key: "some value",
value: "some value"
}
objects = Array.isArray(objects) ? objects : [];
let lastObjectIndex = objects.length - 1;
lastObjectIndex = lastObjectIndex > -1 ? lastObjectIndex : 0
objects[lastObjectIndex] = { ...objects[lastObjectIndex],
...parent
}
}
I think You want to add new value to last object of the array
Method 1
const state = [
{
userId: 1,
},
{
Name: name,
},
{
age: 52,
},
{
title: "et porro tempora",
}]
state[state.length - 1].newKey = "value"
console.log(state)
Method 2
const state = [
{
userId: 1,
},
{
Name: name,
},
{
age: 52,
},
{
title: "et porro tempora",
}]
// 1st method
state[state.length - 1] = {
...state[state.length - 1] ,
newKey : "value"
}
console.log(state)
You can probably use something like this:
const a = [
{ "a" : "a" },
{ "b" : "b" }
]
const c = a.map((obj, index) => {
if (index === a.length -1) {
return { ...obj, newProp: "newProp" }
}
return obj;
});
console.log(c)
This will add property on the last object using spread operator, you can look it up if you are new to JS but basically it will retain all the existing property and add the newProp to the object
This question already has answers here:
Accessing an object property with a dynamically-computed name
(19 answers)
Closed 3 years ago.
I have an object like
let arr = [
{
title: "hello",
pivot: {
id: 1,
bid: 3
}
},
{
title: "home",
pivot: {
id: 2,
bid: 3
}
},
{
title: "nice",
pivot: {
id: 3,
bid: 3
}
}
];
I want to access its property dynamically. I want to access id property's value from pivot from first object of this array. And it's should be dynamic.
This is what I tried already.
let s = "0.pivot.id"
let res = arr[s]
console.log(res)
I can access by arr[0].pivot.id but this is not my case. I want it dynamically.
You can split the string and loop through it updating a variable refrencing the last found value :
let arr = [
{
title: "hello",
pivot: {
id: 1,
bid: 3
}
},
{
title: "home",
pivot: {
id: 2,
bid: 3
}
},
{
title: "nice",
pivot: {
id: 3,
bid: 3
}
}
];
let s = "0.pivot.id";
const getValue = (arr, str) => {
let ref = arr;
const keys = str.split(".");
keys.forEach(k => {
ref = ref[k];
});
return ref;
};
const result = getValue(arr, s);
console.log(result);
what you tried would give you a property which key was 0.pivot.id. So it might work if your object looks like this
{
'0.pivot.id': 'something'
}
There is no native way to access deeper level of an object dynamically. You would need to use recursion for that.
It's quite easy though, You could simply split your key into an array of keys and then recursively check your array for matching keys.
let arr = [
{
title: "hello",
pivot: {
id: 1,
bid: 3
}
},
{
title: "home",
pivot: {
id: 2,
bid: 3
}
},
{
title: "nice",
pivot: {
id: 3,
bid: 3
}
}
];
function getDynamicKeyRecursively(object, key) {
// the key needs to be an array,
// if it isn't, we split it into an array
if(typeof key === 'string') {
key = key.split('.');
}
// we get the current value of the current object
let currentValue = object[key[0]];
// remove the first index of the key
key.shift()
// if the current value is an object or an array, we recursively check this value for what we want
// otherwise, we return the value.
return Array.isArray(currentValue) || typeof currentValue === 'object' ? getDynamicKeyRecursively(currentValue, key) : currentValue;
}
console.log(getDynamicKeyRecursively(arr, '1.pivot.id'));
I have an array of objects:
const array = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4 }
];
and I need to add another entry to it, but it needs to be placeable within any location in the array. So for example:
array.push({ id: 5, after_id: 2 }); and this should place the new entry between ids 2 and 3. Is there some standard way of doing this?
#p.s.w.g Has posted what is probably the best solution in a comment already, but I thought I'd post my original solution here as an answer now this is reopened.
You can use some to iterate through the array until the correct index is found, then you can slice the array and insert the item at the relevant index:
const arrayTest = [{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
}
];
const insertAfterId = (array, item, idAfter) => {
let index = 0;
array.some((item, i) => {
index = i + 1;
return item.id === idAfter
})
return [
...array.slice(0, index),
item,
...array.slice(index, array.length),
];
};
const result = insertAfterId(arrayTest, {
id: 6
}, 2)
console.dir(result)
I have a counter app that simply increment its component state.
This is the sandbox app link: https://codesandbox.io/s/5mxqzn001k .
You can see the counters.indexOf(counter) on file src/components/counters.jsx at line 30 which finds the target object and set its new value and it worked.
handleIncrement = counter => {
const counters = [...this.state.counters];
const index = counters.indexOf(counter);
counters[index] = { ...counter };
counters[index].value++;
this.setState({ counters });
};
I've tried to duplicate that function that finds the target object in vanilla js approach in this link:
https://repl.it/#stoic25/TrickyForsakenLamp but I'm wondering why it doesn't work?
const state = {
counters: [
{ id: 1, value: 4 },
{ id: 2, value: 0 },
{ id: 3, value: 0 },
{ id: 4, value: 0 }
]
};
let myArr = state.counters.indexOf({ id: 4, value: 0 });
console.log( myArr );
// returns -1
Is ReactJS's "indexOf" function behavior is different from vanilla js?
Objects are only equal to each other if they refer to the exact same instance of the object. If you pass the reference of object in the array to indexOf function, it will find the index by comparing reference but if you pass new object, it wont compare each key of the object to find the index of of object in the array. For your second example, try this and see it will work:
const state = {
counters: [
{ id: 1, value: 4 },
{ id: 2, value: 0 },
{ id: 3, value: 0 },
{ id: 4, value: 0 }
]
};
let obj=state.counters[3]
let myArr = state.counters.indexOf(obj);
console.log( myArr );
The counter object passed to handleIncrement function in your first react example, is a reference to an object in you state.counters hence it returns its index.
See jsfiddle here: https://jsfiddle.net/remenyLx/2/
I have data that contains objects that each have an array of images. I want only the first image of each object.
var data1 = [
{
id: 1,
images: [
{ name: '1a' },
{ name: '1b' }
]
},
{
id: 2,
images: [
{ name: '2a' },
{ name: '2b' }
]
},
{
id: 3
},
{
id: 4,
images: []
}
];
var filtered = [];
var b = data1.forEach((element, index, array) => {
if(element.images && element.images.length)
filtered.push(element.images[0].name);
});
console.log(filtered);
The output needs to be flat:
['1a', '2a']
How can I make this prettier?
I'm not too familiar with JS map, reduce and filter and I think those would make my code more sensible; the forEach feels unnecessary.
First you can filter out elements without proper images property and then map it to new array:
const filtered = data1
.filter(e => e.images && e.images.length)
.map(e => e.images[0].name)
To do this in one loop you can use reduce function:
const filtered = data1.reduce((r, e) => {
if (e.images && e.images.length) {
r.push(e.images[0].name)
}
return r
}, [])
You can use reduce() to return this result.
var data1 = [{
id: 1,
images: [{
name: '1a'
}, {
name: '1b'
}]
}, {
id: 2,
images: [{
name: '2a'
}, {
name: '2b'
}]
}, {
id: 3
}, {
id: 4,
images: []
}];
var result = data1.reduce(function(r, e) {
if (e.hasOwnProperty('images') && e.images.length) r.push(e.images[0].name);
return r;
}, [])
console.log(result);
All answers are creating NEW arrays before projecting the final result : (filter and map creates a new array each) so basically it's creating twice.
Another approach is only to yield expected values :
Using iterator functions
function* foo(g)
{
for (let i = 0; i < g.length; i++)
{
if (g[i]['images'] && g[i]["images"].length)
yield g[i]['images'][0]["name"];
}
}
var iterator = foo(data1) ;
var result = iterator.next();
while (!result.done)
{
console.log(result.value)
result = iterator.next();
}
This will not create any additional array and only return the expected values !
However if you must return an array , rather than to do something with the actual values , then use other solutions suggested here.
https://jsfiddle.net/remenyLx/7/