如何基于父控件的作用域生成子控制器

How do I generate child controllers based on the scope of a parent control?

本文关键字:控制器 作用域 何基于 控件      更新时间:2023-10-11

我正在设计一个显示面板列表的界面,每个面板都有自己的模型。我希望能够渲染每个面板,使其使用父控制器中的模型拥有自己的模型

类似于:

function Parent() {
    this.panels = [{name: "Foo", place: "Bar"}, {name: "Hello", place: "World"}];
}
function Child(model) {
    var model = model //{name: "Foo", place: "Bar"}
}
for (var i = 0; i < Parent.panels.length; i++) {
    new Child(Parent.panels[0]);
}

我的问题是:在"棱角分明的心态"下,解决这个问题的最佳方法是什么?

我目前的计划如下。我将有两个控制器,一个用于面板列表,另一个用于每个单独的面板。所以,像这样的东西:

angular.module("panelApp", [])
    .service("panelService", function() {
        var panels = [/* panel classes */];
        return {
           getPanels: function() { return panels }
        }
    })
    .controller("PanelListCtrl", ["$scope", "panelService", function($scope, panelService) {
        $scope.panels = panelService.getPanels();
        $scope.currentPanel = $scope.panels[0];
    })
    .controller("PanelCtrl", ["$scope", "panelService", function($scope, panelService) {
        //this is where stuff gets hazy
        for (var i = 0; i < PanelListCtrl.panels.length; i++) {
           //generate child panels... somehow... =(
        }
    })

我显然做得不对,但总的想法是,我希望能够封装列表和每个单独面板的功能。

我想出的另一种方法是使用指令:

angular.module("panelApp", [])
    .service("panelService", function() {
        var panels = [/* panel classes */];
        return {
           getPanels: function() { return panels }
        }
    })
    .controller("PanelListCtrl", ["$scope", "panelService", function($scope, panelService) {
        $scope.panels = panelService.getPanels();
        $scope.currentPanel = $scope.panels[0];
    })
    .directive("panel", function() {
        require:"PanelListCtrl",
        restrict: "E",
        link: function(scope, element, attrs, panelListCtrl) {
            for (var i = 0; i < panelListCtrl.panels.length; i++) {
                //generate markup... somehow. How can one create directive markup in the DOM on the fly??
            }
        },
        templateUrl: "template.html"
    })

我已经和这个黑社会抗争了至少一个小时了。请帮忙。

注意事项

我忘了提的是,显示的面板数量是可变的。因此,加载页面时DOM中没有标记,必须动态注入。我是angular的新手,不知道如何根据框架使用的MV*方法向页面动态添加元素。

这应该会让您开始:http://plnkr.co/edit/b7KbXMPWOhAG50ajYyYN?p=preview

您的基本想法是合理的,使用分层作用域,它可以在控制器中使用作用域继承,也可以在控制器和指令之间实现。既然我怀疑您需要的主要是UI,那么您最好定义一个指令。

此外,在动态生成模板时,您可能想要的是一个静态模板,用于填充所需值的面板。然后,您可以使用ng-repeat来生成其中的许多。

控制器

.controller("PanelListCtrl", ["$scope", "panelService", function($scope, panelService) {
    $scope.panels = panelService.getPanels();
    // Saving the `isActive` property in the model, keeping the controller thin.
    $scope.panels[0].isActive = true;
    // This will manage the selection of the correct panel.
    $scope.selectPanel = function (panel) {
      $scope.panels.forEach(function (p) {
        p.isActive = p === panel;
      });
    };
}])
.directive("panel", function() {
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
        scope.$watch(attrs.panel, function (newVal) {
          scope.panel = newVal;  // <-- watch and populate the `panel` in the current scope.
          // The directive cam be made to
          // work even without this link function (because of scope
          // inheritence) but the best-practise is to keep the directives
          // as loosely coupled with the controller as possible.
          // In this case, you'll be free the name the panel variable anything 
          // in the controller as long
          // as you pass the variable to the directive: <div panel="nameOfPanel"></div>
        })
    },
    templateUrl: "panel.html"  // <-- template is here for One of the panes.
  }
})

模板

<body ng-controller="PanelListCtrl">
  <div ng-repeat="p in panels">
    <button ng-click="selectPanel(p)">Select panel {{$index}}</button>
    <div panel="p"></div>
  </div>
</body>