AngularJS .value()无法在控制器中获取更新后的值
问题原因分析
这事儿核心是JavaScript引用类型的赋值逻辑在捣鬼,再结合AngularJS的注入特性导致的:
你用.value()注册的errorCollectionObject是一个单例空对象,当你在RUN块里通过$http拿到数据后,如果直接做了errorCollectionObject = response.data这种操作,本质上是把RUN块局部作用域里的变量指向了新的对象地址,但原来通过.value()注入到LoginController的那个空对象的引用根本没变化——控制器拿到的还是最初的空对象引用,自然看不到更新后的数据。
而你在RUN块里console.log能看到预期结果,是因为你打印的已经是那个新赋值的对象了,不是原来的空对象。
解决方案
针对这个问题,有两种常用的解决思路:
思路1:修改原对象的属性(保持引用不变)
既然是引用类型,我们不替换整个对象,而是直接修改原对象的属性或者用合并方式把新数据放到原对象里,这样所有持有该对象引用的地方(包括控制器)都会同步看到更新:
// 1. 初始化.value() angular.module('yourApp').value('errorCollectionObject', {}); // 2. RUN块里正确修改原对象 angular.module('yourApp').run(['$http', 'errorCollectionObject', function($http, errorCollectionObject) { $http.get('/your-api-url').then(function(response) { // 用angular.extend把新数据合并到原对象里,保持引用不变 angular.extend(errorCollectionObject, response.data); // 或者直接给原对象添加属性:errorCollectionObject.items = response.data; console.log(errorCollectionObject); // 这里的原对象已经更新 }); }]); // 3. 控制器里获取更新后的数据 angular.module('yourApp').controller('LoginController', ['$scope', 'errorCollectionObject', function($scope, errorCollectionObject) { // 注意:$http是异步请求,控制器初始化时可能数据还没返回,所以用$watch监听变化 $scope.$watch(function() { return errorCollectionObject; }, function(newVal) { // 当对象内容变化时触发 if (!angular.equals(newVal, {})) { console.log('拿到最新的error集合:', newVal); } }, true); // 第三个参数true表示深度监听对象属性变化 }]);
思路2:用Service/Factory封装值(支持替换整个对象)
如果你的业务场景确实需要替换整个对象而不是修改属性,那最好用.factory()或者.service()来封装这个值,通过getter/setter方法管理引用的更新:
// 1. 用Factory封装error集合 angular.module('yourApp').factory('errorCollectionService', function() { var _collection = {}; // 内部存储的集合 return { getCollection: function() { return _collection; }, setCollection: function(newCollection) { _collection = newCollection; // 可以直接替换整个对象 } }; }); // 2. RUN块里更新集合 angular.module('yourApp').run(['$http', 'errorCollectionService', function($http, errorCollectionService) { $http.get('/your-api-url').then(function(response) { errorCollectionService.setCollection(response.data); console.log(errorCollectionService.getCollection()); // 最新数据 }); }]); // 3. 控制器里获取最新数据 angular.module('yourApp').controller('LoginController', ['$scope', 'errorCollectionService', function($scope, errorCollectionService) { $scope.$watch(function() { return errorCollectionService.getCollection(); }, function(newVal) { console.log('拿到最新的error集合:', newVal); }, true); }]);
关键提醒
不管用哪种方式,都要注意$http是异步操作——控制器初始化的时候,请求可能还没完成,所以直接在控制器里打印errorCollectionObject大概率还是空对象,必须用$watch监听变化,或者在请求完成后再触发控制器里的逻辑。
内容的提问来源于stack exchange,提问作者Ankit Prajapati
相关产品推荐
相关产品推荐

