0

I'm really struggling with this because it should be very simple. I have a route with a controller defined called login. In my template I have the following data binding {{error}} which is defined in my controller after executing a method from a custom service, and resolving the returned promise.

Controller

app.controller("login", ['$scope','XMLMC', 'ManageSettings', function ($scope,api,ManageSettings) {
    $scope.error = 'test';
    $scope.login = function() {
        var params = {
            selfServiceInstance: "selfservice",
            customerId: $scope.username,
            password: $scope.password
    };
        var authenticated = api.request("session","selfServiceLogon",params).then(function(response) {
            ManageSettings.set("session",response, $scope);

            if(response.status === "ok") {
                window.location.href = 'portal';
            } else {
                $scope.error = response["ERROR"];
                console.log($scope.error);
            }
        });

    };
}]);

The console shows Customer not registered. Showing that $scope.error has been updated appropriately, but the view never gets updated. My service is below, and please note that I am doing nothing "outside" of angular and so I should not have to $apply() anything manually.

app.factory("XMLMC", ['$http', '$q', function ($http, $q) {
    function XMLMC($http, $q) {
        $http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';

        var that= this;

        this.prepareForPost = function(pkg) {
            return JSON.stringify(pkg);
        };

        this.request = function(service, request, params, host, newsession) {
            var def = $q.defer();
            var P = def.promise;

            if(request === "analystLogon") {
                newsession = true;
            }

            var call = {
                service: service,
                method: request,
                params: params
            };

            if(host) {
                call.host = host;
            } else {
                call.host = "localhost";
            }

            if(newsession) {
                call.newsession = "true";
            }

            var pkg = {
                contents: this.prepareForPost(call)
            };




            $http.post('php/XMLMC/api.php', jQuery.param(pkg)).success(function (response,status) {
                    that.consume(response, def);

                }).error(function (response,status) {
                    def.reject(response,status);
                });

            return P;


        };

        this.consume = function(response, defer) {
            console.log(response);
            var resp = response[0],
                digested = {},
                i;

            digested.status = resp["attrs"]["STATUS"];
            var params = resp["children"][0]["children"];
            for(i=0; i < params.length; i++) {
                var key = params[i]["name"];
                var val = params[i]["tagData"];
                digested[key] = val;
            }

            defer.resolve(digested);
            //return digested;
        };
    }

    return new XMLMC($http, $q);
}]);

I've created a plunk here with the code exactly as it is on my test server. The routes and etc aren't working for obvious reasons, but you can at least see the code and how it works together

http://plnkr.co/edit/AodFJfCijsp2VWxWpbR8?p=preview

And here is a further simplified plunk where everything has one scope and one controller and no routes. For some reason, this works in the plunk but the $http method fails in my server

http://plnkr.co/edit/nU4drGtpwQwFoBYBfuw8?p=preview

EDIT

Even this fails to update

var authenticated = api.request("session","selfServiceLogon",params).then(function(response) {
            ManageSettings.set("session",response, $scope);

    $scope.error = "foo!";

            if(response.status === "ok") {
                window.location.href = 'portal';
            } 
        });
richbai90
  • 4,994
  • 4
  • 50
  • 85
  • No obvious problems from what you've shown. Is `{{error}}` appearing as 'test' in the view? – Marc Kline Jun 03 '14 at 19:42
  • Yes it is, but it never updates from test – richbai90 Jun 03 '14 at 19:42
  • Just to demonstrate that this should work without a problem: http://plnkr.co/edit/qk5o1XwUtwWE8DTsdZ5K?p=preview Any way you can post a Plunker demonstrating the issue? It could be that you find the problem while putting one together... and I think it's the only way anyone will be able to help you any further unless there is something which I am just blatantly missing. – Marc Kline Jun 03 '14 at 19:56
  • 1
    Went one step further and used his same code, replacing $http call with $timeout call. $scope.error correctly updates after the timeout promise is resolved: http://jsfiddle.net/SuR3K/3/ – Patrick Jun 03 '14 at 20:04
  • I've edited my post with 2 plunks, one is exactly what I have in my test server, and one is a simplified test which strangely enough does not have the same problem that my test server does though very little was changed – richbai90 Jun 03 '14 at 21:24
  • I've narrowed the issue a bit, but I'm still lost as to what's causing this or how ti fix it. Any help is appreciated – richbai90 Jun 03 '14 at 21:31
  • Ever find a solution? Have the same issue where I update $scope.MyVar in the .then() function but the scope variable doesn't change in the view. – Dennis Apr 06 '15 at 19:32
  • I think I ended up taking a different route but I no longer have the code so I don't remember what that was – richbai90 Apr 06 '15 at 21:00

1 Answers1

0

It appears that $scope.$apply is indeed needed. See AngularJS - why is $apply required to properly resolve a $q promise?

To quote @pkozlowski.opensource:

In AngularJS the results of promise resolution are propagated asynchronously, inside a $digest cycle. So, callbacks registered with then() will only be called upon entering a $digest cycle.

Community
  • 1
  • 1
Matthias
  • 13,607
  • 9
  • 44
  • 60
  • adding a $apply() after the resolve method did not return different results. Furthermore wrapping the then function in a $apply() method caused an error stating there was already an apply in progress – richbai90 Jun 03 '14 at 21:03