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.
We go to labeledSlider component here inside main to make the weightSlider. Now let's build the BMI calculator using these labeledSlider components.
Let's first make some space for the second component to arrive. This is now weightProps, and this returns weightSinks. Let's format the code a bit.
Then we're going to return weightSinks. Now we're going to copy/paste this for the height, rename this to heightProps. These are heightSinks, and the properties are in centimeters --140, 220, 170.
So we can either return weightSinks or we can return heightSinks, and there we go, but we actually want both of these sinks for these two sliders combined.
Let's make a vTree stream, a virtual DOM tree stream, that we combine latest both of them the weightSinks.DOM, so the DOM sink of the weight, heightSinks.DOM, then a function that takes the weight virtual DOM tree and the height virtual DOM tree, and it returns a virtual DOM tree containing the weightVTree and the heightVTree.
Here, instead of returning the heightSinks, we will return an object of sinks. It's a DOM sink as vTree stream.
There we go. We have both sliders. They look correct, but if I try to interact with one of them, then we see both of them changing, and that looks wrong. Why does this happen? Let's look at the intent function that is responsible for capturing user events.
The intent function of the heightSlider, for instance, is capturing events coming from all of the elements with class name slider, which includes also the weightSlider. Of course, ideally, we want the height component to only take events from the heightSlider and the weight component to only take events from the weightSlider.
We need to tell the intents to be a bit more specific when selecting the use elements. If the view would have an additional class name for weight, then we could use that class name to narrow down here the selection of elements in the intent.
How did we accomplish that? We can do it with a post-processing step after labelSlider does its job. We can take the DOM sink, and we can sort of patch it, so we can make another observable here called weightVTreeStream.
We take the DOM sink from the weightLabeledSlider, and we're going to get each of these vTrees and add a post-processing step, take the properties, and we're going to append the class name to have now weight as well. Then we return that vtree.
Almost the same thing, but now for the height component, and now we need to use these sort of patched DOM sinks here when we combine them together. Now if we inspect the DOM and check how did they look, they have a height class name and a weight class name, so it means that the intent can now use them to narrow down its search.
How do we do that? We add a pre-processing step before intent takes action, and we do that by simply narrowing down here. The DOM source that we will give to the weight component will be preselected with the weight class name. We're going to do that also for the height.DOM source.
It means that when the intent starts working, it already comes pre-selected here with, for instance, weight. That means that it will get all of the input events that happen in slider elements that are scoped by this weight class name.
That should work. This one is only changing for the height, and that one is only changing for the weight, and that's how we achieve component independence.