代码之家  ›  专栏  ›  技术社区  ›  Sam

从AngularJS中的指令调用父控制器的方法

  •  69
  • Sam  · 技术社区  · 13 年前

    继我之前 question ,我现在正试图从指令中调用父控制器上的一个方法。我得到一个未定义的参数。我是这样做的:

    <body ng-app="myApp" ng-controller="MainCtrl">
      <span>{{mandat.rum}}</span>
      <span>{{mandat.surname}}</span>
    <input type="text" ng-model="mandat.person.firstname" />
    <my-directive mandate-person="mandat.person" updateparent="updatePerson()" >
    
      </my-directive>
    </body>
    

    以及脚本:

    var app = angular.module('myApp', []);
    
        app.controller('MainCtrl', function ($scope) {
            $scope.mandat = { name: "John", surname: "Doe", person: { id: 1408, firstname: "sam" } };
            $scope.updatePerson = function(person) {
                alert(person.firstname);
              $scope.mandat.person = person;   
            }
        });
    
    
        app.directive('myDirective', function () {
            return {
                restrict: 'E',
                template: "<div><span>{{mandatePerson.id}}<span><input type='text' ng-model='mandatePerson.firstname' /><button ng-click='updateparent({person: mandatePerson})'>click</button></div>",
                replace: true,
                scope: { mandatePerson: '=', updateparent: '&' }
                }
            }
        )
    

    当updatePerson方法被调用时,person是未定义的。

    jsfiddle在这里: http://jsfiddle.net/graphicsxp/Z5MBf/7/

    4 回复  |  直到 9 年前
        1
  •  57
  •   Ajay Singh Beniwal    13 年前

    只需简单地更改您的html如下

    <my-directive mandate-person="mandat.person" updateparent="updatePerson(person)" >
    
          </my-directive>
    

    你没有通过updatePerson传递“person”,这就是它不起作用的原因

        2
  •  38
  •   Ziv Weissman    8 年前

    访问控制器方法意味着从指令控制器/链接/作用域访问父作用域上的方法。

    如果指令是共享/继承父作用域,那么只调用父作用域方法是非常直接的。

    当您想要从隔离指令范围访问父范围方法时,只需要做少量的工作。

    很少有选项(可能比下面列出的更多)可以从隔离指令范围调用父范围方法或监视父范围变量( 选项#6 特别是)。

    笔记 我用过的 link function 在这些示例中,但您可以使用 directive controller 以及基于需求。

    选项#1。 通过对象文字和从指令html模板

    index.html

    <!DOCTYPE html>
    <html ng-app="plunker">
    
      <head>
        <meta charset="utf-8" />
        <title>AngularJS Plunker</title>
        <script>document.write('<base href="' + document.location + '" />');</script>
        <link rel="stylesheet" href="style.css" />
        <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
        <script src="app.js"></script>
      </head>
    
      <body ng-controller="MainCtrl">
        <p>Hello {{name}}!</p>
    
        <p> Directive Content</p>
        <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged(selectedItems)" items="items"> </sd-items-filter>
    
    
        <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>
    
      </body>
    
    </html>
    

    itemfilterTemplate.html

    <select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" ng-change="selectedItemsChanged({selectedItems:selectedItems})" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
      <option>--</option>
    </select>
    

    app.js

    var app = angular.module('plunker', []);
    
    app.directive('sdItemsFilter', function() {
      return {
        restrict: 'E',
        scope: {
          items: '=',
          selectedItems: '=',
          selectedItemsChanged: '&'
        },
        templateUrl: "itemfilterTemplate.html"
      }
    })
    
    app.controller('MainCtrl', function($scope) {
      $scope.name = 'TARS';
    
      $scope.selectedItems = ["allItems"];
    
      $scope.selectedItemsChanged = function(selectedItems1) {
        $scope.selectedItemsReturnedFromDirective = selectedItems1;
      }
    
      $scope.items = [{
        "id": "allItems",
        "name": "All Items",
        "order": 0
      }, {
        "id": "CaseItem",
        "name": "Case Item",
        "model": "PredefinedModel"
      }, {
        "id": "Application",
        "name": "Application",
        "model": "Bank"
        }]
    
    });
    

    工作plnkr: http://plnkr.co/edit/rgKUsYGDo9O3tewL6xgr?p=preview

    选项#2。通过对象文字和从指令链接/作用域

    索引html

    <!文档类型html>
    <html ng app=“plunker”>
    
    <头部>
    <meta字符集=“utf-8”/>
    <标题>AngularJS Plunker</标题>
    <脚本>document.write('<base href=“'+document.location+'”/>')</脚本>
    <链接rel=“stylesheet”href=“style.css”/>
    <脚本数据要求=“angular.js@1.3.x“src=”https://code.angularjs.org/1.3.9/angular.js“data semver=”1.3.9“></script>
    <script src=“app.js”></脚本>
    </头部>
    
    <body ng controller=“MainCtrl”>
    <p>您好{{name}}</p>
    
    <p>指令内容</p>
    <sd项目筛选所选项目=“selectedItems”所选项目已更改=“selectedItemsChanged(selectedItems)”项目=“items”></sd项目筛选器>
    
    
    <P style=“color:红色”>所选项目(在父控制器中)设置为:{{selectedItemsReturnedFromDirective}}</p>
    
    </身体>
    
    </html>
    

    itemfilterTemplate.html

    <select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
     ng-change="selectedItemsChangedDir()" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
      <option>--</option>
    </select>
    

    应用程序.js

    var app = angular.module('plunker', []);
    
    app.directive('sdItemsFilter', function() {
      return {
        restrict: 'E',
        scope: {
          items: '=',
          selectedItems: '=',
          selectedItemsChanged: '&'
        },
        templateUrl: "itemfilterTemplate.html",
        link: function (scope, element, attrs){
          scope.selectedItemsChangedDir = function(){
            scope.selectedItemsChanged({selectedItems:scope.selectedItems});  
          }
        }
      }
    })
    
    app.controller('MainCtrl', function($scope) {
      $scope.name = 'TARS';
    
      $scope.selectedItems = ["allItems"];
    
      $scope.selectedItemsChanged = function(selectedItems1) {
        $scope.selectedItemsReturnedFromDirective = selectedItems1;
      }
    
      $scope.items = [{
        "id": "allItems",
        "name": "All Items",
        "order": 0
      }, {
        "id": "CaseItem",
        "name": "Case Item",
        "model": "PredefinedModel"
      }, {
        "id": "Application",
        "name": "Application",
        "model": "Bank"
        }]
    });
    

    工作plnkr: http://plnkr.co/edit/BRvYm2SpSpBK9uxNIcTa?p=preview

    选项#3。通过函数引用和指令html模板

    索引html

    <!DOCTYPE html>
    <html ng-app="plunker">
    
      <head>
        <meta charset="utf-8" />
        <title>AngularJS Plunker</title>
        <script>document.write('<base href="' + document.location + '" />');</script>
        <link rel="stylesheet" href="style.css" />
        <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
        <script src="app.js"></script>
      </head>
    
      <body ng-controller="MainCtrl">
        <p>Hello {{name}}!</p>
    
        <p> Directive Content</p>
        <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>
    
    
        <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnFromDirective}} </p>
    
      </body>
    
    </html>
    

    itemfilterTemplate.html

    <select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
     ng-change="selectedItemsChanged()(selectedItems)" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
      <option>--</option>
    </select>
    

    应用程序.js

    var app = angular.module('plunker', []);
    
    app.directive('sdItemsFilter', function() {
      return {
        restrict: 'E',
        scope: {
          items: '=',
          selectedItems:'=',
          selectedItemsChanged: '&'
        },
        templateUrl: "itemfilterTemplate.html"
      }
    })
    
    app.controller('MainCtrl', function($scope) {
      $scope.name = 'TARS';
    
      $scope.selectedItems = ["allItems"];
    
      $scope.selectedItemsChanged = function(selectedItems1) {
        $scope.selectedItemsReturnFromDirective = selectedItems1;
      }
    
      $scope.items = [{
        "id": "allItems",
        "name": "All Items",
        "order": 0
      }, {
        "id": "CaseItem",
        "name": "Case Item",
        "model": "PredefinedModel"
      }, {
        "id": "Application",
        "name": "Application",
        "model": "Bank"
        }]
    });
    

    工作plnkr: http://plnkr.co/edit/Jo6FcYfVXCCg3vH42BIz?p=preview

    选项#4。通过函数引用和指令链接/作用域

    索引html

    <!DOCTYPE html>
    <html ng-app="plunker">
    
      <head>
        <meta charset="utf-8" />
        <title>AngularJS Plunker</title>
        <script>document.write('<base href="' + document.location + '" />');</script>
        <link rel="stylesheet" href="style.css" />
        <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
        <script src="app.js"></script>
      </head>
    
      <body ng-controller="MainCtrl">
        <p>Hello {{name}}!</p>
    
        <p> Directive Content</p>
        <sd-items-filter selected-items="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>
    
    
        <P style="color:red">Selected Items (in parent controller) set to: {{selectedItemsReturnedFromDirective}} </p>
    
      </body>
    
    </html>
    

    itemfilterTemplate.html

    <select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" ng-change="selectedItemsChangedDir()" ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
      <option>--</option>
    </select>
    

    应用程序.js

    var app = angular.module('plunker', []);
    
    app.directive('sdItemsFilter', function() {
      return {
        restrict: 'E',
        scope: {
          items: '=',
          selectedItems: '=',
          selectedItemsChanged: '&'
        },
        templateUrl: "itemfilterTemplate.html",
        link: function (scope, element, attrs){
          scope.selectedItemsChangedDir = function(){
            scope.selectedItemsChanged()(scope.selectedItems);  
          }
        }
      }
    })
    
    app.controller('MainCtrl', function($scope) {
      $scope.name = 'TARS';
    
      $scope.selectedItems = ["allItems"];
    
      $scope.selectedItemsChanged = function(selectedItems1) {
        $scope.selectedItemsReturnedFromDirective = selectedItems1;
      }
    
      $scope.items = [{
        "id": "allItems",
        "name": "All Items",
        "order": 0
      }, {
        "id": "CaseItem",
        "name": "Case Item",
        "model": "PredefinedModel"
      }, {
        "id": "Application",
        "name": "Application",
        "model": "Bank"
        }]
    
    });
    

    工作plnkr: http://plnkr.co/edit/BSqx2J1yCY86IJwAnQF1?p=preview

    选项#5:通过ng模型和双向绑定,您可以更新父作用域变量。 因此,在某些情况下,您可能不需要调用父作用域函数。

    索引html

    <!DOCTYPE html>
    <html ng-app="plunker">
    
      <head>
        <meta charset="utf-8" />
        <title>AngularJS Plunker</title>
        <script>document.write('<base href="' + document.location + '" />');</script>
        <link rel="stylesheet" href="style.css" />
        <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
        <script src="app.js"></script>
      </head>
    
      <body ng-controller="MainCtrl">
        <p>Hello {{name}}!</p>
    
        <p> Directive Content</p>
        <sd-items-filter ng-model="selectedItems" selected-items-changed="selectedItemsChanged" items="items"> </sd-items-filter>
    
    
        <P style="color:red">Selected Items (in parent controller) set to: {{selectedItems}} </p>
    
      </body>
    
    </html>
    

    itemfilterTemplate.html

    <select ng-model="selectedItems" multiple="multiple" style="height: 200px; width: 250px;" 
     ng-options="item.id as item.name group by item.model for item in items | orderBy:'name'">
      <option>--</option>
    </select>
    

    应用程序.js

    var app = angular.module('plunker', []);
    
    app.directive('sdItemsFilter', function() {
      return {
        restrict: 'E',
        scope: {
          items: '=',
          selectedItems: '=ngModel'
        },
        templateUrl: "itemfilterTemplate.html"
      }
    })
    
    app.controller('MainCtrl', function($scope) {
      $scope.name = 'TARS';
    
      $scope.selectedItems = ["allItems"];
    
      $scope.items = [{
        "id": "allItems",
        "name": "All Items",
        "order": 0
      }, {
        "id": "CaseItem",
        "name": "Case Item",
        "model": "PredefinedModel"
      }, {
        "id": "Application",
        "name": "Application",
        "model": "Bank"
        }]
    });
    

    工作plnkr: http://plnkr.co/edit/hNui3xgzdTnfcdzljihY?p=preview

    选项6:通过 $watch $watchCollection 它是双向绑定 items 在以上所有示例中,如果在父作用域中修改了项,则指令中的项也将反映这些更改。

    如果您想从父作用域中观察其他属性或对象,可以使用 $手表 $watchCollection系列 如下所示

    html格式

    <!DOCTYPE html>
    <html ng-app="plunker">
    
    <head>
      <meta charset="utf-8" />
      <title>AngularJS Plunker</title>
      <script>
        document.write('<base href="' + document.location + '" />');
      </script>
      <link rel="stylesheet" href="style.css" />
      <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
      <script src="app.js"></script>
    </head>
    
    <body ng-controller="MainCtrl">
      <p>Hello {{user}}!</p>
      <p>directive is watching name and current item</p>
      <table>
        <tr>
          <td>Id:</td>
          <td>
            <input type="text" ng-model="id" />
          </td>
        </tr>
        <tr>
          <td>Name:</td>
          <td>
            <input type="text" ng-model="name" />
          </td>
        </tr>
        <tr>
          <td>Model:</td>
          <td>
            <input type="text" ng-model="model" />
          </td>
        </tr>
      </table>
    
      <button style="margin-left:50px" type="buttun" ng-click="addItem()">Add Item</button>
    
      <p>Directive Contents</p>
      <sd-items-filter ng-model="selectedItems" current-item="currentItem" name="{{name}}" selected-items-changed="selectedItemsChanged" items="items"></sd-items-filter>
    
      <P style="color:red">Selected Items (in parent controller) set to: {{selectedItems}}</p>
    </body>
    
    </html>
    

    脚本app.js

    var app = angular.module('plunker', []);
    
    app.directive('sdItemsFilter', function() {
      return {
        restrict: 'E',
        scope: {
          name: '@',
          currentItem: '=',
          items: '=',
          selectedItems: '=ngModel'
        },
        template: '<select ng-model="selectedItems" multiple="multiple" style="height: 140px; width: 250px;"' +
          'ng-options="item.id as item.name group by item.model for item in items | orderBy:\'name\'">' +
          '<option>--</option> </select>',
        link: function(scope, element, attrs) {
          scope.$watchCollection('currentItem', function() {
            console.log(JSON.stringify(scope.currentItem));
          });
          scope.$watch('name', function() {
            console.log(JSON.stringify(scope.name));
          });
        }
      }
    })
    
     app.controller('MainCtrl', function($scope) {
      $scope.user = 'World';
    
      $scope.addItem = function() {
        $scope.items.push({
          id: $scope.id,
          name: $scope.name,
          model: $scope.model
        });
        $scope.currentItem = {};
        $scope.currentItem.id = $scope.id;
        $scope.currentItem.name = $scope.name;
        $scope.currentItem.model = $scope.model;
      }
    
      $scope.selectedItems = ["allItems"];
    
      $scope.items = [{
        "id": "allItems",
        "name": "All Items",
        "order": 0
      }, {
        "id": "CaseItem",
        "name": "Case Item",
        "model": "PredefinedModel"
      }, {
        "id": "Application",
        "name": "Application",
        "model": "Bank"
      }]
    });
    

    有关指令的详细解释,您可以随时参考AngularJs文档。

        3
  •  12
  •   prava    11 年前

    有两种方法,我们可以称之为使用 & = .

    如果我正在使用 = 对于scope属性 然后

    ng-click='updateparent({person: mandatePerson})' 
    

    将更改为

    ng-click='updateparent(mandatePerson)'
    

    在指令中,

    updateparent="updatePerson()" 
    

    将更改为

    updateparent="updatePerson"
    

    这里不需要提及参数,它们将作为引用传递给控制器的函数定义。

    使用 & 在其他答案中进行了解释。

        4
  •  1
  •   Ruslanas BalčiÅ«nas    9 年前

    这是另一种模式(适用于 角度1.5 ).

    angular.module('module', [])
    
        .controller('MyController', function() {
    
            var self = this;
            self.msg = 0;
            // implement directive event listener interface
            this.onEvent = function(arg) {
                self.msg++;
            };
        })
    
        .directive('myDirective', function() {
            return {
              scope: {
                data: '=',
                handler: '='
              },
              template: '<button ng-click="handler.onEvent(data)">Emit event</button>'
            }
        });
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
    
    
    <div ng-app="module" ng-controller="MyController as ctrl">
    <my-directive handler="ctrl" data="'...received'"></my-directive>
      {{ctrl.msg}}
    </div>