I am having a newbie question and I have tried to read the manuals over and over and cannot figure it out.
so I have this code:
export function editSerier(data, products) {
return (dispatch) => {
const filteredProducts = Object.assign(
...Object.keys(products)
.filter(key => products[key].Artikelgrupp === data.Artikelgrupp)
.map(k => ({
[k]: products[k]:{
Beskrivning: data.Beskrivning,
kategori: data.kategori,
status: data.status,
synas: data.synas,
tillverkare: data.tillverkare,
titel: data.titel}
})
})
console.log(filteredProducts)
}
}
Where I want to filter the incoming object products by "Artikelgrupp" and then modify the existent properties of the remaining products with properties from "data".
However this code does not let me run it.
Does someone have any idea?
UPDATE:
just solved it by merging both objects
const filteredProducts = Object.assign(
...Object.keys(products)
.filter(key => products[key].Artikelgrupp === data.Artikelgrupp)
.map(k => ({
[k]: {...products[k], ...data}
}))
)
You have invalid JavaScript. If you want a nested object, you need { something: { } } and if you want to use a computed property name, you need to surround it with [].
So, this will work
export function editSerier(data, products) {
return dispatch => {
const filteredProducts = Object.assign(
...Object.keys(products)
.filter(key => products[key].Artikelgrupp === data.Artikelgrupp)
.map(k => ({
[k]: {
[products[k]]: {
Beskrivning: data.Beskrivning,
kategori: data.kategori,
status: data.status,
synas: data.synas,
tillverkare: data.tillverkare,
titel: data.titel
}
}
}))
);
console.log(filteredProducts);
};
}
If I understand correctly, you are wanting to obtain a single object which:
excludes all value objects of products where a Artikelgrupp field does not match data.Artikelgrupp and,
the specific fields Beskrivning, kategori, etc, from your data object are merged/copied into the product values of the resulting object
One solution to this would be as
/* Extract entry key/value pairs from products object */
Object.entries(products)
/* Reduce entry pairs to required object shape */
.reduce((result, [key, value]) => {
/* Substitute for prior filter step. Avoid overhead of array copy
between prior filter and this reduction. */
if(value.Artikelgrupp !== data.Artikelgrupp) {
return result;
}
/* Update result object, "upserting" fields of data object into
existing product value, for this reduce iteration */
return {
...result,
[ key ] : {
...value,
Beskrivning: data.Beskrivning,
kategori: data.kategori,
status: data.status,
synas: data.synas,
tillverkare: data.tillverkare,
titel: data.titel
}
};
}, {})
Related
I am storing the prev values in an array of objects, for example [{ActFollow: 'BlN'},{ActSendGift: 'BlY'},{ActSubscribe: 'BlY'}] I want to store the key and values in an object like this {ActFollow: 'BlN',ActSendGift: 'BlY', ActSubscribe: 'BlY'}
const [activityTypes, setActivityTypes] = useState<any>([]); // state
.then((response: any) => {
setActivityTypes((oldArray: any) => [
...oldArray,
{[item.channelSettingTypeId]: response.settingValue},
]);
});
How about this, if the nesting is only one level deep
const data = [{ActFollow: 'BlN',ActSendGift: 'BlY', ActSubscribe: 'BlY'}]
console.log([{...data[0],"hey" : "world"}])
const items = [{ActFollow: 'BlN'},{ActSendGift: 'BlY'},{ActSubscribe: 'BlY'}]
let object = {}
items.forEach(item=>{
for (const [key, value] of Object.entries(item)) {
object = {
...object,
[key]: value
}
}
})
console.log(object)
You can use this simple idea in React also. Just hold on the default empty object in state and update the object.
You can reduce the array of objects into an object.
You can do it by spreading (...) the current object into the resultant object, as shown below:
const
arrOfObjs = [{ ActFollow: "BlN" }, { ActSendGift: "BlY" }, { ActSubscribe: "BlY" }],
obj = arrOfObjs.reduce((res, o) => ({ ...res, ...o }), {});
console.log(obj);
You can also do it using Object.assign, as shown below:
const
arrOfObjs = [{ ActFollow: "BlN" }, { ActSendGift: "BlY" }, { ActSubscribe: "BlY" }],
obj = arrOfObjs.reduce((res, o) => Object.assign(res, o), {});
console.log(obj);
Use Spread Operator
const items = [{ActFollow: 'BlN', Anurag: 26},{ActSendGift: 'BlY'},{ActSubscribe: 'BlY'}]
let obj ={}
items.forEach((item) => {
obj = {
...obj,
...item
}
})
console.log(obj)
How to add value to a specific object to the array by the index?
I wrote this, but of course, it creates a new object in the array, but I want to insert "errors" to an existing object with index (on screen it 0 index)
ipcRenderer.on('fileData', (event, data) => {
this.setState({jobs: [...this.state.jobs, {errors: data}]})
});
Then i wrote this:
ipcRenderer.on('fileData', (event, data) => {
this.state.jobs.forEach((item, index) => {
this.setState({jobs: [...this.state.jobs, {errors: item[index] = data}]
})
console.log(this.state)
})
});
It inserts a value into the object, but without a name and it still creates a new element in the array
I want the result to be like this:
jobs: [
0: {errors: 10, fileName:...}
]
If you know the index, you can just do
const jobs = this.state.jobs.slice(0);
jobs[index].errors = data;
this.setState({jobs});
Might have to do more than slice the array, might have to make a deep copy, but yeah, that should work.
Firstly you can make a copy of your array like
let jobsCopy = this.state.jobs
Then if you know the index you could just do like
jobsCopy[index].errors = 10
this.setState({
jobs: jobsCopy
})
You would need to know the index of the object you want to change. For example if you know it is the first item in the array you can do this:
const indexToChange = 0
this.setState(prevState => prevState.map((obj, i) => {
if(i === indexToChange) {
return {
...obj,
errors: data
}
} else {
return obj
}
}))
I have this code that i use in a redux reducer:
case 'REMOVE_FL_EVENT' :
return{
...state,
events: Object.keys(state.events).map(group => {
return state.events[group].filter(item => item.id !== action.id)
})
}
What happens here is that the state.events is an object, where every key is the name of the group of it's events, the value is an array with the events. What i want to do is when i convert the object into an array with map, if the filter happened convert back to it's original state, where state.events is not an array, but an object, with the original names of the keys.
There is no need to use map, you could use reduce only, something like:
{
...state,
events: Object.keys(state.events).reduce(
(obj, event) => ({
...obj,
[group]: state.events[group].filter(item => item.id !== action.id)
}),
{}
)
};
Update
The reduce has the following signature:
arr.reduce(callback[, initialValue])
So in our script, we are giving an empty object as the initial value for the accumulation.
You can use map/reduce for this purpose. First map it and then reduce it into an object.
case 'REMOVE_FL_EVENT' :
return{
...state,
events: Object.keys(state.events).map(group => {
return { [group]: state.events[group].filter(item => item.id !== action.id) }
}).reduce((obj, event) => Object.assign(obj, event), {})
}
The output will be an object with keys as groups. Let me know if it works.
With standard JS, you can use reduce to convert the array back to an obj:
arr.reduce((acc, o) => Object.assign(acc, o), {})
Using ramda.js you can filter Objects and their nested properties. https://ramdajs.com/docs/#filter
I'm trying to add some behavior exclusively to the last item in a list in Cycle.js. I tried to use cycle-onionify to make a collection like so:
const List = makeCollection({
item: Child,
itemKey: (childState, index) => String(index),
itemScope: key => key,
collectSinks: instances => {
return {
onion: instances.pickMerge('onion'),
DOM: instances.pickCombine('DOM')
.map(itemVNodes => ul(itemVNodes))
}
}
});
I understand that lenses can be used to share state between components, but there doesn't seem to be a way to use lenses with a collection. I'm thinking I could pass the Collection length to the children so I could compare it with an id.
Is there something I am missing?
You can use lenses with makeCollection. Remember it returns a normal Cycle.js component that you can isolate. So if you want to add a boolean isLast you can do this like this:
function omit(obj, key) {
let tmp = { ...obj }; //Copy the object first
delete tmp[key];
return tmp;
}
const listLens = {
get: stateArray => stateArray.slice(0, -1).concat({
...stateArray[stateArray.length - 1],
isLast: true
}),
set: (stateArray, mappedArray) => mappedArray.slice(0, -1)
.concat(omit(mappedArray[mappedArray.length - 1], 'isLast'))
};
const List = isolate(
makeCollection({
item: Child,
itemKey: (childState, index) => String(index),
itemScope: key => key,
collectSinks: instances => ({
onion: instances.pickMerge('onion'),
DOM: instances.pickCombine('DOM')
.map(itemVNodes => ul(itemVNodes))
})
}),
{ onion: listLens, '*': null }
);
As a side note, if you want to apply a lens on each individual item, you can do so too, with the itemScope property. For example
itemScope: key => ({ onion: myLens, '*': key })
I'm trying to create a conditional sub-set of an array.
I have an array allBooks which has properties such as type,author,id etc.
In a particular view I want to show only some of properties based on a condition.
For example; displaying summarized properties of all the books in stock.
Here is what I have tried:
let booksInStock: any[] = [];
this.allBooks.forEach(book => {
// Add only when book is in stock
if (book.isInStock) {
// Get only few keys from all the available keys
let temp: any = {
typeOfBook: book.targetType,
author: book.author,
bookId: book.id,
bookDisplayName: book.value,
bookName: book.bookName
};
// Add to the summarized or filtered list
booksInStock.push(temp);
}
});
Is there a more efficient way of doing it?
Using filter and map would be more semantic, like so:
let booksInStock = this.allBooks
.filter(book => book.isInStock)
.map(book => ({
typeOfBook: book.targetType,
author: book.author,
bookId: book.id,
bookDisplayName: book.value,
bookName: book.bookName
})
);
If efficiency is your priority however, a for loop is faster. See this link for an example: https://jsperf.com/map-vs-for-loop-performance/6
For example:
// This function is pretty generic, you can find one in e.g. underscore.js or Ramda:
const pluck = fields => item =>
Object
.keys(item)
.filter(key => fields.includes(key))
.reduce((result, key) => {
result[key] = item[key]
return result
}, {})
// Create filter+map+pluck -settings for different 'views':
const inStock = books =>
books.filter(b => b.isInStock)
.map(pluck(['targetType', 'author', 'id', 'value', 'name']))
// Invoke them:
const booksInStock = inStock([
{ isInStock: true, author:'harry', otherFIeld:'not-included' },
{ isInStock:false, author:'notharry'}
])