Use Multiple Independent Instances of a Cycle.js Component

André Staltz
InstructorAndré Staltz

Share this video with your friends

Send Tweet
Published 6 years ago
Updated 3 years ago

Once we have a labeled slider component inside the main function, we should be able to create another labeled slider. This lesson teaches how to accomplish that, and make sure those two instances work independently of each other.

[00:00] We have a labeledSlider component inside our main here to make the weight slider. Now, let's build a BMI calculator using two labeledSlider components. First let's make some space for the other component. I'm just going to rename props to weightProps and I'm going to use that here.

[00:19] Our sinks are going to going to be weightSinks. That's what we return here. Then I can make a very similar component just for the height. This one will have heightProps labeled as height, centimeters 140 to 20 and 140.

[00:39] This would be weightSinks when we give weightProps. Then I can either use weightSinks here at the bottom or I can use heightSinks. As you can see we get that. We want both of these component instances combined. Let's make a VDOM stream here which will combine both of them together.

[01:01] Then we return the combination here as the sinks. We use xs.combine to combine the streams from these two. We want the DOM sink from the weight and the DOM sink from the height.

[01:22] That gives us a stream of arrays so we can map that array which has the weightVDOM and the heightVDOM. We can put both of these in a div. We're going to have weightVDOM and heightVDOM. There we go. We have both the slider showing on the DOM.

[01:47] They look correct, but if I try to interact with the height slider then both of the sliders will change. If I try to interact with the weight slider then both of them will change. That doesn't sound correct. Why does that happen? We need to look at the intent function will handles user events.

[02:04] We see that here this is a stream of all of the events of type input happening on any slider on the DOM. We don't want that. We want the intent inside the labeledSlider for the weight to only capture events related to the slider inside that weight.

[02:25] We could instead do something like this. We want to select slider elements that are inside the weight element, and the weight element would be here. For instance, this one. We know then that this is selecting events happening on this element inside that element. Then we're basically directly modifying our code here and hard coding it for the weight slider only.

[02:53] To do something less intrusive we can do instead a post processing step. Here we're going to make a stream which is a post processing of this stream. labeledSlider will call intent, model and view. After that we can add a post processing step to handle this one.

[03:13] We're going to get weightSinks.DOM, which is referring to this one, and we're going to add an additional step there. For each VDOM we're going to change its selector to have weight, and then we're going to return that VDOM.

[03:34] This is now post process. Instead of using weightSinks.DOM directly I'm going to use the post-processed version like that, and I'm going to do something very similar for height. We're going to take heightSinks.DOM and change each selector to have height class. That's what we're going to use here, the post processed VDOM stream.

[04:00] When we run this, we can inspect each of these classes, and we see there that this has the class weight and this has the class height. That's good, because then we can use these classes in the intent. Instead of directly modifying the intent code we're going to add a preprocessing step. Just like we had a post processing step we're going to have a preprocessing.

[04:25] We're going to have here, let's say, weightDOMSource would be sources.DOM and select weight. This DOM source is basically preselected to focus on .weight class name. That's what we're going to pass here. If you see the sources for the weight slider, have the weightDOMSource which is preprocessed and the props.

[04:56] We're going to do something very similar for the height. Here the heightDOMSource is going to be preselected with the height class name. That's what we're going to use here when we call the component, like that.

[05:15] Then I know that the DOMSource here passed to this labeledSlider will be passed to the intent. The intent will basically select a slider but we know that this DOMSource was already preselected for the weight. When I interact with the weight it's already preselected for that part, and the height is preselected for this part.

[05:41] That's how we can achieve component independence. We just add some preprocessing and some post processing steps.

~ 6 years ago

This part looks like the 'parallel parking'. I have to watch this again and again.

Stephen James
Stephen James
~ 5 years ago

Could the selector class be added to props and props be passed to intent as well as view? The pre/post stuff seems klunky for adding class and selector

~ 4 years ago

Could the selector class be added to props and props be passed to intent as well as view? The pre/post stuff seems klunky for adding class and selector

This seems weird indeed, introducing imperative code into a functional app... I've simply passed the selector into the intent/view functions, and prepended it to the existing selector.