0

I'm trying to wrap my head around Ramda.js but I'm stuck. I have an array that looks something like this:

const state = [
  {
    itemId: 112,
    animations: [{id: 1}, {id:2}],
    classes: ['animated']    
  },
  {
    itemId: 121,
    animations: [{id:2}],
    classes: ['animated']    
  }
]

My goal is to create a function where

removeAnimation(121, 2, state);

...would return:

const state = [
  {
    itemId: 112,
    animations: [{id: 1}, {id:2}],
    classes: ['animated']    
  },
  {
    itemId: 121,
    animations: [],
    classes: []    
  }
]

So the function removes the animation obj based on the specified id inside the object with the specified itemId, and if no more objects present in the animations array, it also removes the animated string in the classes list.

This is how far I got:

const removeAnimationFromItem = R.curry((itemId, animId, state) => {
  return R.map(
    R.when(
      R.propEq('itemId', itemId), [--This is where I'm stuck--]
    ), state)
  })

Thank you for your time.

2
  • Do you want to do this using ramda.js only? Commented Jun 8, 2018 at 18:18
  • Yes. With vanilla ES6 this wouldn't take long. I'm trying to practice functional programming, and the app already has Ramda.js. Commented Jun 8, 2018 at 18:20

1 Answer 1

1

I think there is an important question here of whether you actually want Ramda's behavior. If we do something like this with Ramda, it will not change your data. It will return new objects that share what they can with your originals, but your originals will still be as they were. The Ramda team (disclaimer: I'm one of the Ramda authors) thinks this is a very good thing. But sometimes it might be surprising.

Ramda does not have any ready-made solutions that would make this easy. If I were to do it, I'd probably break it down first into two steps: remove the target animations, then update the classes property for all items. This I find simpler to think about. If it turned out to have performance problems, I might look to combine them.

Here is one approach:

const {findIndex, propEq, adjust, evolve, remove, without, pipe, map} = R

const removeOneAnimation = (itemId, animId, state) => {
  const itemIdx = findIndex(propEq('itemId', itemId), state)
  if (itemIdx < 0) {return state}
  const animIdx = findIndex(propEq('id', animId), state[itemIdx].animations)
  if (animIdx < 0) {return state}
  return adjust(evolve({animations: remove(animIdx, 1)}) , itemIdx, state)
}

const updateAnimClass = (item) => item.animations.length === 0 ? evolve({classes: without(['animated'])}, item) : item

const removeAnimations = pipe(
  removeOneAnimation,
  map(updateAnimClass)
)

const state = [{"animations": [{"id": 1}, {"id": 2}], "classes": ["animated"], "itemId": 112}, {"animations": [{"id": 2}], "classes": ["animated"], "itemId": 121}]

const newState = removeAnimations(121, 2, state)

console.log(newState)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>

Note that some of the Ramda code here doesn't give a great deal of lift. For instance, this:

  const itemIndex = findIndex(propEq('itemId', itemId), state)

could just as easily be written as

  const itemIndex = state.findIndex(item => item.itemId === itemId)

But some of the other functions, such as evolve, adjust, remove, and without do a lot. If you want Ramda's approach of treating data as immutable, these are fairly powerful.

Sign up to request clarification or add additional context in comments.

2 Comments

First of all thank you very much for your time and generally for the ramda library Scott. One question though, you said ".. share what they can with your originals". What did you mean by that? Do you mean that state[0].animations[0] === removeAnimations(121, 2, state)[0].animations[0] would be true? That's not a problem for me, and I also think that's a good thing. I guess If I didn't want them to be the same, I could wrap them in R.clone(). Thanks again.
Yes, that's precisely what I mean. We find that behavior useful, but some find it off-putting.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.