最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why do I need to use angular.copy in my factory? - Stack Overflow

programmeradmin1浏览0评论

I'm trying to have the Thing factory make an HTTP request and be able to use the response in my controller.

  1. In my factory I have to do angular.copy(data, arr). Simply doing arr = data doesn't work. Why is this? angular.copy() just a) deletes everything from arr and b) iterates through data and assigns stuff to arr. The only difference between that and arr = data is that arr points to data rather than a new copy of data. Why would this matter? And why doesn't arr = data.slice(0) work (from what I understand, it's pretty much the same as angular.copy)?

  2. What is the best way to acplish my goal? (use the factory properly)

main.html

<div class="container">

<div class="page-header">
  <h1>Test App</h1>
</div>

<ul>
  <li ng-repeat="thing in things">{{thing.name}}</li>
</ul>

</div>

main.controller.js

'use strict';

angular.module('testApp')
  .factory('Thing', function($http) {
    var arr = [];
    return {
      things: arr,
      get: function() {
        $http.get('/api/things').success(function(data) {
          angular.copy(data, arr); // this works
          // arr = data; but this doesn't
          // arr = data.slice(0); and neither does this

        });
      }
    };
  })
  .controller('MainCtrl', function ($scope, Thing) {
    Thing.get();
    $scope.things = Thing.things;
  });

I'm trying to have the Thing factory make an HTTP request and be able to use the response in my controller.

  1. In my factory I have to do angular.copy(data, arr). Simply doing arr = data doesn't work. Why is this? angular.copy() just a) deletes everything from arr and b) iterates through data and assigns stuff to arr. The only difference between that and arr = data is that arr points to data rather than a new copy of data. Why would this matter? And why doesn't arr = data.slice(0) work (from what I understand, it's pretty much the same as angular.copy)?

  2. What is the best way to acplish my goal? (use the factory properly)

main.html

<div class="container">

<div class="page-header">
  <h1>Test App</h1>
</div>

<ul>
  <li ng-repeat="thing in things">{{thing.name}}</li>
</ul>

</div>

main.controller.js

'use strict';

angular.module('testApp')
  .factory('Thing', function($http) {
    var arr = [];
    return {
      things: arr,
      get: function() {
        $http.get('/api/things').success(function(data) {
          angular.copy(data, arr); // this works
          // arr = data; but this doesn't
          // arr = data.slice(0); and neither does this

        });
      }
    };
  })
  .controller('MainCtrl', function ($scope, Thing) {
    Thing.get();
    $scope.things = Thing.things;
  });
Share Improve this question edited Feb 7, 2015 at 5:31 Adam Zerner asked Feb 7, 2015 at 5:25 Adam ZernerAdam Zerner 19.4k18 gold badges101 silver badges174 bronze badges 4
  • angular.copy works for Objects or arrays, is data an object by any chance? BTW you should make use of hoisting and extract your anon functions into named functions and simply pass the function name in to the factory and controller method. Makes it much easier to figure out the ponents of a module. – Robert Commented Feb 7, 2015 at 5:35
  • data is an array of objects. – Adam Zerner Commented Feb 7, 2015 at 5:41
  • 1 It works because arr (array) is a reference, and you need to preserve the reference in order for the scope bindings to work. Otherwise, you are just overwriting arr with a new reference - which is pletely different object than the reference that was originally bound to the scope. – Michael Kang Commented Feb 7, 2015 at 5:49
  • @pixelbits could you elaborate? I thought that scope bindings had to do with $scope itself. How does the factory affect scope bindings? – Adam Zerner Commented Feb 7, 2015 at 6:11
Add a ment  | 

2 Answers 2

Reset to default 7

Your problem is not related to angular, but to Javascript.

var arr = [] // arr is a pointer to an empty array
var things = arr  // things is a pointer to the same empty array
arr = data   // now arr points to data, but things still points to the empty array

You can convince yourself of that by running the following code:

var a = [1];
var b = a;
a = [2];
// Now if you console.log a and b, a === [2] and b === [1]

However if you manipulate the property of an object

var a = { data: 1 }
var b = a;
a.data = 2;
// Now a.data and b.data are the same: 2
a = { data: 3 };
// Here we changed a, not its property, so a and b are not the same anymore
// a.data === 3 but b.data === 2

If you understand that, there are many ways to solve your issue, such as:

angular.module('testApp')
  .factory('Thing', function($http) {
  var obj = {};
  return {
    things: obj,
    get: function() {
      $http.get('/api/things').success(function(data) {
        obj.data = data;
      });
    }
  };
})

And in your HTML use things.data.

Or if you don't want to use an object property, but directly the array, instead of replacing the pointer you need to only update the content of the array (so arr still points to that same array):

angular.module('testApp')
  .factory('Thing', function($http) {
  var arr= [];
  return {
    things: arr,
    get: function() {
      $http.get('/api/things').success(function(data) {
        for (var i in data) {
          arr[i] = data[i];
        }
      });
    }
  };
})

This happens because you set arr to some new instance of an array instead of using the current one. Here is an analogy to what you're doing:

var foo = function() {
    this.test = 'hello';
    console.log(this.test);
};

foo = function() {
    this.test = 'other';
    console.log(this.test);
};

console.log(foo()); // outputs other

angular.copy instead does something like this:

// foreach item in the source (in this case data)
arr.push({
   my: "value"
});
发布评论

评论列表(0)

  1. 暂无评论