Using "if" on Observable

I am trying to do a conditional assignment and it doesn’t work.
The datafile on the screen below should have the value of attached,
which is FileAttachment {name: "sample.csv"}, but it is empty?

image

your “if” cell puts a dataflow dependency on the variables “uploaded” and “attached”. It updates if these values change.

Because uploaded does not resolve until something is uploaded, the whole cell containing the “if” code is not run at all! That’s what the vertical bar on the left means (pending).

You can peak at a viewof’s value without adding a dataflow dependency on the data like

    viewof uploaded.value

but then when you do upload a file the cell won’t be rerun (it’s no longer reactive).

You can fix this with some manual wiring of addInputListener(‘input’, …) but maybe there is a simpler way to provide a default value to the localInput

    viewof uploaded = localFileInput({value: attached})

now uploaded is initially your sample, which will be overridden if the user uploads a file.

5 Likes

Thanks for the explanation. The bar could have a tooltip to explain that it is waiting for resolution of uploaded, because attached is already resolved.

I used the localFileInput({value: attached}) before, but decided to rewrite the logic to be more explicit. The addInputListener looks like a JavaScript thing. Is it the official way to write things that may change multiple times?

If you really want to host the if logic in its own cell then you can also do

viewof uploaded = localFileInput({value: null})

which ensures that cell resolves. If either attached, or uploaded changes the if block will be reevaluated automatically by Dataflow.

I confirm this works as needed.

viewof uploaded = localFileInput({value: null})

With that, the following code is reevaluated every time a new file is uploaded.

datafile = {
  if (uploaded) {
    return uploaded;
  } else {
    return attached;
  }
}

But why it is different from the previous definition where it hangs?

viewof uploaded = localFileInput()

The background to views is here: Introduction to Views / Observable / Observable

It is not stated there but a view with value ‘undefined’ is not considered resolved.

This also hangs:

viewof uploaded = localFileInput({value: undefined})

As does

viewof example = html`<div>`

I think it is a conscious choice to not resolve anything until an actual value is published. Null is considered a value, whereas undefined is better describing semantically an unset value. data flow is for data, undefined is not data in JS idioms, so it’s a reasonable design choice I think

a good example of the usefulness of holding up data flow until a user does something is Authentication Simulator / Mike Bostock / Observable

4 Likes

That’s very interesting! In regular javascript, you can still test for undefined a === undefined but it doesn’t seem to work with an unresolved cell on observable. Interesting you can test viewof value, but it’s not reactive viewof file.value === undefined

Have a look at The `.value` is a lie.🎂 (on viewof'ed inputs at least) - #2 by mootari for an explanation.

1 Like

I have hit the difficulty of conditional dataflow a few times myself in other settings, so I sat down and tried to figure out how to do it cleanly even when there is no “value” get out-of-jail-card argument.

1 Like