UX not responding to Observable update

Hey guys,

I am currently struggeling with some basic Observable handling.
First of all, I am fetching a complex JSON structure, just like in the Working with REST APIs Tutorial.
This is working just like it should.

I am fetching the data and assign it to my data variable, which is an Observable:

  API.getPois().then(function(newContent){
    var tmp = [];
    tmp.push(newContent);
    data.replaceAll(tmp);

The structure of my JSON data looks like this:

{"poi":[{"id":"1","title":"TITLE OF MY POI","city":"CITY OF MY POI""latitude":"LATITUDE OF MY POI","longitude":"LONGITUDE OF MY POI"}]}
....

In my UX-File, I each through my Observable, which is also working perfectly:

<Each Items="{data.poi}">
....
</Each

Initial I was going to sort my array by using the Array.Sort() function, which was only working with a copy of my array, not with the original array.
So I experimented a bit with my Observable and found a strange behaviour which I hope you can help me get rid of:

As I mentioned, the stuff above is working perfectly.
But if I change my Observable after the stuff above, my UX is not responding to it.

If I, for example, change the title of my first entry:

data.value.poi[1].title = "another title";

my UX is not changing the title.
It is still displaying the old title but even if I, afterwards, log my change to the console console.log(data.value.poi[1].title);, the log is showing the correct change.

I even tried to erase the whole Observable with .clear() didn’t change anything.

What am I doing wrong here?

You haven’t fully understood how Observables work.

You are updating your Observable list of items with the result of that fetch, but the individual properties of those items are not Observables. The fact that your list is an Observable does not magically make the children objects (and their properties) Observables.

If you want to observe the titles of your POIs, what you should have is something like this:

API.getPois().then(function(newContent) {
    var tmp = [];
    newContent.poi.forEach(function(item) {
        tmp.push({
            id: item.id,
            title: Observable(item.title),
            city: item.city,
            latitude: item.latitude,
            longitude: item.longitude
        });
    })
    data.replaceAll(tmp);

I see your point.
Bur shouldn‘t the list at least update, when I clear the whole Observable?

How would this work if I want to sort the Observable?

That is a different question.

In your Each, you data-bind to data.poi. data is an Observable, but data.poi is not. Even more, data in your case is a single-value observable, and my suggested solution turns it into a proper list Observable, so you should update your Each to <Each Items="{data}">.

As for sorting, it would… just work. Please read some more about observables in the links I shared before.

I updated my structure, but I think I still could need some of your help.

I updated my response-Array, so it now looks like this:

JSON Data:

[{"id":"1","title":"TITLE OF MY POI","city":"CITY OF MY POI""latitude":"LATITUDE OF MY POI","longitude":"LONGITUDE OF MY POI"}]
....

And i update my Each to:

<Each Items="{data}">
....
</Each

But now it cannot show any data.

When I log the received response, this is what it looks like:

 [[{"id":"1","title":"TITLE OF MY POI","city":"CITY OF MY POI""latitude":"LATITUDE OF MY POI","longitude":"LONGITUDE OF MY POI"}]]

Comparing it to the JSON-Data (thats the response I get, when checking it with a REST tool), it seems like fuse is wrapping another array arround it?

I don’t really get what’s wrong here.

Please post a complete, minimal, fully working reproduction that I could copy-paste and run. Think of it as a single-UX-file app.

We’ll have that sorted out in no time then.

Here is a minimal reproduction:

UX-File:

<App>
  <JavaScript File="Main.js" />
  <ClientPanel>
    <ScrollView>
      <StackPanel>
        <Each Items="{data}">
          <Text Value="{title}" />
        </Each>
      </StackPanel>
    </ScrollView>
  </ClientPanel>
</App>

JS-File:

var Observable = require('FuseJS/Observable');
var data = Observable("");


loadPois();

/* Load Data and push to Observable */
function loadPois() {
  getPois().then(function(newContent){
    var tmp = [];
    tmp.push(newContent);
    data.replaceAll(tmp);
  });
}

/* Fetch Data */
function getPois(){
  return apiFetch("poi", {
    method: "GET"
  });
}

function apiFetch(path, options) {
  var url = encodeURI(ROOT_URL + path);
  if(options === undefined) {
    options = {};
  }

  if(options.body !== undefined) {
    options = Object.assign({}, options, {
      body: JSON.stringify(options.body),
      headers: Object.assign({}, options.headers, {
        "Content-Type": "application/json"
      })
    });
  }

  // Fetch the resource and parse the response as JSON
  return fetch(url, options).then(function(response) {
    // console.log(JSON.stringify(response));
    return response.json();
  }).then(function(responseObject) {
    // console.log(JSON.stringify(responseObject));
    return responseObject;
  }).catch(function(err) {
    console.log("Error: " + err);
  });
}

module.exports = {
  data: data
}

There you go.

    var tmp = [];
    tmp.push(newContent);
    data.replaceAll(tmp);

If you’re receiving an array, why stuff it inside of another array? Change those three lines to this instead:

        data.replaceAll(newContent);

Thats working perfect, thank you!

Is it correct that, from now on, I only can access all values of data.value by using data.forEach?
Because if not, I am only getting the first element.

I am not really sure how to combine that with array.Sort().

I guess I found it out by using data._values instead.
Is that the correct approach?

No, do not access any properties on Observables directly. The underscore hints that it’s a private property and you should treat it like that. Instead, use the methods available on Observables: see docs.

The docs on .value state, specifically: The value property acts as a shorthand for getAt(0) and replaceAt(0).

A regular approach to sorting observables is using .toArray() to get an array, perform sorting with regular JS array sorting methods, and then executing a .replaceAll() with the now-sorted data.

You might find other useful methods in the Observable docs, such as .replaceAt, .refreshAll and others. Please spend some time reading docs, it’ll help a lot.

Awesome, thank you for your help!
It’s insane how quick and great the support of the Fuse Team is, thank you!