6

We are building an application using Cordova and Angular 2. I have the following code:

    import { Component, OnInit, ChangeDetectorRef, NgZone } from '@angular/core';
    import { Location } from '@angular/common';

    declare var WL : any;

    @Component({
      selector: 'app-store',
      templateUrl: './store.component.html',
      styleUrls: ['./store.component.css']
    })

    export class StoreComponent implements OnInit {
      status: string;
      document: any;

      constructor(private _location: Location,  private changeDetector: ChangeDetectorRef,
        private zone: NgZone) { }

      ngOnInit() {
        var collectionName = 'people';
        this.status = "JSONStore is not yet initialized!";
        if(typeof WL !== "undefined" && typeof WL.JSONStore.get(collectionName) !== "undefined")
                this.status = "JSONStore is initialized!";
        }
      }
      jsonStoreInit(){
                var that = this;
                var collectionName = 'people';

                // Object that defines all the collections.
                var collections = {

                    // Object that defines the 'people' collection.
                    people : {

                        // Object that defines the Search Fields for the 'people' collection.
                        searchFields : {name: 'string', age: 'integer'}
                    }
                };

                // Optional options object.
                var options = { };

                /* // Optional username, default 'jsonstore'.
                username : 'carlos',

                // Optional password, default no password.
                password : '123',

                // Optional local key generation flag, default false.
                localKeyGen : false
                };*/

                WL.JSONStore.init(collections, options).then(function () {

                    // Data to add, you probably want to get
                    // this data from a network call (e.g. MobileFirst Adapter).
                    var data = [{name: 'carlos', age: 10}];

                    // Optional options for add.
                    var addOptions = {

                        // Mark data as dirty (true = yes, false = no), default true.
                        markDirty: true
                    };

                    // Get an accessor to the people collection and add data.
                    return WL.JSONStore.get(collectionName).add(data, addOptions);
                })

                .then(function (numberOfDocumentsAdded) {
                    that.status = "JSONStore is initialized!";
                })

                .fail(function (errorObject) {
                // Handle failure for any of the previous JSONStore operations (init, add).
                    alert("Error");
                    console.log(errorObject);
                });
            }
    }

On a web browser, this works great. When jsonStoreInit() fires, it sets status and updates the UI to "JSONStore is initialized". On the Cordova app, if I don't utilize manual change detection, it will not update the UI. For example, see below where I have //IF THIS ISN'T HERE, IT WILL NOT UPDATE IN CORDOVA:

       ngOnInit() {
            var collectionName = 'people';
            this.status = "JSONStore is not yet initialized!";
            if(typeof WL !== "undefined" && typeof WL.JSONStore.get(collectionName) !== "undefined")
                this.status = "JSONStore is initialized!";

                //IF THIS ISN'T HERE, IT WILL NOT UPDATE IN CORDOVA
                this.changeDetector.markForCheck();
                this.zone.run(()=> function(){});
            }
       }

       jsonStoreInit(){
            var that = this;
            var collectionName = 'people';

            // Object that defines all the collections.
            var collections = {

                // Object that defines the 'people' collection.
                people : {

                    // Object that defines the Search Fields for the 'people' collection.
                    searchFields : {name: 'string', age: 'integer'}
                }
            };

            // Optional options object.
            var options = { };

            /* // Optional username, default 'jsonstore'.
            username : 'carlos',

            // Optional password, default no password.
            password : '123',

            // Optional local key generation flag, default false.
            localKeyGen : false
            };*/

            WL.JSONStore.init(collections, options).then(function () {

                // Data to add, you probably want to get
                // this data from a network call (e.g. MobileFirst Adapter).
                var data = [{name: 'carlos', age: 10}];

                // Optional options for add.
                var addOptions = {

                    // Mark data as dirty (true = yes, false = no), default true.
                    markDirty: true
                };

                // Get an accessor to the people collection and add data.
                return WL.JSONStore.get(collectionName).add(data, addOptions);
            })

            .then(function (numberOfDocumentsAdded) {
                that.status = "JSONStore is initialized!"

                //IF THIS ISN'T HERE, IT WILL NOT UPDATE IN CORDOVA
                this.changeDetector.markForCheck();
                this.zone.run(()=> function(){});
            })

            .fail(function (errorObject) {
            // Handle failure for any of the previous JSONStore operations (init, add).
                alert("Error");
                console.log(errorObject);
            });
        }

I'm also seeing this on simple button clicks to set a variable. Nothing happens in Cordova unless I manually use change detection. I am just learning Angular 2, so any help on what I'm doing wrong is greatly appreciated.

kemsky
  • 14,727
  • 3
  • 32
  • 51
Derek Daley
  • 160
  • 8

1 Answers1

3

zone.js patches XHR object and other apis like setInterval, addEventListener, Promise so angular is notified when something happens and it triggers change detection itself.

It looks like JSONStore is using different Promise implementation (jQuery?) which is not patched by zone.js, so you have to trigger change detection manually or wrap you callbacks in zone.run.

kemsky
  • 14,727
  • 3
  • 32
  • 51
  • 1
    I follow what you are saying. I'm still confused as to why it will work when running the same code without manual change detection on a node server. Then when it's deployed to a mobile device inside the Cordova wrapper, it doesn't work. – Derek Daley Jan 28 '17 at 02:31
  • Try to add `console.log('zone', Zone.current);` to check current zone. Zone is global variable, may you will have to add typing definition to use it. – kemsky Jan 28 '17 at 15:10
  • Sorry for the delay.... It's being logged as "angular" on the web and parent is Zone. When I check the console from cordova, it's logged as "" and parent is null. – Derek Daley Jan 31 '17 at 00:51
  • Any idea what I can check to see why it's falling out of the angular zone? – Derek Daley Feb 01 '17 at 12:40
  • 1
    it seems to be the reason, promise is not patched under cordova. You have two options: 1. create wrapper service and wrap callbacks with zone.run 2. try to load zone.js first as early as possible (i'm not familiar with cordova so i'm not sure if this can be done), also if json plugin uses custom promises under cordova it wont be patched anyway. See https://github.com/angular/zone.js/issues/218 – kemsky Feb 01 '17 at 14:52
  • thank you for the information. It's definitely not what I wanted to hear, but nonetheless, you answered it :) – Derek Daley Feb 01 '17 at 15:12