0

I'm having trouble figuring out a way to use local variables in a controller that contains an asynchronous call. Is there a way to force the controller to run [at least some of] the code sequentially?

Controller:

angular.module('myApp.controllers.contacts', [])

.controller('CtrlContacts',
[       '$scope','apiUsers',
function($scope,  apiUsers){

    var selected = $scope.selected = [];

    apiUsers.getShortlist().then(function(response){

        // WILL correctly populate the associated view
        $scope.selected = response.data.data.contacts;

        // WILL NOT correctly populate the associated view
        selected = response.data.data.contacts;
        console.log(selected); // shows the correct data

    });
}

;

If apiUser.getShortlist() were not an asynchronous call, this would work just fine.

I wouldn't mind so much, but the variables can get a bit unwieldy. Additionally, it's a pain trying to cross-train people when occasional responses have to be "I'm not sure why, but do it or angular will get angry".

=========

EDIT

=========

Thanks Esteban and Greg.

Was thinking of my selected variable as an object property, like a dummy. I'm actually using "controller as" syntax, so I ended up writing my controller like this:

Controller:

angular.module('myApp.controllers.contacts', [])

.controller('CtrlContacts',
[       '$scope','apiUsers',
function($scope,  apiUsers){

    var self = this;
    var selected = $scope.selected = [];

    apiUsers.getShortlist().then(function(response){

        self.selected = response.data.data.contacts;

    });
}

;
1
  • To access anything from your view, it needs to be within $scope. It's hard to tell what you're asking. Is it that you want your views to be able to access vars that aren't a part of $scope? Commented Oct 13, 2014 at 23:42

1 Answer 1

2

This has nothing to do with 'angular getting angry'. This how references work in most programming languages. To fix your issue you can do the following:

var selected = $scope.selected = [];

apiUsers.getShortlist().then(function(response){
    selected = $scope.selected = response.data.data.contacts;
});

Alternative:

var selected = $scope.selected = [];

apiUsers.getShortlist().then(function(response){
    // this will update the array itself:
    $scope.selected.splice(0, $scope.selected.length, response.data.data.contacts);
});

Why do you need to update the selected variable?
The reason is that selected is pointing to an array you are not expecting it to. Take the following example code:

var foo,
bar;

// foo && bar both will look this: [1] && [1]
foo = bar = [1];    

// foo && bar will look this: [1] && [1,2]
bar = [1,2];

What you are changing is the reference of bar to be something different from foo. If, however you update the underlying array the reference will stay the same and your values will be the same. An example:

var foo,
bar;

// foo && bar both will look this: [1] && [1]
foo = bar = [1];    

// foo && bar will look this: [1,2] && [1,2]
bar.push(2);
3
  • in your first solution, why is it that the first line wouldn't save a reference that the .then() block could use to populate scope? Commented Oct 13, 2014 at 23:57
  • @user3822241 Because you are redefining what the local variable selected is equal to, it will no longer point to the same object as the $scope.selected property. Which means they no longer mean the same thing. Hence why you have to assign the result back to both to keep them in sync. Commented Oct 13, 2014 at 23:59
  • @user3822241 Greg is correct, you are changing the variable's reference and not the underlying array itself. If you take a look at my updated answer it better explains what is going on. Commented Oct 14, 2014 at 0:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.