before I use only nextJs everything is good to go but after I try to use recoil and I try to assign new value to array object by using .map() but the error show up
Cannot assign to read only property
Here is my example Array object
const [allData, setAllData] = useRecoilState(
allDataStatte
);
Here is example state AllData
const allData = [
{
id:1,
value:"test1"
},
{
id:2,
value:"test2"
}
]
Here is my code
const edit = (listId, value) => {
allData.map((data) => {
if (data.id === listId) {
data.value = value;
}
});
};
example I want to call edit funcion like this
edit(1,"newTitle1")
I want my new allData output look like this
const data = [
{
id:1,
value:"newTitle1"
},
{
id:2,
value:"test2"
}
]
I have read someone told that I have to use .slice() to create new object but still not use how to use slice with an array object
Here is what you need to do,
const [allData, setAllData] = useRecoilState(allDataState);
const edit = (listId : number, value : string) => {
let newAllData = allData.map((data) => {
let newData = {...data};
if (data.id === listId) {
newData.value = value;
}
return newData;
});
setAllData (newAllData);
};
edit(1, 'new value 1');
Noticed, newAllData is a new array. Also newData is a new object constructed from data.
it's because of atom in recoil you have to re create object array and then setState again by using _clondeep or slice
Related
Below is my sample data from which I want to extract the string present inside ResponseVariations array's object : CriterionExpression
Articles":[
"ResponseVariations":[
"CriterionExpression":"User: internal AND Country: CA"
]
]
Code Snippet:
function getChannel(agent){
const channelInfo = agent.Articles;
channelInfo.forEach((ResponseVariations) => {
if(channelInfo.values(CriterionExpression)!=="DEFAULT_SELECTION")
var iterator = channelInfo.values();
console.log(iterator.next().value);
});
But the above criteria is not fitting well to extract information of those criteria in which the String is not DEFAULT_SELECTION.
Any suggestions how to traverse this array object's value ?
The below code worked in order to fetch the key:
const _dir1 = path.resolve(__dirname, `../`);
const _config1 = JSON.parse(fs.readFileSync(path.resolve(_dir, "./export.4862052732962492282_2.json"), "utf-8"));
const filteredArr = {};
_config1.Articles.forEach(el => {
if (el.ResponseVariations && el.ResponseVariations.length > 1 ) {
el.ResponseVariations && el.ResponseVariations.forEach((rv) => {
if(rv.CriterionExpression !== 'DEFAULT_SELECTION') {
console.log('not default', rv);
filteredArr[rv.CriterionExpression]= rv.Text;
project['data']['supportedChannels'].push(filteredArr);
}
})
Despite the fact that the title seems difficult, let me give you a simple example.
I have an object.
{
name:"Ethan"
pets:{cat:"joline",dog:"Momo",bird"Mimi"}
}
My goal is to push the values of the array to the object.
{
name:"Ethan",
cat:"joline",
dog:"Momo",
bird"Mimi"
}
The question is simple and I believe you can approach it in a clever way, thanks.
Simple way to do this is to combine pets object and other properties using spread operator and then delete the pets from result.
const data = {
name:"Ethan",
pets:{cat:"joline",dog:"Momo",bird:"Mimi"}
}
const res = {...data, ...data.pets};
delete res.pets;
console.log(res);
If you want to do it in a functional way you can use the following approach.
Wrap the original element in a array.
Apply map on it.
Destructure pets from the object and store the rest of the properties in other variable.
Return a new object where you spread the rest object and pets.
const data = {
name:"Ethan",
pets:{cat:"joline",dog:"Momo",bird:"Mimi"}
}
const res = [data].map(({pets, ...rest}) => ({...rest, ...pets}))[0]
console.log(res)
The simplest and cleanest way to obtain desired result with destructuring.
const obj = {
name: "Ethan",
pets: { cat: "joline", dog: "Momo", bird: "Mimi" },
};
const { name, pets } = obj;
const result = { name, ...pets };
console.log(result);
Iterating through the elements and values in the object. And spreading the value into the return object
const data = {
name: "Ethan",
pets: {
cat: "joline",
dog: "Momo",
bird: "Mimi"
}
};
function flatten(data) {
let result = {};
for (const key in data) {
const value = data[key];
if (typeof value != 'object') result[key] = value;
else result = { ...result, ... flatten(value)}
}
return result;
}
console.log(flatten(data));
As others have said, this is straightforward with object destructuring. I think it's cleanest when you use parameter destructuring. So a simple function like this should do it:
const promotePets = ({pets, ...rest}) =>
({...rest, ...pets})
const obj = {name: "Ethan", pets: { cat: "joline", dog: "Momo", bird: "Mimi" }};
console .log (promotePets (obj))
I'm doing this:
const rawValues = this.filterList.map(s => {
return {[s.filterLabel]: s.selectedOption}
});
filterList variable has this type:
export interface SelectFilter {
filterLabel: string;
options: Observable<any>;
selectedOption: string;
}
now rawValues is being mapped like this:
[
{filterLabel: selectedOption},
{filterLabel: selectedOption},
{filterLabel: selectedOption}
]
so it's an array of my new objects,
but what I want is a SINGLE object, so the end result should be:
{
filterLabel: selectedOption,
filterLabel: selectedOption,
filterLabel: selectedOption
}
NOTE that "filterLabel" will always be unique.
What do I need to change in the map() ?
For this use case, a map isn't needed as it would result in creating a new array which is unnecessary. Just iterate over each element in the array then assign each filterLabel as a new key to the obj like this:
const obj = {};
this.filterList.forEach(s => {
obj[s.filterLabel] = s.selectedOption;
});
console.log(obj);
I think this is use case for array reduce:
let result =
[{filterLabel: 'label1', selectedOption: 'option1'}, {filterLabel: 'label2', selectedOption: 'option2'}, {filterLabel: 'label3', selectedOption: 'option3'}, {filterLabel: 'label4', selectedOption: 'option4'} ]
.reduce(function(previousValue, currentValue, index, array) {
return {
[currentValue.filterLabel]: currentValue.selectedOption,
...previousValue }
}, {});
console.log(result);
More details:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
You shouldn't do anything to get the result you want. First, when you run a map on the array, a new array is returned. To change that you would have to re-write the map function with your own. Technically possible, but not recommended.
Second, you cannot have multiple properties on an object that have the exact same name. I know of no way around this.
You might be able to do something like what you want with a loop:
let rawValues = {};
for (i = 0; i < filterList.length; i++) {
rawValues[`${filterList[i].filterLabel}${i}`] = filterList[i].selectedOption;
}
Which should give you something like this:
{
filterLabel1: selectedOption,
filterLabel2: selectedOption,
filterLabel3: selectedOption
}
Can you guarantee that the filterLabel will always be unique?
var result = {};
this.filterList.forEach(s => {
result[s.filterLabel] = s.selectedOption;
});
you can use reduce to achieve the same result:
var result = this.filterList.reduce((prev, next) => {
return {...prev, [next.filterLabel]:next.selectedOption}
}, {});
I have an API that response JSON data like this-
{
"unitcode":"apple",
"description":"bus",
"color":"red",
"intent":"Name 1"
}
I want to change like this-
{
"Value1":"apple",
"Value2":"bus",
"value3":"red",
"value4":"sale"
}
Presently, I can code to rename single key but i want some code to replace all key in one shot. my code like this-
request(baseurl)
.then( body => {
var unit = JSON.parse(body);
unit.intent = "sales"
unit.value1 = unit.unitcode
delete unit.unitcode;
console.log(unit)
console.log(unit.Value1)
var unit2 = JSON.stringify(unit)
// let code = unit.description;
conv.ask('Sales is 1 million metric tonnes ' + unit2);
})
please help me out on this and please little elaborate also to learn something new. thanks
Create a Map of original key to new key (transformMap). Convert the object to pairs of [key, value] with Object.entries(), iterate with Array.map() and replace the replacement key from the Map (or the original if not found). Convert back to an object with Object.toEntries():
const transformMap = new Map([
['unitcode', 'Value1'],
['description', 'Value2'],
['color', 'Value3'],
['intent', 'Value4']
]);
const transformKeys = obj =>
Object.fromEntries(
Object.entries(obj)
.map(([k, v]) => [transformMap.get(k) || k, v])
);
const obj = {
"unitcode": "apple",
"description": "bus",
"color": "red",
"intent": "Name 1"
};
const result = transformKeys(obj)
console.log(result)
If you know the object structure and it is constant, you could just use destructing like so.
const data = {
"unitcode":"apple",
"description":"bus",
"color":"red",
"intent":"Name 1"
};
// If the object is fixed and the fields are known.
const mapData = ({ unitcode, description, color, intent }) => ({
Value1: unitcode,
Value2: description,
Value3: color,
Value4: intent
});
console.log(JSON.stringify(mapData(data)));
But if the object has an unknown number of properties:
const data = {
"unitcode":"apple",
"description":"bus",
"color":"red",
"intent":"Name 1"
};
// If the object is fixed and the fields are known.
const mapData = (data) => {
return Object.keys(data).reduce((a,v,i) => {
a[`Value${i+1}`] = data[v];
return a;
}, {});
};
console.log(JSON.stringify(mapData(data)));
You can edit the array to have the values you need
let i=0,j=0,unit1={};
let unit = JSON.parse(body);
let unit3=["val1","val2","val3","val4"]
let unit5=Object.values(unit);
for(let key in unit){
unit1[unit3[i++]]=unit5[j++];
}
var unit2 = JSON.stringify(unit1)
console.log('Sales is 1 million metric tonnes \n' + unit2);
//Sales is 1 million metric tonnes
//{"val1":"apple","val2":"bus","val3":"red","val4":"Name 1"}
Well your target is to modify the keys and retain the value
In that context, you can iterate through your data. To dynamically generate keys as Value1, Value2, etc, we will append Value with iteration index which is going to be unique always.
const modifyInput = (input) => {
const modifiedInput = {}
Object.values(input).forEach((item, index) => {
modifiedInput[`Value${index + 1}`] = item
})
return modifiedInput
}
Use this function, pass your input and get your desired result
I am building an typescirpt dictionary like that:
const skills = x
.map(y => y.skills)
.flat(1)
.map(z => {
return { [z.id]: { skill: z } };
});
That is the array I am getting by the code above:
{ 7ff2c668-0e86-418a-a962-4958262ee337: {skill: {…}} }
{ c6846331-2e11-45d6-ab8d-306c956332fc: {skill: {…}} }
{ 0fc0cb61-f44d-4fd0-afd1-18506380b55e: {skill: {…}} }
{ 36dc0b74-84ee-4be2-a91c-0a91b4576a21: {skill: {…}} }
Now the issue is I can not access the dictionary by key:
const id = '7ff2c668-0e86-418a-a962-4958262ee337';
const one = myArr.find(x => x === id); // returns undefined
const two = myArr[id]; // returns undefined
Any ideas how to fix?
You can use Object.keys() to get the key of each of your objects. In your case the key of each of your objects is its id. Then use that to check whether it equals x (you search id).
See example below:
const myArr = [
{"7ff2c668-0e86-418a-a962-4958262ee337": {skill: 1}},
{"c6846331-2e11-45d6-ab8d-306c956332fc": {skill: 2}},
{"0fc0cb61-f44d-4fd0-afd1-18506380b55e": {skill: 3}},
{"36dc0b74-84ee-4be2-a91c-0a91b4576a21": {skill: 4}}],
id = "36dc0b74-84ee-4be2-a91c-0a91b4576a21",
one = myArr.findIndex(x => Object.keys(x)[0] === id); // the index of the object which has the search id as its key.
myArr[one] = {newKey: "newValue"}; // set the index found to have a new object
console.log(myArr);
You are now creating an array of objects. I suggest you create an object instead, with your ids as keys
Example:
const skills = x
.map(y => y.skills)
.flat(1)
.reduce((acc, z) => {
acc[z.id] = z;
return acc;
}, {});
Your myArr is going to look something like:
{
'7ff2c668-0e86-418a-a962-4958262ee337': {...}
'c6846331-2e11-45d6-ab8d-306c956332fc': {...},
'0fc0cb61-f44d-4fd0-afd1-18506380b55e': {...},
'36dc0b74-84ee-4be2-a91c-0a91b4576a21': {...}
}
You can then access it the way you intended:
const skill = myArr['7ff2c668-0e86-418a-a962-4958262ee337'];
make use of map that can help,
Map is a new data structure introduced in ES6. It allows you store key-value pairs similar to other programming languages e.g. Java, C#.
let map = new Map();
const skills = x
.map(y => y.skills)
.flat(1)
.map(z => {
map.set(z.Id, { skill: z })
return map;
});
//Get entries
amp.get("7ff2c668-0e86-418a-a962-4958262ee337"); //40
//Check entry is present or not
map.has("7ff2c668-0e86-418a-a962-4958262ee337"); //true