使用工厂时控制器/模板不共享相同的状态
Controllers/templates not sharing same state when using factory
我正在开发一个示例Rails应用程序,使用AngularJS从JSON后端馈送。下面列出了代码。我在两条路由之间共享工厂数据时遇到问题,每条路由由单独的控制器控制(在本例中实际上是相同的)。
下面是一个场景:
- 假设我已经导航到/list 路径并刷新了浏览器。我的人员列表将出现。
- 我单击一个人,它会将其切换为选中并以红色突出显示。
- 我导航到/roller 路径,但未选择该人员。
- 我导航回/list 路径,但那里不再选择"人员"。
- 我在不刷新浏览器的情况下重复这些步骤,现在保持对任何人员的选择。
这是另一种情况:
- 假设我已经导航到/roller 路径并刷新了浏览器。
- 我单击"人员"以选择它。
- 我导航到/list 路径,其中也选择了该人员。
- 我导航回/roller 路径,其中该人员仍处于选中状态。
这两种情况都不一致。从本质上讲,这种行为是不可预测的(我对 Angular 内部工作原理的理解有限)。两条路线在驶离时要么保留选择,要么不保留选择。我想知道 Angular 中发生了什么,以便我可以找到这个用例的可靠替代方案。
(索引正文.html)
<header>
<nav>
<a id="logo" href="/#/"><h2>Roller</h2></a>
<ul class="links">
<li><a href="/#/people">People</a></li>
<li><a href="/#/lists">Lists</a></li>
</ul>
</nav>
</header>
<div id="main" ng-app="RollerApp">
<ng-view></ng-view>
</div>
列表.html
<div ng-controller="ListCtrl">
<ul>
<li ng-repeat="person in people">
<a class="selected-{{ person.selected }}" ng-click="toggleSelect( person )">{{ person.name }}</a>
</li>
</ul>
</div>
滚筒.html
<div ng-controller="RollerCtrl">
<ul>
<li ng-repeat="person in people">
<a class="selected-{{ person.selected }}" ng-click="toggleSelect( person )">{{ person.name }}</a>
</li>
</ul>
</div>
滚筒.js
rollerApp = angular.module('RollerApp', ['People']);
rollerApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider){
$routeProvider.when('/', {
templateUrl: 'assets/roller.html'
}).when('/lists', {
templateUrl: 'assets/lists.html'
}).otherwise({
template: 'Not Found'
});
}]);
roller_ctrl.js
rollerApp = angular.module('RollerApp');
rollerApp.controller('RollerCtrl', ['$scope', 'Person', function($scope, Person){
$scope.people = Person.all();
$scope.toggleSelect = function(person){
person.selected = !person.selected;
};
}]);
list_ctrl.js
rollerApp = angular.module('RollerApp');
rollerApp.controller('ListCtrl', ['$scope', 'Person', function($scope, Person){
$scope.people = Person.all();
$scope.toggleSelect = function(person){
person.selected = !person.selected;
};
}]);
person_factory.js
people = angular.module('People', ['ngResource']);
people.factory('Person', ['$resource', '$q', function($resource, $q){
var _person = $resource('people/:id', {id: '@id'}, {});
var people = null;
function query(){
if(!people){
var deferred = $q.defer();
people = _person.query(function(success){
deferred.resolve(success);
}, function(failure){
deferred.reject(failure);
});
return deferred.promise;
}else{
return people;
}
}
return {
all: function(){
return query();
}
}
}])
样式.css
a.selected-true { color: red }
经过编辑以包括@jpmorin建议的实施
补充问题
使用工厂使用来自另一个工厂的数据时,如何使用基于承诺的方法?
列表工厂.js
lists = angular.module('Lists', ['ngResource']);
lists.factory('List', ['$resource', '$q', 'Person', function($resource, $q, Person){
var _list = $resource('lists/:id', {id: '@id'}, {});
var people = Person.all();
var lists = null;
function query(){
if(!lists){
var deferred = $q.defer();
lists = _list.query(function(success){
success.forEach(function(list){
people.then(function(value){
addPeopleToList(list, value);
});
});
deferred.resolve(success);
}, function(failure){
deferred.reject(failure);
});
return deferred.promise;
}else{
return lists;
}
}
function personById(id, people){
return people.filter(function(person){ return id === person.id })[0];
}
function addPeopleToList(list, people){
ids = list.people.map(function(person){ return person.id });
list.people = ids.map(function(id){ return personById(id, people) });
}
return {
all: function(){
return query();
}
}
}])
上面的List实现在我的原始问题的另一半中成功(我缩小了它以简化示例)。但是,我谨慎地让这个"List"工厂知道从Person.all()
返回的值是一个承诺。除了用我自己的"类"(通常是首选项)包装这些组件之外,还有没有另一种方法来限制这种跨工厂知识?
我创建了一个演示,尝试在Person
工厂中使用$q
和$timeout
来模拟数据库调用。
演示 http://plnkr.co/edit/Q5NbIuj2JUMxjf8OkT8J?p=preview
在第一次调用时,将从数据库请求数据,但随后会缓存数据以供下一次调用使用。由于它们是对象,并且它们的引用通过您的应用程序传递,因此您所做的任何修改都将在其他任何地方可用。在这里我们使用承诺,因为它是一个异步调用,我们不知道数据何时可用。因此,在控制器中,您必须使用以下方法等待 promise 的回调:
Person.all().then(function(data) {
$scope.people = data;
});
第一次调用会有小的延迟,但下一次调用将使用缓存的数据即时调用。
- 在Knockoutjs中的ViewModels之间共享变量状态
- new Datamap() 在调用之间保持内存的共享状态
- 在角度上不同控制器之间共享状态
- 如何通过React Native中的组件共享登录状态
- JavaScript-使用sessionStorage保存文档之间共享的复选框状态
- 正在加载ui路由器状态下的共享模型
- Ember JS中控制器之间共享状态的正确方式
- 如果我两次使用相同的反应/冗余组件,它们会共享状态吗?
- 使用工厂时控制器/模板不共享相同的状态
- 摩卡测试共享状态,因为范围不好
- ui路由器——具有一条路由'的URL与另一个具有$stateParams的状态共享同一级别
- 更新React组件共享状态
- 如何在没有闭包的情况下对共享状态进行编程
- 在ui路由器中的状态之间共享ng模型数据
- 在控制器之间共享非单例状态(Angular Architecture)
- 在子组件之间共享父组件状态'州
- 保存公用共享的值状态(添加到URL)
- 如何在angularjs中使用两个不同的ui路由器在状态之间共享作用域数据?
- 使用服务在控制器之间共享状态
- 使用AngularJS进行SPA设计——在一些页面上共享状态,但不是所有页面