Please help me understand the behavior of the angular.

There is a service:

myApp.factory('myService', function($http){ var obj = []; function init () { return $http.get('test.php'). then(function(answ) { obj = answ; }); } function getObj () { return obj; } return { init: init, obj1: obj, obj2: getObj } }) 

And there is a controller that works with this service:

 myApp.controller('myController', function myController($scope, myService){ console.log('0.0 ' + myService.obj1); console.log('0.1 ' + myService.obj2()); myService.obj1 = ['test']; console.log('1.0 ' + myService.obj1); console.log('1.1 ' + myService.obj2()); myService.init() .then(function() { console.log('2.0 ' + myService.obj1); console.log('2.1 ' + myService.obj2()); myService.obj1 = ['test1']; console.log('3.0 ' + myService.obj1); console.log('3.1 ' + myService.obj2()); }); 

As a result, the console will display:

 0.0 0.1 1.0 test 1.1 test 2.0 test 2.1 [*данные от сервера*] 3.0 test1 3.1 [*данные от сервера*] 

I can not understand why this is happening. Obj1 and obj2 come first to refer to the same data, and through obj1 they can be changed and obj2 will notice these changes, but after the data in the service is changed by the service itself, obj1 continues to refer to the old version of the data, and obj2 to the new version , and data changes through obj1 are not visible in obj2 (and vice versa. If you also enter the setter, change data through it, then the changes will be visible in obj2 and not visible in obj1).

Why does obj1 continue to reference the old object?

  • Are you sure that for the given log, the first change was an assignment, and not a push call for example? - Grundy
  • Already not sure. I tried different options there for a long time, I could get confused. Actually, even if the first was a push, the situation does not become clearer. Why, if in the first and second cases we get a link to the same array, after receiving and processing data from $ http, suddenly, the direct link points to the old array, and the getter starts to return the link to the new array? - Tolomuco
  • though ... I guess I got it. If I did in the service not obj = answ; and, for example, obj.push (answ), there would be no difference, right? - Tolomuco
  • Yes, since in this case obj and obj1 would continue to refer to the same object. - Grundy

3 answers 3

After

 myService.obj1 = ['test']; 

myService.obj1 already points to another, newly created array of one value 'test'. Accordingly, there is a different output from myService.obj1 and myService.obj2 ()

True, this does not fit in with your log:

 0.0 0.1 1.0 test 1.1 test 2.0 test 2.1 [*данные от сервера*] 3.0 test1 3.1 [*данные от сервера*] 

Specifically, with the fourth line, where an empty line is expected. Link to Plunker.

  • This moment is not clear to me. Why myService.obj1 = ['test']; does not change the array in the service? It turns out the service after this action becomes 2 properties with the same name? Moreover, if I make a push instead of assignment, the picture will not change either. Experiments have shown that the separation of information occurs at the time of receiving data from the $ http request - Tolomuco
  • myService.obj1 = ['test']; does the same as myService.obj1 = new Array ('test'); those. creates a new array, and assigns a reference to it to the myService.obj1 field. The original array, to which the link was previously stored in myService.obj1, continues to exist; you get it with getObj. - Vladimir Gamalyan
  • If you really need to change the value of the original array, then instead of myService.obj1 = ['test']; you can try myService.obj1.length = 0; myService.obj1.push ('test'); - Vladimir Gamalyan
  • That's it from the push it all started. Push seems to have changed the source array, I decided that everything was working as I had planned, loaded the data from the server and did not see them in the array. He began to understand and came to the conclusion that after processing the http request, the data obtained from the getter correspond to the loaded data, and the data obtained directly in some way "exfoliate" and continue to live their own lives. I would like to see what happens if I refer to this.obj from the service. But so far there is no time. - Tolomuco

I will partially answer myself. I was sure that the service through return {obj1: obj} returns a reference to the obj variable, and not its value. As far as I understand, I was wrong. It remains unclear why, after the first data change, I did not have a discrepancy in myService.obj1 and myService.obj2 (). Actually it confused me.

  • in fact he links and returns :-) - Grundy
  • So what then? Only it seemed to me that I began to understand something, like you! :) - Tolomuco
  • See the next answer: first you save the reference to obj in the field of the object obj1 - when you refer to the properties. for example, length , push , etc. - they were called by obj , since obj1 - referred to it, but as soon as the link was replaced by myService.obj1 = ['test']; - nj, now all operations are performed with the ['test'] array, while obj has remained inside, and the method always returns it. - Grundy
  • Thank you, figured out. - Tolomuco

To understand the work, you can track what the necessary objects refer to at each stage.

 myApp.factory('myService', function($http){ var obj = []; // при инициализации ссылается на пустой массив; function init () { return $http.get('test.php'). then(function(answ) { obj = answ; // после присваивания ссылается на ответ от сервера }); } function getObj () { return obj; // возвращает значение на которое ссылается obj } return { init: init, obj1: obj, // сохраняем ссылку на obj obj2: getObj }; }) 

Now the points in the controller:

 myApp.controller('myController', function myController($scope, myService){ console.log('0.0 ' + myService.obj1); // ссылка на obj -> [] console.log('0.1 ' + myService.obj2()); // возвращает obj -> [] myService.obj1.push('test'); // обновляем значение по ссылке. добавляя в массив на который ссылаемся элемент console.log('1.0 ' + myService.obj1); // -> ['test'] console.log('1.1 ' + myService.obj2()); // -> ['test'] myService.init() .then(function() { // в этот блок попадаем после присваивания в функции init, console.log('2.0 ' + myService.obj1); // obj1 - ссылается на старый массив, так как при присваивании значения переменной obj - она стала ссылаться на новый массив, а obj1 - не изменился -> ['test'] console.log('2.1 ' + myService.obj2()); // возвращает то, что присвоили -> [полученные данные] myService.obj1 = ['test1']; // замена ссылки в obj1 -> ['test1'] console.log('3.0 ' + myService.obj1); // -> ['test1'] console.log('3.1 ' + myService.obj2()); // -> [полученные данные] }); 

Since when assigning a value in the init function, the variable obj began to refer to the new array, and obj1 - continued to refer to the old one - we have a discrepancy.