How to access parent scope from within a custom directive *with own scope* in AngularJS?
我正在寻找在指令中访问"父"范围的任何方式。任何范围、超越、要求、从上面传入变量(或范围本身)的组合,等等。我完全愿意向后弯曲,但我想避免完全黑客或不可维护的东西。例如,我知道我现在可以通过从预链接参数中获取
我真正想要的是能够在父范围中使用
一个重要的注意事项是,该指令必须在同一父范围内可重用。因此,默认行为(scope:false)对我不起作用。每个指令实例需要一个单独的作用域,然后需要
代码示例值1000个字,因此:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | app.directive('watchingMyParentScope', function() { return { require: /* ? */, scope: /* ? */, transclude: /* ? */, controller: /* ? */, compile: function(el,attr,trans) { // Can I get the $parent from the transclusion function somehow? return { pre: function($s, $e, $a, parentControl) { // Can I get the $parent from the parent controller? // By setting this.$scope = $scope from within that controller? // Can I get the $parent from the current $scope? // Can I pass the $parent scope in as an attribute and define // it as part of this directive's scope definition? // What don't I understand about how directives work and // how their scope is related to their parent? }, post: function($s, $e, $a, parentControl) { // Has my situation improved by the time the postLink is called? } } } }; }); |
看看AngularJS中作用域原型/原型继承的细微差别是什么?
总结:指令访问其父(
默认(
以上链接包含所有4种类型的示例和图片。
您不能访问指令编译函数中的作用域(如下所述:https://github.com/angular/angular.js/wiki/understanding directive s)。您可以在link函数中访问指令的作用域。
看:
1。2。上面:通常通过属性指定指令需要哪个父属性,然后$watch它:
1 |
1 | scope.$watch(attrs.attr1, function() { ... }); |
如果您正在监视对象属性,则需要使用$parse:
1 |
1 2 | var model = $parse(attrs.attr2); scope.$watch(model, function() { ... }); |
3。在上面(隔离范围),注意使用
1 |
1 2 3 4 5 6 7 | scope: { localName3: '@attr3', attr4: '=' // here, using the same name as the attribute }, link: function(scope, element, attrs) { scope.$watch('localName3', function() { ... }); scope.$watch('attr4', function() { ... }); |
访问控制器方法意味着从指令控制器/链接/作用域访问父作用域上的方法。
如果该指令正在共享/继承父作用域,那么只调用父作用域方法是非常直接的。
当您想从独立的指令作用域访问父作用域方法时,只需要做很少的工作。
从独立指令作用域调用父作用域方法或监视父作用域变量(特别是选项6)的选项很少(可能比下面列出的多)。
注意,我在这些示例中使用了
选项1。通过对象文本和从指令HTML模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <!DOCTYPE html> <html ng-app="plunker"> <head> <meta charset="utf-8" /> AngularJS Plunker document.write('<base href="' + document.location + '" />'); <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 src="app.js"> </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> |
1 2 3 | <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> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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=预览
选项2。通过对象文本和从指令链接/作用域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <!DOCTYPE html> <html ng-app="plunker"> <head> <meta charset="utf-8" /> AngularJS Plunker document.write('<base href="' + document.location + '" />'); <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 src="app.js"> </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> |
1 2 3 4 | <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> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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/brvym2spbk9uxnicta?P=预览
选项3。通过函数引用和从指令HTML模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <!DOCTYPE html> <html ng-app="plunker"> <head> <meta charset="utf-8" /> AngularJS Plunker document.write('<base href="' + document.location + '" />'); <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 src="app.js"> </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> |
1 2 3 4 | <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> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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/jo6fcyvxcg3vh42biz?P=预览
选项4。通过函数引用和从指令链接/作用域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <!DOCTYPE html> <html ng-app="plunker"> <head> <meta charset="utf-8" /> AngularJS Plunker document.write('<base href="' + document.location + '" />'); <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 src="app.js"> </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> |
1 2 3 | <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> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 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=预览
选项5:通过ng模型和双向绑定,可以更新父范围变量。因此,在某些情况下可能不需要调用父范围函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <!DOCTYPE html> <html ng-app="plunker"> <head> <meta charset="utf-8" /> AngularJS Plunker document.write('<base href="' + document.location + '" />'); <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 src="app.js"> </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> |
1 2 3 4 | <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> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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=预览
方案6:通过
如果您想从父作用域中观察其他属性或对象,可以使用下面给出的
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | <!DOCTYPE html> <html ng-app="plunker"> <head> <meta charset="utf-8" /> AngularJS Plunker document.write('<base href="' + document.location + '" />'); <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 src="app.js"> </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',[]);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 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文档。
1 2 | scope: false transclude: false |
您将拥有相同的作用域(带有父元素)
1 | $scope.$watch(... |
根据这两个选项scope&exclude,有很多方法可以访问父作用域。
这里有一个我曾经使用过的技巧:创建一个"伪"指令来保存父范围,并将其放在所需指令之外的某个地方。类似:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | module.directive('myDirectiveContainer', function () { return { controller: function ($scope) { this.scope = $scope; } }; }); module.directive('myDirective', function () { return { require: '^myDirectiveContainer', link: function (scope, element, attrs, containerController) { // use containerController.scope here... } }; }); |
然后
1 |
也许不是最优雅的解决方案,但它完成了任务。
如果您使用ES6类和
请参见下面的代码片段,注意
1 2 3 4 5 6 | myApp.directive('name', function() { return { // no scope definition link : function(scope, element, attrs, ngModel) { scope.vm.func(...) |
尝试了所有的方法之后,我终于想出了一个解决办法。
只需在模板中放置以下内容:
它只写入要访问当前作用域的父作用域属性/变量。
还要注意,在语句末尾的
这有点老土,但经过几个小时的反复试验,它确实做到了。