вызов метода родительского контроллера из директивы в 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/
4 ответов:
просто измените свой html, как показано ниже
<my-directive mandate-person="mandat.person" updateparent="updatePerson(person)" > </my-directive>вы не передаете "человек" с updatePerson вот почему он не работает
метод доступа к контроллеру означает доступ к методу в родительской области из директивного контроллера / link / scope.
если директива/обмен наследование родительской, то это довольно прямо вперед, чтобы просто вызвать метод родительской области.
немного больше работы требуется, когда вы хотите получить доступ к родительскому методу области из изолированной области директивы.
существует несколько вариантов (может быть больше, чем указано ниже) для вызова метода родительской области из изолированная область действия директив или переменные родительской области наблюдения (#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="[email protected]" 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.jsvar 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="[email protected]" 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.jsvar 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="[email protected]" 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.jsvar 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="[email protected]" 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.jsvar 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-модель и двухстороннюю привязку вы можете обновить переменные родительской области.. Таким образом, вам может не потребоваться вызывать родительские функции области в некоторых случаи.
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="[email protected]" 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.jsvar 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="[email protected]" 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>приложение сценарий.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 для получения подробных объяснений о директивах.
есть два способа, с помощью которых мы можем назвать, используя
&и=.если я использую
=для атрибута scope, потомng-click='updateparent({person: mandatePerson})'будет заменен на
ng-click='updateparent(mandatePerson)'
и в директиве,
updateparent="updatePerson()"изменится на
updateparent="updatePerson"здесь не нужно упоминать аргументы, они будут переданы в определение функции контроллера в качестве ссылки.
используя
&объясняется в другой ответ.
вот еще один шаблон (работает в Угловое 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>
Comments