最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - In angular js, How do I pass data from a parent controller to a child controller? - Stack Overflow

programmeradmin9浏览0评论

I have a little widget I'd like to use over and over on a single page. It has its own controller. Problem is it needs a piece of data to operate (basically a key), and each key is contained in the parent controller.

Here is an example (which is obviously wrong)

script:

angular.module('myApp', [])
  .controller('ParentCtrl', ['$scope',
    function($scope) {
      $scope.keyForChartABC = "somekey1";
      $scope.keyForChartXYZ = "somekey2";
      $scope.keyForChartLALA = "somekey3";

    }
  ])
  .controller('ChartCtrl', ['$scope',
    function($scope) {
      //todo: have $scope.key assigned from parent somehow

      //not shown:  use $scope.key to pull data and format chart data
    }
  ])

index:

    <!-- ng-init like this is quite wrong -->
    <div    ng-init="key = keyForChartABC"
            ng-include="'chartwidget.html'"></div>
    <hr>
    <div    ng-init="key = keyForChartXYZ"
            ng-include="'chartwidget.html'"></div>
    <hr>
    <div    ng-init="key = keyForChartLALA"
            ng-include="'chartwidget.html'"></div>

chartwidget:

<div ng-controller="ChartCtrl">
    <p>Drawing chart for data: {{key}}</p>
    <p>some chart directive here</p>
</div>

As you can see in the plunker, what I tried here with ng-init doesn't work - key for all the sub-controllers end up with the same value.

I've gotten this to work with ng-repeat and an array of data in the parent, somehow $index gets set in each child to the right index and stays that one value. But I'd like to avoid using ng-repeat in this case so I can have more control of the layout.

I have a little widget I'd like to use over and over on a single page. It has its own controller. Problem is it needs a piece of data to operate (basically a key), and each key is contained in the parent controller.

Here is an example (which is obviously wrong)

http://plnkr.co/edit/VajgOr1LqpLDnbEJcvor?p=preview

script:

angular.module('myApp', [])
  .controller('ParentCtrl', ['$scope',
    function($scope) {
      $scope.keyForChartABC = "somekey1";
      $scope.keyForChartXYZ = "somekey2";
      $scope.keyForChartLALA = "somekey3";

    }
  ])
  .controller('ChartCtrl', ['$scope',
    function($scope) {
      //todo: have $scope.key assigned from parent somehow

      //not shown:  use $scope.key to pull data and format chart data
    }
  ])

index:

    <!-- ng-init like this is quite wrong -->
    <div    ng-init="key = keyForChartABC"
            ng-include="'chartwidget.html'"></div>
    <hr>
    <div    ng-init="key = keyForChartXYZ"
            ng-include="'chartwidget.html'"></div>
    <hr>
    <div    ng-init="key = keyForChartLALA"
            ng-include="'chartwidget.html'"></div>

chartwidget:

<div ng-controller="ChartCtrl">
    <p>Drawing chart for data: {{key}}</p>
    <p>some chart directive here</p>
</div>

As you can see in the plunker, what I tried here with ng-init doesn't work - key for all the sub-controllers end up with the same value.

I've gotten this to work with ng-repeat and an array of data in the parent, somehow $index gets set in each child to the right index and stays that one value. But I'd like to avoid using ng-repeat in this case so I can have more control of the layout.

Share asked Jul 4, 2015 at 22:54 adapt-devadapt-dev 1,7882 gold badges19 silver badges31 bronze badges 1
  • don't use ng-include for this, use a directive. – Claies Commented Jul 4, 2015 at 23:28
Add a ment  | 

1 Answer 1

Reset to default 7

Creating re-usable widgets is exactly the purpose of Directives. You can create a directive which handles the output of your widget quite easily.

I forked your plunker and modified it to change it to use a directive.

Here are a few highlights:

First, your template no longer needs the controller defined within it.

<div>
    <p>Drawing chart for data: {{key}}</p>
    <p>some chart directive here</p>
</div>

Next, the directive is defined, with an isolate scope which is unique to each instance of the directive:

.directive('chartWidget', function(){
    return {
      restrict: 'E',
      scope: {
        key: '='
      },
      templateUrl : 'chartwidget.html'
    }
})

Lastly, the directive is declared in the HTML. Note the camel-case name of the directive in the JavaScript, but the hyphenated name in the HTML:

<div>
    <chart-widget key="keyForChartABC"></chart-widget>
    <hr>
    <chart-widget key="keyForChartXYZ"></chart-widget>
    <hr>
    <chart-widget key="keyForChartLALA"></chart-widget>
</div>

Edit

I updated the plunker to show binding the directive property to an inner controller. This method uses the ControllerAs syntax to define the controller, and binds the directive's scope to the controller scope.

Relevant changes:

.directive('chartWidget', function(){
    return {
      restrict: 'E',
      scope: {
        key: '='
      },
      templateUrl : 'chartwidget.html',
      controller: 'chartWidgetController',
      controllerAs: 'ctrl',
      bindToController: true
    }
  })
  .controller('chartWidgetController', function(){
    console.log(this.key);
  })

And a small change to the template to support ControllerAs:

<div>
    <p>Drawing chart for data: {{ctrl.key}}</p>
    <p>some chart directive here</p>
</div>

Note that trying to use ng-controller= in the template will cause the template to have a different scope object from the scope object created for the directive, and the controller would not have access to the properties defined on the directive.

Also note, bindToController is a feature of angular 1.3.x or higher. in angular 1.2.x or earlier, your only option was to use $scope.$watch to monitor the isolate scope for changes.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论