在控制器生命周期内检测和使用更改的控制器依赖项

Detecting and using a changed controller dependency during controller lifetime

为了便于理解,假设我有一个 AngularJS 应用程序,它具有与 Whosebug 相似的数据,因此它:

  1. 正在使用通常的 ngRoute/$routeProvider
  2. 有一个 userService returns favouriteignore 已登录用户的标签列表 - 两者列表是同时获取的,对它们的请求是一个承诺,当解析时缓存这些列表
  3. 有一个显示问题列表的视图,其中 QuestionsController 提供其模型(类似于 Whosebug)
  4. QuestionsController 发出问题请求,然后根据缓存的标签列表适当地标记它们

作为 recommended guideline 当控制器依赖其他异步数据时,我们应该将它们卸载到路由 resolve 部分,这样当控制器被实例化时,这些承诺就已经解决了。因此,我将提取标签列表的任务卸载到它,以便两个列表都准备就绪并注入到控制器中。这一切都按预期工作。

我的问题列表视图的附加功能是,当用户单击问题上显示的标签时,它会自动将此标签添加到收藏夹列表(或者当该标签已经是收藏夹列表的一部分时关闭它)。

路由配置

...
.when({
    templateUrl: "...",
    controller: "QuestionsController as context",
    resolve: {
        tags: ["userService", function(userService) {
            return userService.getMyTags();
        }]
    }
})
.when(...)
...

控制器伪代码

QuestionsController.prototype.markQuestions = function() {
    this.model.questions.forEach(function(q, idx) {
        // "myTags" is resolve injected dependency
        q.isFavourite = q.tags.any(myTags.favourite);
        q.isIgnored = q.tags.any(myTags.ignored);
    });
};
QuestionsController.prototype.toggleTag = function(tag) {
    var self = this;
    // change tag subscription
    tagService
        .toggleFavourite(tag)
        .then(function() {
            // re-mark questions based on the new set of tags
            self.markQuestions();
        });
};

问题

当视图显示时,所有问题都会加载并根据提供的标签列表正确标记。现在,当用户单击特定标签并且该标签的收藏状态发生更改时,我的控制器的依赖项应该会自动更新。

我该怎么做 因为我的控制器已经实例化并且在实例化过程中注入了标签列表?

我想避免在我的控制器中手动加载这些列表,因为在那种情况下我应该在实例化期间做同样的事情并重用相同的功能而不是在两个地方(路由解析和控制器内部)。

只要您的 "resolved" 变量指的是其他地方使用的同一对象,它们就是同一对象。

因此,如果您的 userService.getMyTags 在概念上类似于以下内容:

.factory("userService", function($timeout){
  var tags = [/*...*/];
  return {
     getMyTags: function(){
        return $timeout(function(){ return tags; }, 500);
     },

     addTag: function(newTag){
        tags.push(newTag);
     }
  }
});

然后任何地方对标签的引用都会发生变化:

.controller("ViewCtrl", function($scope, tags){
  $scope.tags = tags; // tags is "resolved" with userService.getMyTags()
})
.controller("AddTagCtrl", function($scope, userService){
  $scope.addTag = function(newTag){
     userService.addTag(newTag); // changes will be reflected in ViewCtrl
  }
}

plunker,以说明