如何根据父控件的范围生成子控制器?

时间:2013-11-24 20:42:59

标签: javascript angularjs angularjs-directive angularjs-scope

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

类似的东西:

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中没有标记,必须动态注入。我是角色的新手,我不知道如何根据框架使用的MV *方法动态地向页面添加元素。

1 个答案:

答案 0 :(得分:1)

这应该让你开始: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>