Observable Array


#1

Observable Array seems odd!

const viewModel = new observable.fromObjectRecursive({
  is_open: true,
  staff: [
    {
      name: "Megan"
      wage: "23",
      role: "waitress"
    }
  ]
  books: new observableArray.ObservableArray([
    {
        title: "Hard to find"
    },
    {
      title: "These items"
    }
  ])
});

Taking the above into consideration you would think to access the title of a book in your xml bindedContext you would;

<Label text="{{ books[0].title }}"/>

Since thats how you access the non-observed staff array;

<Label text="{{ staff[0].name }}" />

And you just set the books value to an array, right?.. wrong!

// Books, the observableArray
console.log(books) // [object Object]
console.log(books[0]) // undefined
console.log(Array.isArray(books)) // false

// Staff, the non-observed array
console.log(books) // [object Object]
console.log(books[0]) // object Object]
console.log(Array.isArray(books)) // true

ObservableArray(..) does not return an array! Which seems very odd. Instead it returns an object with _observers,_array,_addArgs,_deleteArgs.

In order to access the books array you need to;

<Label text="{{ books._arrray[0].title }}" />

#2

Observable Array !== Array

It’s a special class similar to array, you can perform all push, pop, splice etc., methods. Additionally it can notify the listeners when changes are made to array. So you can’t access an element at index using books[index] but books.getItem(index).

Docs - https://docs.nativescript.org/cookbook/data/observable-array

I don’t think you can directly access observable array by index from binding expression. May be you can use a Repeater to loop through each index or if you specifically want to access one index, try using a converter.


#3

Yeah, I saw that. Just thought it’s a strange way to go.

Do you know of any technical reason behind this decision. To me it seems like a needless extraction. Why not just return an array and let us access it, mutate it via JavaScripts’ existing methods?

For my use case I’ve decided to just stick with observer.fromObjectRecursive. Mainly because;

  • I can just drop items directly into xml
  • And when I need to iterate via array methods, Object.keys(...)<some_method> does the trick.

This does require converting the array to object, and {N} drops in some keys like _observers that need to be filtered out. But that’s easy enough.


#4

As I already mentioned it’s to keep track of changes in Array. Observable Array simply wraps the original array triggers events upon push, pop, or slice / splice etc.,

NativeScript Core is lightweight, unlike Angular (or Vue) which runs lot of checks in background to know whether a Array was updated or not, and gives you what exactly you are looking for here.

NativeScript didn’t have to build all these features in box which are already there in different JavaScript frameworks it supports. Still Observable Array was an easiest path chosen to support data binding when developer is not using one of these frameworks. So it seems to be a very valid reason, at least for me :wink: