PCUI ArrayInput Data-Binding

Hi again folks, :grinning_face_with_smiling_eyes:

Sorry to make a nearly identical thread name. This time I’m trying to data-bind an ArrayInput like so:

var observer = new Observer({
    selectedNode: {
        guid: "",
        tags: []
    }
});

var arrayInput = new ArrayInput({
    binding: new BindingTwoWay(),
    type: "string",
});
arrayInput.link(observer, "selectedNode.tags");

But whenever the observer object’s value is set, I get an error in the console.

observer.set("selectedNode.tags", graphNode.tags.list(), true, false);

Error looks like this:

selectedNode.guid:set (event error)
index.mjs:81 TypeError: value.equals is not a function
    at Observer.set (index.mjs:375)
    at Observer.<anonymous> (Editor.ts:90)
    at Observer.emit (index.mjs:78)
    at Observer.set (index.mjs:507)
    at Editor.selectBox (Editor.ts:178)
    at <anonymous>:1:8

Is this the wrong way to data-bind an ArrayInput? @Elliott, thanks for helping in the other thread. Maybe you can assist here as well? Thanks :smiley:

Hi @damvad, It looks to me like you’ve set up your observer and array input correctly. What does the call to graphNode.tags.list() return. The array input will be expecting to path selectedNode.tags in the observer you created to contain an array like: ['my', 'list']. Another thing to try would be to rename your observer something other than ‘observer’. This may be clashing with the global object created by the library.

2 Likes

Thanks for the reply :smiley:

The list() method in GraphNode.tags returns exactly that. An array of strings.

I’ll try renaming the observer in a jiffy

Darn, it didn’t seem to do anything :frowning:

I’m doing it the same way successfully with BooleanInput, TextInput, and VectorInputs (of course different types in the Observer object)

Weird how this one is different… :thinking:

Ok I’ve narrowed the error down, I think. It only seems to happen when resizing the array! Changing existing array item values via a data-bound ArrayInput works flawlessly. The value changes as expected in the Observer object.

But increasing or decreasing the size of the array triggers the error:

change (event error) (index.mjs:80)
TypeError: value.equals is not a function (index.mjs:81)
    at Observer.set (index.mjs:375)
    at BindingElementToObservers._observerSet (index.js:9123)
    at BindingElementToObservers._setValueToObservers (index.js:9097)
    at execute (index.js:9019)
    at BindingElementToObservers._setValue (index.js:9050)
    at BindingElementToObservers.setValues (index.js:9299)
    at BindingTwoWay.setValues (index.js:9384)
    at ArrayInput._updateValues (index.js:8383)
    at ArrayInput._onSizeChange (index.js:8225)
    at NumericInput.emit (index.mjs:78)

Diving into the error, it seems that the Observer.set() method attempts an .equals() function on the value parameter which is an Array.

Apparently Arrays don’t have that function. Is this an error in the @playcanvas/observer package?

image

@Elliott I figured it out! :smiley:

Array does indeed miss the equals() function.

I tried extending the prototype with a custom function, and it worked! Hooray! (I work in TypeScript btw)

declare global {
    interface Array<T> {
        equals(o: T): boolean;
    }
}

Array.prototype.equals = function(other) {
    return Array.isArray(other) &&
        this.length === other.length &&
        this.every((val, index) => val === other[index]);
}