Nativescript: [2.2.1] Nested observables break the app

Created on 18 Aug 2016  路  16Comments  路  Source: NativeScript/NativeScript

I just recently updated to TNS 2.2.1 from 2.1.x (iOS). My app was using nested observables to function, and in the recent update of TNS, #2457, fixed so you don't need nested observables. However, this is now breaking my app workflow because when navigating to a view that has nested observables, will do nothing. Nothing as in not navigating to that view.

What I need to do is recode everything so there are no nested observables. I am okay with this, but I need to know why such a big change breaks due to an update? I mean, shouldn't the nested observable just be ignored and be served as just a normal value (non-observable)?

bug

Most helpful comment

@nsndeck -- You do realize that fromJSON is totally misnamed and IMHO should be corrected ASAP since it was just introduced; the usage is completely wrong...

From the official JSON site:

JSON is a text format that is completely language independent

Please note the TEXT part of this; JSON is a 100% TEXT STRING...

var testObject = Observable.fromJSON({
    isLoading: false, 
    'itemList': new ObservableArray(),
    'someObject': {
         'firstProp': "firstPropertyValue",
         'secondProp': "secondPropertyValue"
    }
});

That is _NOT_ a JSON, that is a REAL JavaScript OBJECT -- JSON is a TEXT based Object Notation; for example; you can't put ObservableArray into a JSON representation, because the ObservableArray has NO ability to be serialized to and deserialized from JSON. So valid JSON would be:

var someJSONString =  '{ "isLoading": false, ' + 
'   "itemList": [], ' + 
'    "someObject": { ' +
'        "firstProp": "firstPropertyValue", ' +
'         "secondProp": "secondPropertyValue" ' +
'    } ' +
'}'
var testObject = Observable.fromJSON(someJSONString);

So this REALLY needs to be renamed to:
Observable.fromObject({});
and
Observable.fromObjectRecursive{{});

Please fix the naming as this is very confusing to use the totally wrong name for something it doesn't do (i.e. it doesn't work with JSON, it works with already constructed Objects)

All 16 comments

Hi @NordlingArt ,
We indeed fix that behavior unfortunately it does not enter into the today's recent release. You could safely use tns-core-modules@next version where the fix presents. Further info on how to use it you probably read in issue #2457.
Let me know if this is a show-stopper for you in order to force a new hot fix for tns-core-modules.
Sorry for the inconvenience caused.

@nsndeck Good to know it is getting a fix. For me it is not a show-stopper although it does add extra work for me. There shouldn't be any nested observables anymore after this recent update, so I could just fix my issues right away instead of having to deal with them later on for optimization.

@NordlingArt With the code in the @next version we returned the behavior before 2.2.0. Which means that Observable constructor with JSON object will create only a single-level observable and set some properties according to the supplied JSON. Keep in mind that we mark this constructor as deprecated as we plan to remove it, since we added two help static functions Observable.fromJSON and Observable.fromJSONRecursive which will satisfy both scenarios.

@nsndeck Alright. Though I'm not sure what you mean there with fromJSON and fromJSONRecursive.

Another issue that I just encountered. How should one add an ObservableArray to the bindingContext if nestling doesn't work? See this scenario:

var pageData = new Observable({
  isLoading: false,
  itemList: new ObservableArray(
   { id: 1, title: "Test 1" },
   { id: 2, title: "Test 2" },
  )
});

exports.navigatingTo = function(args) {
  page.bindingContext = pageData;
};

isLoading needs to be within an Observable and itemList also needs to be within the bindingContext. Since I cannot have two bindingContext, how should I work this around? I have a ListView in the XML and itemList is loading items simultaneously and therefore all entries within haven't been loaded yet at navigatedTo.

Perhaps this is what you mean with @next version. If so, which one do I need; fromJSON or fromJSONRecursive?

@NordlingArt I'll try to bring some light to fromJSON and fromJSONRecursive methods:

Usage:

import { Observable } from 'data/observable';

// create Observable from JSON
var testObject = Observable.fromJSON({
    isLoading: false, 
    'itemList': new ObservableArray(),
    'someObject': {
         'firstProp': "firstPropertyValue",
         'secondProp': "secondPropertyValue"
    }
});

this results in a runtime object similar to the following:

import { Observable } from 'data/observable';
import { ObservableArray } from 'data/observable-array';

