How do I set property name to variable? - javascript

I am working on an online class, for which we have to build a list tracker application using react. I have had issues when trying to set the state of one of my classes. In this state I have a variable which is equal to an object. I am attempting to variably set both the name and value of this object, however I was uncertain on how to set the name variably.
let name = this.props.idName;
this.setState((prevState) => {
return {
newItem: { name: item}
};
}, () => {
this.props.addItem(this.state)
});
As you can see, I try to set the key in this object equal to the variable name, however this just sets it to the value of name rather than the value of the the name variable.

You can try this. Just enclose the name in square brackets. More on this https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names.
let name = this.props.idName;
this.setState((prevState) => {
return {
newItem: { [name]: item}
};
}, () => {
this.props.addItem(this.state)
});
var k = "key";
var obj = {[k]: "VALUE"}
console.log(obj);

You can regard objects as dictionaries:
$ node
> let name = 'Nyan'
undefined
> let omg = { newItem: {} }
undefined
> omg
{ newItem: {} }
> omg['newItem'][name] = 'item' // note the quotes in this statement
'item'
> omg
{ newItem: { Nyan: 'item' } }

Related

Vue JS run computed property for each key value of another computed property

I have a computed property:
relateditems () {
return this.related.find((relation) => {
return relation.id === this.currentItem.id
})
},
with the following output:
relateditems:Object
-KQ1hiTWoqAU77hiKcBZ:true
-KQ1tTqLrtUvGnBTsL-M:true
id:"-KQ1if2Zv3R9FdkJz_1_"
I'm trying to create another computed property that then loops through the relateditems object and finds a relation with the matching ID for the first two keys.
The following doesn't work but I think it gives the idea:
relateditemsdata () {
let test = []
for (var key in this.relateditems) {
this.items.find((relateditem) => {
relateditem.id === key.id
test.push(relateditem)
})
}
return test
}
I think calling a computed property in another one is not a good way, so you could add a watcher property in order to watch the first computed property and update a data object property based on that one like :
data() {
return {
relateditemsdata: [],
}
},
computed: {
relateditems() {
return this.related.find(relation => {
return relation.id === this.currentItem.id
})
},
},
watch: {
relateditems(val) {
for (var key in this.relateditems) {
this.items.find(relateditem => {
relateditem.id === key.id
relateditemsdata.push(relateditem)
})
}
},
},
Seems like your problem is not related to Vue.
Your key.id is undefined in the for..in loop. You would have to use this.relateditems[key] to access the value or just key to access the key. Since you do not want filter your other array for the 'id' key, you should also filter your object-keys first.
E.g.
relatedItems() {
return this.related.find((item) => {
return this.item.id == this.currentItem.id;
});
} // returns first objects with the same id
relatedItemsData() {
// grabs all keys except 'id'
const keys = Object.keys(this.relateditems).filter((key) => key != 'id');
this.items.filter((item) => {
return keys.indexOf(item.id) != -1; // checks if item.id is inside the keys-array
});
} // returns again array of objects;
Instead of a nested loop, you can also just use the Array.prototype.filter() function, like above.

Remove an key value from an object in react js

