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';
            } 
        });
8
  • No obvious problems from what you've shown. Is {{error}} appearing as 'test' in the view? Commented Jun 3, 2014 at 19:42
  • Yes it is, but it never updates from test Commented Jun 3, 2014 at 19:42
  • Just to demonstrate that this should work without a problem: 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. Commented Jun 3, 2014 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: jsfiddle.net/SuR3K/3 Commented Jun 3, 2014 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 Commented Jun 3, 2014 at 21:24

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.