export class TestObject extends Observable {
    private _isLoading: boolean;
    private _itemList: ObservableArray<any>;
    private _someObject : any;

    public get isLoading(): boolean {
        return this._isLoading;
    }

    public set isLoading(value: boolean) {
        if (this._isLoading !== value) {
            this._isLoading = value;
            this.notifyPropertyChange('isLoading', value);
        }
    }

    public get itemList(): ObservableArray<any> {
        return this._itemList;
    }

    public set itemList(value: ObservableArray<any>) {
        if (this._itemList !== value) {
            this._itemList = value;
            this.notifyPropertyChange('itemList', value);
        }
    }

    public get someObject() : any {
        return this._someObject;
    }
    public set someObject(value : any) {
        if (this._someObject !== value) {
            this._someObject = value;
            this.notifyPropertyChange('someObject', value);
        }
    }
}

of course just an instance of TestObject class.

The only difference between fromJSON and fromJSONRecursive methods is that fromJSONRecursive will create same run-time class for someObject too.
Arrays (including ObservableArray) and functions will not be changed (converted to Observable).

So to answer the question this syntax should work with both fromJSON and fromJSONRecursive methods. For the time being even with constructor (as you are using it), since there is no nested object within JSON.
Let me know if there is something unclear or you have some issues with implementation within tns-core-modules@next build.

@nsndeck - Thanks, this worked!

@nsndeck: It doesn鈥檛 look like this fix made it into 2.2.1, as I鈥檓 still having the same issue. Can you confirm that?

@nsndeck -- You do realize that fromJSON is totally misnamed and IMHO should be corrected ASAP since it was just introduced; the usage is completely wrong...

From the official JSON site:

JSON is a text format that is completely language independent

Please note the TEXT part of this; JSON is a 100% TEXT STRING...

var testObject = Observable.fromJSON({
    isLoading: false, 
    'itemList': new ObservableArray(),
    'someObject': {
         'firstProp': "firstPropertyValue",
         'secondProp': "secondPropertyValue"
    }
});

That is _NOT_ a JSON, that is a REAL JavaScript OBJECT -- JSON is a TEXT based Object Notation; for example; you can't put ObservableArray into a JSON representation, because the ObservableArray has NO ability to be serialized to and deserialized from JSON. So valid JSON would be:

var someJSONString =  '{ "isLoading": false, ' + 
'   "itemList": [], ' + 
'    "someObject": { ' +
'        "firstProp": "firstPropertyValue", ' +
'         "secondProp": "secondPropertyValue" ' +
'    } ' +
'}'
var testObject = Observable.fromJSON(someJSONString);

So this REALLY needs to be renamed to:
Observable.fromObject({});
and
Observable.fromObjectRecursive{{});

Please fix the naming as this is very confusing to use the totally wrong name for something it doesn't do (i.e. it doesn't work with JSON, it works with already constructed Objects)

Agreed with @NathanaelA as I found the usage confusing as well. Since this hasn鈥檛 shipped in an official release yet we should be fine to switch this up to naming we鈥檙e comfortable with.

Hi all,

Just a follow up on this. Indeed the naming was poor (thanks @NathanaelA for pointing this out) and we renamed these functions to fromObject and fromObjectRecursive. Furthermore we move these functions out of the Observable class and place them in observable module instead. So just a little change of the way we use these functions:

import {fromObject} from 'data/observable';

...
let someObservable = observable.fromObject({someProp: "propertyValue"});
...

Awesome, thanks for being so responsive @nsndeck ... I would also recommend you rename the internal addPropertiesFromJSON to AddPropertiesFromOBJECT as those following in your footsteps will be confused why you called it FromJSON and have a json parameter that is a real object...

I also believe I found a case that blows up. If you pass in an object with a value equal to null; the recursive logic explodes. As typeof null === 'object' So it tries to turn it into a new Observable...

Example: var Someobject = { nullValue: null };

@nsndeck: I鈥檓 just quickly give a quick 馃憤 to the updated APIs. Semantically those functions are going to be a heck of a lot easier for me to explain in the tutorials. Looking forward to seeing these in a release 馃槃

@NathanaelA, I'll fix it with some of my later commits.

https://github.com/NativeScript/NativeScript/issues/2682
see this,may be a solution,use typescript

Already fixed.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings