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 })