简体   繁体   中英

AngularJS scope variable not setting properly

I am using electron-json-storage and I'm attempting to set an AngularJS $scope variable equal to the data stored.

Below is my code:

portal.controller('portalViewController', function($scope) {
    //$scope.url = "http://www.google.com"; //correctly sets $scope.url to google.com
    storage.get('portal_url', (err, data) => {
        console.log(data.url); //prints out data as it should
        $scope.url = data.url;
    });
});

As you can see, I have each individual component of this working, but when I combine them, the $scope.url does not seem to be getting set. I've been stuck on this for a while now and can't figure out what the issue is. I'm fairly new to AngularJS so this may be something really simple that I'm missing.

Thanks for any help you can provide!

As storage seems to be a third party plugin, so any change in the $scope does not execute the digest cycle. Use $timeout to force a digest cycle so as the changes gets rendered in UI.

portal.controller('portalViewController', function($scope, $timeout) {
    storage.get('portal_url', (err, data) => {
        console.log(data.url); //prints out data as it should
        $timeout(function(){
            $scope.url = data.url;
        });
    });
});

If the callback is truly from a third-party source outside the AngularJS execution context, one can simply use $apply :

portal.controller('portalViewController', function($scope) {
    storage.get('portal_url', (err, data) => {
        $scope.$apply(function() {
            $scope.url = data.url;
        });
    });
});

From the Docs:

AngularJS modifies the normal JavaScript flow by providing its own event processing loop. This splits the JavaScript into classical and AngularJS execution context. Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc... You can also use $apply() to enter the AngularJS execution context from JavaScript.

Keep in mind that in most places (controllers, services) $apply has already been called for you by the directive which is handling the event. An explicit call to $apply is needed only when implementing custom event callbacks, or when working with third-party library callbacks.

— AngularJS Developer Guide - Integration with the browser event loop


Converting Callback-based APIs to AngularJS Promise-based APIs

One can integrate a callback-based API into the AngularJS framework by creating a service:

app.service("storageAPI", function($q) {
    this.get = function(url) {
        var deferred = $q.defer();
        storage.get(url, (err, data) => {
            if (err) { 
                deferred.reject(err);
            } else {
                deferred.resolve(data);
            };
        });
        return deferred.promise;
    };
});

Usage:

app.controller('portalViewController', function($scope, storageAPI) {
    storageAPI.get('portal_url')
      .then(function(data) {
         $scope.url = data.url;
    }).catch(function(err) {
         console.log(err);
    });
});

The advantage of this approach is that it integrates the API into the AngularJS framework without the need of $apply (the $q service does that automatically). In addition, it robustly handles errors from the API.

For more information, see - AngularJS $q Service API Reference - The Deferred API .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM