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

在我之前的问题之后 ,我现在试图从我的指令调用父控制器上的一个方法。 我得到一个未定义的参数。 这就是我所做的:

<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/

只需简单地改变你的HTML如下

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

你没有通过updatePerson“人”这就是为什么它不工作

访问控制器方法意味着从指令控制器/链接/范围访问父范围的方法。

如果指令是共享/inheritance父范围,那么直接调用一个父范围方法是非常简单的。

当您要从独立指令作用域访问父级作用域方法时,需要做更多的工作。

有几个选项(可能比下面列出的更多)从独立的指令作用域调用父作用域方法,或者监视父作用域variables(特别是选项#6 )。

请注意 ,我在这些例子中使用了link function ,但是您也可以根据需要使用directive controller

选项1。 通过Object literal和from指令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。 通过对象字面量和从指令链接/范围

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="selectedItemsChangedDir()" 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", 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模板

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" 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> 

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.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个选项。 通过函数引用和指令链接/范围

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" 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> 

app.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-model和双向绑定,可以更新父范围variables。 。 所以,在某些情况下,您可能不需要调用父范围函数。

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 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> 

app.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双向绑定,如果在父范围内修改项目,则指令中的项目也会反映更改。

如果你想观察其他属性或从父范围的对象,你可以做到这一点使用$watch$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文档以获取关于指令的详细解释。

有两种方法,我们可以使用&=来调用。

如果我使用=作为范围属性 ,那么

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

将被改为

 ng-click='updateparent(mandatePerson)' 

而在指令中,

 updateparent="updatePerson()" 

将改变为

 updateparent="updatePerson" 

这里不需要提到参数,它们会作为参考传递给控制器​​的函数定义。

在其他答案中解释使用&

这是另一种模式(在Angular 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>