Get value of variable set in script from one cell in a different cell without using `mutable`

Hello! I’ll preface this by saying that I’m new to Observable (and Observable Talk), and so apologies if this topic has already been addressed elsewhere and I’m missing it.

I’m building a notebook that explores a data set via an interactive visualization (built with D3). The interactive visualization is the output from one of the Observable cells. The data set includes a very long text string (a speech transcript) for each entry; in this visualization, users can click on an element in the interactive visualization, and I’m trying to get the speech transcript to display in a scrollable text box as an output from the subsequent cell. The click event sets a variable mutable DisplayText to be the transcript string from the selected data element. I can get the selected text to display in the text box output from the subsequent cell this way; however, the issue is that I have to declare the mutable DisplayText variable in a cell (Cell 1, below) prior to using it in my visualization code (Cell 2, below), and it also updates and displays the long transcript text in that initial cell (Cell 1, below) when you click on the visualization. It seems like I can’t hide the output of the initial cell, but having the transcript text show up here is irritating. Is there any way to get the DisplayText value in my text box cell (Cell 3, below) without using mutable?

This is how I have it implemented so far:
Cell 1:

mutable DisplayText = "" // the output of this cell also shows the transcript text - I don't want this.

Cell 2:
[Relevant part of code for visualization]

{
   svg.selectAll('circle')
      .data(data)
      .join('circle')
      .on('click', function(event, d) {
           mutable DisplayText = d.Transcript   // d.Transcript is the transcript text string I want to display
       });
 }

Cell 3:

html`
  <div style="height:300px;width:900px;border:1px solid #ccc;font:16px/26px Georgia, Garamond, Serif;overflow:auto;" id="TransriptBox1">
  ${DisplayText}  // This is the only place I want the transcript text to display
  </div>`
1 Like

To avoid mutable altogether, you might name your html cell, d3.select it in your response to the click, and then change it directly there. Thus, your html cell might be:

info = html``

Then, your response to the click might look like:

.on("click", function (event, d) {
  d3.select(info).text(d.Transcript);
});

Here’s a similar example where I base the info text on a title element, rather than a transcript.

I recommend Observable’s viewof macro:

viewof DisplayText = {
   const svg = /* ... */;
   svg.selectAll('circle')
      .data(data)
      .join('circle')
      .on('click', function(event, d) {
           svg
             .property('value', d.Transcript) // Assign text to (<svg>).value
             .dispatch('input'); // Notify Observable that you updated the value
       });
  return svg.node();
}

Now you can get rid of Cell 1. No changes to Cell 3 are necessary.

To learn more about viewof, have a look at this introduction:

1 Like

Here is a more direct implementation of how you can programatically set another cells value and initiate data flow on it using viewof magic. This is a bit closer to what you were asking than @mootari method (which is probably neater over all but not always applicable)

(Mcmcclur’s also valid way is doing direct DOM manipulation which is completely outside the observable runtime, which is portable to any webpage but does not engage the Observable reactive machinery)

Thank you! This worked perfectly - and I was also able to modify the HTML cell to include a few different div elements with different interactive text.

1 Like

Thanks @mootari and @tomlarkworthy as well - the links you shared for viewof are something I’ll definitely look more into as well. Much appreciated!