Dependent Inputs.select in Observable Framework don't always react

I have one Inputs.select depending on the results of another in an Observable Framework markdown page and I can’t quite get it to always update. It seems to only do this half the time.

I thought maybe I needed to set up an onchange handler to update the answerInput dropdown explicitly, but that doesn’t seem to fire.

If I use something like const questionNr = Generators.input(questionNrInput) instead of await, I’ll then get a ‘RuntimeError: element.addEventListener is not a function’.

const surveyQuestions = [
  {
    text: 'Question 1',
    answers: [{ text: 'Q1 Answer 1' }, { text: 'Q1 Answer 2' }, { text: 'Q1 Answer 3' }],
  },
  {
    text: 'Question 2',
    answers: [{ text: 'Q2 Answer 1' }, { text: 'Q2 Answer 2' }, { text: 'Q2 Answer 3' }],
  },
  {
    text: 'Question 3',
    answers: [{ text: 'Q3 Answer 1' }, { text: 'Q3 Answer 2' }, { text: 'Q3 Answer 3' }],
  },
];
const questionNrInput = view(
  Inputs.select(new Map(surveyQuestions.map((q, i) => [`Q${i + 1}: ${q.text}`, i + 1])), {
    label: 'Question',
    value: 1,
  })
);
questionNrInput.onchange = () => {
  console.log('onchange');
  // answerInput.value = ...
  // answerInput.dispatchEvent(new CustomEvent('input'));
};
const questionNr = await questionNrInput;
// const questionNr = Generators.input(questionNrInput);
const answerInput = view(
  Inputs.select(
    surveyQuestions[questionNr - 1].answers.map((a) => a.text),
    {
      label: 'Answer',
      value: surveyQuestions[questionNr - 1].answers[0].text,
    }
  )
);
const answer = await answerInput;
display(`questionNr: ${questionNr}`);
display(`answer: ${answer}`);

You mixed up the input element, returned from Inputs.select and the result of it displayed + value observed, returned from view(Inputs.select(...)).

You can think of view(<INPUT>) as rendering + wrapping the input in Generators.inputs in one step, so what you get back is already the input’s value and can be used directly, i.e. no need for await ....

Whereas if you want to defer the rendering, you can use Inputs.select() to create the input first (but not rendered), then use Generators.inputs on the returned from it to monitor its current value, and finally display the input element at where you desired.

Something like:

Do you mind asking this question instead on GitHub? We’re trying to consolidate all questions on our open-source projects to GitHub, where these projects are developed. Thank you!

1 Like

@MP_Li Thanks! This did trick!