$ selective update by service resolution


I have a service that fetches data asynchronously and exposes that to a controller. There it is bound to $scope

and used in the view.
What I don't understand is the update differences, depending on how this service is used in the controller.


The service does not provide promises for the data, but rather represents the data itself. I modeled it below with timeouts:

(edit: I've added initialization to the variable Opt

to show that this doesn't solve the problem.)

app.service("Options", ["$q", "$timeout", function ($q, $timeout) {
    var Opt = {

    $timeout(function () {
        Opt.people = [ {frst: "Johnny", last: "Walker"},
                       {frst: "Jack", last: "Daniels"},
                       {frst: "Jim", last: "Bean"} ];
    }, 1000);

    $timeout(function () {
        Opt.symbols = [ {name: "Pi", descr: "circles"},
                        {name: "Phi", descr: "ratios"},
                        {name: "Psi", descr: "waves"},
                        {name: "Chi", descr: "distributions"} ];
    }, 2000);

    $timeout(function () {
        Opt.cities = [ {name: "Amsterdam", country: "Netherlands"},
                       {name: "Cairo", country: "Egypt"},
                       {name: "Santiago", country: "Chile"} ];
    }, 3000);

    /* etc */

    return Opt;


Then it is used in the controller like this:

app.controller("Ctrller", ["$scope", "Options", "$timeout", function ($scope, Options, $timeout) {
    $scope.options = Options; //updating
    $scope.symbols = $scope.options.symbols; //not updating
    $scope.symbols = Options.symbols; //not updating either

        $scope.symbols = $scope.options.symbols; //updating
    }, 4000);



I created a demo in Plnkr here .

As you can see, the second item select

in the view (and the 'symbol' property for $scope

) is updated after 4 instead of 2 seconds. If it wasn't in the controller $timeout

, it certainly won't happen.

Why is this so? Why aren't the changes cascading through?



source to share

2 answers

You are trying to assign $scope.symbols


or Options.symbols

before the array symbols

exists in the object returned by the service Options

, so it is $scope.symbols

assigned ( ) undefined

rather than a symbol object reference. You can see this by adding a few console statements before attempting assignments. Since the object symbols

doesn't exist yet, your variable $scope.symbols

cannot refer to it.

This is not a problem with people

or cities

because you are accessing them through an object $scope.options

that refers to the object Opt

returned by the service Options

. Since the base link remains constant, yours ng-repeats

sees changes in the child objects people

and cities


If you really want to assign Options.symbols

to $scope.symbols

, you can execute it with a clock on $scope.options.symbols


$scope.$watch('options.symbols', function(value) {
    $scope.symbols = value;


Change after plunger update

Revised plunker continues to display the same behavior because initialized people

, cities

and symbols

overwritten $timeout

. If you want to keep the link the same, you shouldn't use the operator =

in $timeout

. One option would be to iterate over the returned list and add each item with a click:

$timeout(function () {
    results = [ {name: "Pi", descr: "circles"},
                {name: "Phi", descr: "ratios"},
                {name: "Psi", descr: "waves"},
                {name: "Chi", descr: "distributions"} ];
    angular.forEach(results, function(result) {
}, 2000);


Here is a revised plunker with my suggested changes.

There may be better ways to do this, but the key point is that you cannot reassign Opt.symbols

to any other object (even if that other object is also an array).

Another approach would be to change Opt.symbols

how an object with an array inside it, your reference $scope.symbols

points to an object ( Opt.symbols

) and can look at internal values.

Opt = {
    people: [],
    symbols: {},
    cities: []

$timeout(function() {
    Opt.symbols.values = [ {name: "Pi", descr: "circles"},
                           {name: "Phi", descr: "ratios"},
                           {name: "Psi", descr: "waves"},
                           {name: "Chi", descr: "distributions"} ]; 
}, 2000);


If you went this route you will need to tweak your ng options to look like,

ng-options="s as s.name for s in symbols.values"


Here is a working plunker of this approach.

There are other approaches that you could take outside of the two examples given that make sense for your project and you need to make a decision. The key point is that $timeout

you cannot reassign a value Opt.symbols

and expect to $scope.symbols

refer to a new value.



In index.html you specified ng-options correctly for 'options.people' and 'options.options', but forgot to do it for 'characters'


ng-options="s as s.name for s in symbols"



ng-options="s as s.name for s in options.symbols"


Here's a new plunker:




All Articles