I have an object in the state ,
this.state = {
selectedValue: {}
}
Now,Here I am adding a property to this by object in the following way
if (e.currentTarget.checked) {
this.setState({
selectedType: {
...this.state.selectedType,
[resumeId]: type
}
})
Now, In else part I have to remove the property with the matching resumeId.
Or Do I need to create an array of objects ? I am kind of confused here.
Can any one help me with this ?
The best way to do this is add a prefix to your resumId:
if (e.currentTarget.checked) {
this.setState({
selectedType: {
...this.state.selectedType,
[`resume-${resumeId}`]: type
}
})
Now, you have a way to identify your resumeId. Then loop through your selectedType state and remove resumeId. You can do it as the following:
let selectedType = this.state.selectedType;
for (let key in selectedType) {
if (key.indexOf('resume') !== -1) {
delete selectedType[key]
}
}
this.setState({selectedType})
if (e.currentTarget.checked) {
this.setState({
selectedType: {
...this.state.selectedType,
[resumeId]: type
}
}) else {
const selectedType = {
...this.state.selectedType
}
delete selectedType[resumeId];
this.setState({
selectedType
});
}
You can delete the resumeId from the object iself.
Use Object destructuring to acheive this cleanly:
if (e.currentTarget.checked) {
this.setState({
selectedType: {
...this.state.selectedType,
[resumeId]: type
}
})
} else {
// Destructure the resumeId and rest properties
const { resumeId, ...rest} = this.setState.selectedType;
// Only assign the rest properties now
this.setState({ selectedType: ...rest });
}
Update:
To check if all values are same:
const data = { "a": "11", "b": "11", "c":"12", "d" : "11" };
const objectValues = Object.values(data);
// Check first value with every value
const isEveryValueSame = objectValues.every(x => x === objectValues[0]);
console.log(isEveryValueSame);

Object push Firebase, how to remove key names from pushed items

I have this Object.key code that pushes all items:
const cloned_items = [];
Object.keys(items).sort().map(key => {
let item = {
[`item-${uid}`]: {
item: false
}
}
cloned_items.push({ ...item });
});
database.ref('/app/items').update({
...cloned_items
})
but this produces following result:
"0" : {
"timeslot-87dah2j" : {
item: false
}
},
"1" : {
"timeslot-7s1ahju" : {
item: false
}
}
instead of:
"timeslot-87dah2j" : {
item: false
},
"timeslot-7s1ahju" : {
item: false
}
any idea ?
It seems like you want to create a plain object, not an array.
In that case:
const cloned_items = Object.assign(...Object.keys(items).map(uid =>
({ [`item-${uid}`]: {item: false} })
));
NB: sorting is of no use when creating an object -- its keys are supposed to have no specific order.
You're creating an array of objects. Seems like you want to use .reduce() to create a single object from the array.
const cloned_items = Object.keys(items).sort().reduce((obj, key) =>
Object.assign(obj, { [`item-${uid}`]: { item: false } })
, {});
Your code doesn't show where uid is coming from, but I assume you meant key there, along with timeslot instead of item.
You may find Object.defineProperty to be cleaner, though you'll need to set up the property descriptor as you want it.
const cloned_items = Object.keys(items).sort().reduce((obj, key) =>
Object.defineProperty(obj, `item-${uid}`, {value:{item: false}})
, {});

React: Calling filter on Object.keys

A React component is passed a state property, which is an object of objects:
{
things: {
1: {
name: 'fridge',
attributes: []
},
2: {
name: 'ashtray',
attributes: []
}
}
}
It is also passed (as a router parameter) a name. I want the component to find the matching object in the things object by comparing name values.
To do this I use the filter method:
Object.keys(this.props.things).filter((id) => {
if (this.props.things[id].name === this.props.match.params.name) console.log('found!');
return (this.props.things[id].name === this.props.match.params.name);
});
However this returns undefined. I know the condition works because of my test line (the console.log line), which logs found to the console. Why does the filter method return undefined?
Object.keys returns an array of keys (like maybe ["2"] in your case).
If you are interested in retrieving the matching object, then you really need Object.values. And if you are expecting one result, and not an array of them, then use find instead of filter:
Object.values(this.props.things).find((obj) => {
if (obj.name === this.props.match.params.name) console.log('found!');
return (obj.name === this.props.match.params.name);
});
Be sure to return that result if you use it within a function. Here is a snippet based on the fiddle you provided in comments:
var state = {
things: {
1: {
name: 'fridge',
attributes: []
},
2: {
name: 'ashtray',
attributes: []
}
}
};
var findThing = function(name) {
return Object.values(state.things).find((obj) => {
if (obj.name === name) console.log('found!');
return obj.name === name;
});
}
var result = findThing('fridge');
console.log(result);
You need to assign the result of filter to a object and you get the result as the [id]. You then need to get the object as this.props.things[id]
var data = {
things: {
1: {
name: 'fridge',
attributes: []
},
2: {
name: 'ashtray',
attributes: []
}
}
}
var name = 'fridge';
var newD = Object.keys(data.things).filter((id) => {
if (data.things[id].name === name) console.log('found!');
return (data.things[id].name === name);
});
console.log(data.things[newD]);

update nested object with (ES6) computed property name

In my case, I'm using React.js and I would like to dynamically update the values in the deployOptions object.
For example -
initial state looks like:
getInitialState() {
return {
deployOptions: {
config: null,
action: 'deploy',
env: 'qa'
}
}
}
Obviously this is not correct - but this is what I'm trying to achieve
configOptionChange(option) {
// option -> { key: 'env', value: 'prod' }
this.setState({
[deployOptions.option.key]: option.value
});
}
so that my state would then be
{
deployOptions: {
config: null,
action: 'deploy',
env: 'prod' // only this changes
}
}
It's not especially pretty, but I think this is the best you can do with ES6:
configOptionChange({ key, value }) {
this.setState({
...this.state,
deployOptions: {
...this.state.deployOptions,
[key]: value
}
});
}
It's basically equivalent to your own Object.assign solution but using the ES6 spread (...) operator (and argument destructuring for good measure).
Here's a second option that isn't as clever but feels a little cleaner to me:
configOptionChange({ key, value }) {
const { deployOptions: prevDeployOptions } = this.state;
const deployOptions = { ...prevDeployOptions, [key]: value };
this.setState({ ...this.state, deployOptions });
}
Just like these are nested objects, you can nest ES6 Computed Property Name like this:
[yourNestedObject]: {...yourNestedObject, [nestedObjectProperty]: value}
Here is an example function that will update an object's properties and the properties of nested objects. Where prop is the property to change, value is the value to assign, and propObj is the name of your nested object. I used useState hook for this.
const [obj, setObj] = useState({
prop1: '',
prop2: '',
nestedObj: {
prop1: '',
prop2: ''
}
});
const updateObj = (prop, value, propObj=false) => {
if (propObj) {
setObj({...obj, [propObj]: {...obj[propObj], [prop]: value}})
} else {
setObj({...obj, [prop]: value})
}
}
I think this might do the trick - but if anyone has a better solution?
configOptionChange(option) {
this.setState({
deployOptions: Object.assign({}, this.state.deployOptions, {[option.key]: option.val})
});
}
I'm using reduce to update the state of a component from a passed string of path properties:
handleChangeNested(event) {
const target = event.target; //an <input /> tag
let newState = { ...this.state };
let valuePath = target.name.split('.'); //the input's name is the the keys of the state object like 'group1.input1'
// Move down in the state object until we get to the 'bottom' property and change its value
// If the object does not have the properties we create them on the fly
valuePath.reduce((acc, key, index, path) => {
if (index === path.length - 1) {
acc[key] = target.value;
}
acc[key] = acc[key] || {};
return acc[key];
}, newState);
this.setState(newState);
}
The best solution I know would be to use "immutable" library.
configOptionChange(option) {
// option -> { key: 'env', value: 'prod' }
this.setState(state => setIn(state, ['deployOptions', option.key], option.value));
}

Categories