go.Picture never shows image if element source is set delayed in binding

Hello,

I have a go.Picture with a binding on the element.
In the binidng, I create a new Image and assign its source.

However, if the delayed setting of the image source takes too long, the image is never displayed.

In our app, I am loading an image from the harddrive and converting it to a Blob via URL.createObjectURL() in the binding. The actual image to be loaded depends on a node data attrbiute.

I have created an example where I simulate delayed setting of the element source with setTimeout(). A timeout of 500 still works, where a timeout of 1000 never shows the image on the node:

Why is the image never shown in the example and what can I do to fix it?

This:

            new go.Binding("element", "", (e, obj) => {
              const element = new Image();
              //element.src = "";
              //element.crossOrigin = "Anonymous";
              setTimeout(() => {
                obj.diagram?.commit(() => {
                        element.src = "xyz.jpg";
                        obj.reloadSource();
                        obj.redraw();
                    }, null);
                
              }, 1000)
             
              return element;
            }))

Seems like a really bad idea. In the documentation we mention:

Conversion functions can be named or anonymous functions. They take a data property value and return a value suitable for the property that is being set. They should not have any side-effects. They may get called any number of times in any order.

This is especially true for an empty-string binding, which will get evaluated every single time any node data changes.

I suggest that instead of doing bindings to set these images, you load the model, load your images some other way (creating your own new Image()s are fine, and set them once loaded.

The empty string binding was only for the example, however I can understand that the whole approach is a bad idea.

Thanks for your suggestion, I’ll try to load the images frist and then set them. Still I think this approach is at first counter-intuitive if one is used to work with bindings. Maybe you could consider some kind of support for asynchronously loading of go.Picture bindings in a future version.

At a high level, why would you want a delay or async binding at all? Introducing something like that might make it more difficult for us to ensure state, so we are unlikely to encourage it.

I am reading files from the disk using Apache Cordova, and the file reading API is async.

Not sure, but might also be useful when one uses web workers?

I think if you are getting the data async, it really shouldn’t be in the binding that you do any of the fetching or waiting. Instead, once the data is ready, then you can set it. You can set it of course by calling a binding via
model.set(nodeData, property, value)

Where property here is source or element on the Picture, but are best set only once the resource exists.

Okay, thanks!