Detect which viewof changed

I have two radio viewof inputs in a notebook (named inpA and inpB), and a cell with code that uses both inpA and inpB.

Currently, if the user changes the selection of either inpA or inpB, the cell runs (because something changed). I would like to be able to distinguish between the inpA selection changing versus the inpB selection changing. Is this possible?

Please see @mbostock’s post below for a much better approach!

It is possible but it might get messy. Basically, you’ll want to refer to viewof inpA.value and viewof inpB.value instead of inpA and inpB so that the runtime doesn’t re-evaluate your downstream cell when inpA and inpB are changed.

The change detection will have to be done manually, i.e. you’ll have to add event listeners to the view elements inside your downstream cell.

Here’s a simple example, note that I refer to “reset” directly to cause the last cell to re-evaluate when the viewof reset button is clicked:

1 Like

I guess I should explain exactly what I am trying to do because I cannot see a way to make your code work with what I want to have happen. The following notebook has some code with my (non-working) attempt:

I have a zoomLevel viewof and an ageGroup viewof, and based on which viewof is modified (i.e., if the user changes the zoomLevel option or the user changes the ageGroup option), I want to change the duration of a transition.

I would like to have a variable named duration that represents the duration of the transition - if the zoomLevel viewof is modified I would like the duration to be 0, and if the ageGroup option is modified I would like the duration to be 600. Because the radio buttons are mutually exclusive only one of the two can change at any one time.

I think I am pretty close with the code I have, but I just cannot make the last step work. Hopefully you can point out a silly error I am making with this…

Indeed, you were quite close. I just sent you the following suggestion:

It uses a mutable cell for duration. My preference would be to combine the cell that adds the event listeners with duration in some way, but this should work.

2 Likes

Thank you so much, that works exactly as I had hoped!

Be careful about using addEventListener to listen to views. If you do, you also need to use the invalidation promise to remove your listener when the cell is invalidated, or else your old cells will continue to run indefinitely.

And viewof doesn’t work if you put text after your input:

viewof inpA = html`<input type="range">A`

The viewof operator needs an element that has a value, such as an INPUT element or a FORM. The above cell has an implicit SPAN element because the html template literal needs to wrap everything in an element.

You can use Jeremy’s inputs for a nice labeled range, or you can create a nice input yourself using a FORM element. See this recent example.

But getting back to the heart of the issue: if you want to “detect changes” or otherwise employ side-effects such as transitions, I recommend that the cell that wants to detect changes expose one or more update functions that you call from other cells. Here’s my fork of your notebook:

Here, the display cell returns your two DIV elements (again wrapped in an implicit SPAN), that has an update method exposed. This update method is called by two side-effect cells when inpA or inpB changes.

display.update("A", inpA)
display.update("B", inpB)

Thus, the display cell can react selectively to either of these inputs and transition appropriately. You can see this technique in use here:

3 Likes