1

I have an AngularJS Service defined as follows:

function testService(testProvider) {
  var ref = this;
  ref.firstLevel = {};
  ref.secondLevel = {};

  initialize();

  function initialize() {
    testProvider.getData().then(function(result) {
      ref.firstLevel = result;
      ref.secondLevel.testData = result;
    });
  }
}

The testProvider is a simple wrapper around $http.get that fetches data from a JSON. The controller copies over these properties:

function testController(testService) {
  var vm = this;

  vm.firstLevel = testService.firstLevel;
  vm.secondLevel = testService.secondLevel;
}

When I create bindings in my template, the second level works, the first level doesn't.

<!-- Doesn't work -->
<p>{{vm.firstLevel.testProperty1}}</p>  
<p>{{vm.firstLevel.testProperty2}}</p>

<!-- Does work -->
<p>{{vm.secondLevel.testData.testProperty1}}</p>  
<p>{{vm.secondLevel.testData.testProperty2}}</p>  

See this Plunker for a working example:

https://plnkr.co/edit/pLInqcaJNhhbQWbvTUEE

Why doesn't the first level example work?

Daan
  • 6,952
  • 4
  • 29
  • 36

1 Answers1

2

This is because when you overwrite an object in Javascript, you actually lose the reference to the actual object.

testProvider.getData().then(function(result) {
    ref.firstLevel = result;
    ref.secondLevel.testData = result;
});

Here ref.firstLevel = result overwrites the reference to the object that was initialized to {}. Any data bindings that you had on that object would be lost after this line.

Whereas, by doing ref.secondLevel.testData = result, you are not rewriting the object, rather you are only modifying the object by adding an extra key testData. Thus the reference is still preserved and so are the AngularJS bindings.

See this answer for more clarity.

Community
  • 1
  • 1
hallucinations
  • 3,424
  • 2
  • 16
  • 23
  • That was my initial theory, but I *thought* I had ruled this out with a test. But I have more faith in your (and my) theory than in the quick test I hacked together :) – Daan Feb 12 '16 at 08:01
  • 1
    Timing is important here: first the object gets initalized in the service, *then* the controller copies the references to the object, *then* the Promise resolves, replacing the object alltogether. In my (incorrect) test, I replaced the object in the initialize phase of the Service, which is **before** the controller gets its reference, so all seemed to work fine. – Daan Feb 12 '16 at 13:51
  • 1
    Indeed it is! I kinda guessed that you would be doing something like this when you said about your incorrect test. I was thinking that what if we needed to rewrite the object keeping its reference and learned angular.copy has a version which allows us to do it: `angular.copy(source, [destination]);`. Never knew that it could take a second parameter. – hallucinations Feb 12 '16 at 14:43
  • Thanks for the `angular.copy` reference, that's a good one to keep in mind! I'm not sure what the performance implications are if you go and deep-copy objects around like that, but let's leave that for another question :) – Daan Feb 12 '16 at 14:57