【问题标题】:Shared variables and multiple controllers AngularJS共享变量和多个控制器 AngularJS
【发布时间】:2016-09-02 04:17:40
【问题描述】:

我正在编写的一个小应用程序上有多个控制器,并且我已经成功地在控制器之间共享了一个“选定”变量,就像这样。

app.service('selectedEmployee', function () {
    var selected = null;

    return 
    { 
        getSelected: function() {
            return selected;
        },
        postSelected: function(employee) {
            selected = employee;
        }
    };

});

我有一个带有员工列表的侧导航栏。当我点击一个员工时,我调用 postSelected 函数,然后调用 getSelected 来设置 $scope.selected。

$scope.selectEmployee = function(employee) {

   //Calling Service function postSelected
    selectedEmployee.postSelected(employee);

    $scope.selected = selectedEmployee.getSelected();

    if ($mdSidenav('left').isOpen()) {
        $mdSidenav('left').close();
    }

}

我的主要内容区域有第三个控制器,这就是我不知道该怎么做的地方。我希望显示来自所选员工的信息,但 Angular 在第一个员工有机会被设置为选中之前编译整个页面,并且员工的后续选择不会重新加载主要内容页面(因为我没有我想告诉他们)。这是我的主要内容控制器:

app.controller('mainContentController', ['$scope','selectedEmployee',
    function ($scope, selectedEmployee) {
        $scope.selected = selectedEmployee.getSelected();
        console.log($scope.selected);
    }
]);

我现在的主要内容视图非常简单

<h2>{{selected.firstName}}{{selected.lastName}}</h2>

我的问题是如何告诉控制器有效地更新其局部视图,以便在我选择员工时显示信息。

GitLab repo

【问题讨论】:

  • 你的问题很难理解。但不用担心,这可能是我的错,或者它是一种难以理解的问题。如果你可以将所有代码推送到一个简单的 plunker 会更好...... plnkr.co/edit .. 并分享你的 Plunk和我们一起!
  • 我会马上解决这个问题,好建议。
  • 将这个问题转换为可用的 plunker 并不像我想象的那么容易。我在上面的仓库中添加了一个 gitlab 链接。
  • 一个非常快速的建议:尝试在 mainContentController 中的函数主体周围抛出 $scope.$applyAsync(...)。也许如果它只需要一个摘要周期即可到达控制器,那应该可以解决它。
  • @UnicornMaster 如果你不知道有一个名为 Cloud9IDE 的在线 IDE(我认为这是最好的)......我目前在那里克隆它。我们可以在那里讨论并解决它。链接:ide.c9.io/amanuel2/gitclone。在那里打开协作选项卡。

标签: javascript angularjs angularjs-service angularjs-controlleras


【解决方案1】:

如果您的目标只是显示和修改控制器模板中的数据,请不要依赖杂乱无章的广播。

您的控制器不需要“知道”服务或工厂何时更新以便在模板中使用它,因为 Angular 会为您处理这个,因为您通过 dot notation 访问数据.这是您应该详细了解的重要概念。

这个 Fiddle 展示了访问数据的两种方式,以及在模板中使用容器对象如何导致 Angular 在更改时重新检查相同的实际对象 - 而不是存储在控制器中的原始字符串值:

http://jsfiddle.net/a01f39Lw/2/

模板:

<div ng-controller="Ctrl1 as c1">
    <input ng-model="c1.Bands.favorite" placeholder="Favorite band?">
</div>
<div ng-controller="Ctrl2 as c2">
    <input ng-model="c2.Bands.favorite" placeholder="Favorite band?">
</div>

JS:

var app = angular.module("app", []);      

app.factory('Bands', function($http) {
    return {
        favorite: ''
    };    
});

app.controller('Ctrl1', function Ctrl1(Bands){
    this.Bands = Bands;
});
app.controller('Ctrl2', function Ctrl2(Bands){
    this.Bands = Bands;
});

【讨论】:

  • 在这种情况下使用工厂而不是服务有优势吗?据我了解,基本区别在于服务是构造函数,而工厂返回对象文字。我知道的不多。
  • 这篇文章在这个问题上的回答比我能回答的要多:stackoverflow.com/a/26924234/5046541
【解决方案2】:

首先让我们从良好实践开始,然后在这里解决您的问题...

良好做法

至少据我所知,我不打算像你那样使用服务……你看,服务更像是对象。因此,如果我要将您的服务转换为我通常使用的方式,则会产生以下结果:

app.service('selectedEmployee', [selectedEmployeeService])

    function selectedEmployeeService(){
      this.selected = null;
      this.getSelected = function(){
        return this.selected;
      }
      this.postSelected = function(emp){
        this.selected = emp;
      }
    }

你看我把函数分开了,并且把服务变成了一个实际的对象。我建议你像这样格式化你的控制器函数参数…如果你想讨论/查看好的做法去here。无论如何,关于真正问题的良好实践已经足够了。

解决问题

好吧,安德鲁真的想通了!!问题是:他需要使用 $rootScope 广播他的消息:

$rootScope.$broadcast('selected:updated', $scope.selected);

然后你必须检查 $scope.selected 何时更新......有点像 $scope.$watch...

$scope.$on('selected:updated', function(event, data) {
          $scope.selected = data;
})

之后它会自动更新并运行!希望这有帮助!

PS:不知道他已经回答了……

【讨论】:

  • 我只是想在这里指出,您在编写服务时没有使用范围规则。关键字“this”将改变它所指的函数。当你说'return this.selected;'您正在返回一个未定义的值,因为尚未定义 getSelected 成员范围内的 this.selected 。此代码不起作用。
【解决方案3】:

因此,经过大量研究和来自 Dsafds 的大量帮助后,我能够使用 $rootScope.$broadcast 通知我对变量更改的部分视图。

如果您从 rootScope 广播,它将到达每个子控制器,并且您不必在服务变量上设置 $watch。

$scope.selectEmployee = function(employee) {
            selectedEmployee.postSelected(employee);
            $scope.selected = selectedEmployee.getSelected();
            $rootScope.$broadcast('selected:updated', $scope.selected);
            if ($mdSidenav('left').isOpen()) {
                $mdSidenav('left').close();
            }
        }

并且在主内容区的控制器中

function ($scope) {
    $scope.$on('selected:updated', function(event, data) {
        $scope.selected = data;
    })
}

我认为您不必直接传递数据,您也可以轻松调用 selectedEmployee.getSelected()

$rootScope 也必须包含在父控制器和广播控制器中。

【讨论】:

  • 滥用rootscope广播从长远来看会给你带来麻烦并且不容易调试。最好在需要相互广播事件并在特定范围内使用发射/广播的控制器之间建立分层关系,甚至在可能的情况下更容易使用共享模型 - 请参阅我的答案以获取示例后者。
  • 感谢您的建议,我将不得不阅读如何正确设置控制器关系。
猜你喜欢
  • 1970-01-01
  • 2014-06-29
  • 1970-01-01
  • 2019-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多