同一元素上的两个指令不能同时具有隔离范围,但它们是否都可以使用与其父元素隔离的相同范围?他们都可以使用绑定到隔离范围的属性吗?
例如,如果我对元素有两个指令
<e-directive a-directive prop="parentProp"/>
一个指令定义了一个带有绑定属性的隔离范围
App.directive('eDirective', function() {
return {
restrict: 'E',
scope: {
localProp: '=prop'
},
...
};
});
另一个指令是否获得该范围,是否可以使用绑定属性?
App.directive('aDirective', function() {
return {
restrict: 'A',
link: function postLink(scope, element, attrs) {
scope.$watch('localProp', function(newProp, oldProp) {
...
}
},
...
};
});
我的初步尝试(几乎按上述编码)失败。
答案 0 :(得分:19)
我建议你利用指令之间的沟通&#39;控制器通过辅助指令的require属性。第一个指令(e-directive)保存隔离范围,而第二个指令(a-directive)包含对第一个指令的引用,并通过第一个指令定义的函数设置属性。一小部分样本(see plunker):
<!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.2.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js" data-semver="1.2.16"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<div e-directive config="parentConfig" a-directive></div>
</body>
</html>
和javascript:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.parentConfig = {};
});
app.controller('ECtrl', function ( $scope ) {
this.setProp = function(newProp){$scope.config.prop = newProp;};
$scope.$watch('config', function(newProp, oldProp) {
console.log(oldProp, newProp);
});
});
app.directive('eDirective', function() {
return {
restrict: 'A',
scope: {
config: '='
},
controller: 'ECtrl',
link: function(scope, element, attrs) {
scope.config.prop ="abc";
}
};
});
app.directive('aDirective', function() {
return {
restrict: 'A',
require: 'eDirective',
link: function(scope, element, attrs,ctrl) {
ctrl.setProp("def");
}
};
});
答案 1 :(得分:1)
指令可以创建一个新的子范围,而不是隔离范围,这两个范围将由两个指令共享。如果您需要修改指令中的parentProp
,请注入并使用$parse
:
<div ng-controller="MyCtrl">
<e-directive a-directive prop="parentProp"></e-directive>
</div>
使用Javascript:
var app = angular.module('myApp', []);
app.controller('MyCtrl', function($scope) {
$scope.parentProp = { prop1: 'value1' };
});
app.directive('eDirective', function($parse) {
return {
restrict: 'E',
scope: true,
template: '<div>dir template: {{eDirLocalProp}}<br>'
+ '<a href ng-click="eDirChange()">change</a></div>',
link: function(scope, element, attrs) {
scope.eDirProp1 = 'dirPropValue';
var model = $parse(attrs.prop);
scope.eDirLocalProp = model(scope);
scope.eDirChange = function() {
scope.eDirLocalProp.prop1 = "new value";
};
}
};
});
app.directive('aDirective', function() {
return {
scope: true,
link: function postLink(scope, element, attrs) {
scope.$watchCollection(attrs.prop, function(newValue) {
console.log('aDirective', newValue);
});
},
};
});
如果两个指令都需要在新子作用域上创建属性,请使用某种命名约定来防止名称冲突。例如,scope.eDirProp1 = ...
和scope.aDirProp1 = ...
。
答案 2 :(得分:1)
是的,例如使用element.isolateScope()
(或参见fiddle):
<强> HTML 强>
<div ng-app="app" ng-controller="BaseController as baseCtrl">
<input type="text" ng-model="inputA.value" directive-config="{data: 'bar'}" >
<input type="text" ng-model="inputB.value" directive-config="{parsers: externalParser, data: 'buzz'}" custom-input >
<br><br>
<span style="font-style: italic; font-size: 12px; color: red;">*Open Console to view output</span>
</div>
<强> JS 强>
(function(angular){
"use strict";
angular.module("app", [])
.controller("BaseController", ['$scope', function($scope){
$scope.inputA = {value: "This is inputA"};
$scope.inputB = {value: "This is inputB"};
$scope.externalParser = function(value) {
console.log("...parsing value: ", value);
}
}])
.directive("input", [function() {
return {
restrict: "E",
require: '?ngModel',
scope: {
directiveConfig: "="
},
link: function(scope, element, attrs, ngModelCtrl) {
console.log("input directive - scope: ", scope);
console.log("input directive - scope.directiveConfig.data: ", scope.directiveConfig.data);
}
}
}])
.directive("customInput", [function() {
return {
restrict: "A",
require: '?ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
console.log("");
console.log("--------------------------------------------");
console.log("customInput directive - scope: ", scope);
// Use `element.isolateScope()`
var parentScope = element.isolateScope();
console.log("customInput directive - parentScope.directiveConfig.parsers: ", parentScope.directiveConfig.parsers);
console.log("customInput directive - parentScope.directiveConfig.data: ", parentScope.directiveConfig.data);
console.log("");
console.log("--------------------------------------------");
console.warn("DO NOT USE `$$childHead` as it may not target the element you are expecting; use `element.isolateScope()` instead.");
// DO NOT USE `$$childHead` as it may not be the element you expect
console.log("customInput directive - scope.$$childHead.directiveConfig.parsers: ", scope.$$childHead.directiveConfig.parsers);
console.log("customInput directive - scope.$$childHead.directiveConfig.data: ", scope.$$childHead.directiveConfig.data);
}
}
}])
;
})(angular)
控制台输出
//input directive - scope: n {$id: 3, $$childTail: null, $$childHead: null, $$prevSibling: null, $$nextSibling: null…}
//input directive - scope.directiveConfig.data: bar
//input directive - scope: n {$id: 4, $$childTail: null, $$childHead: null, $$prevSibling: n, $$nextSibling: null…}
//input directive - scope.directiveConfig.data: buzz
//--------------------------------------------
//customInput directive - scope: b {$$childTail: n, $$childHead: n, $$nextSibling: null, $$watchers: Array[4], $$listeners: Object…}
//customInput directive - parentScope.directiveConfig.parsers: function (value) {
// console.log("...parsing value: ", value);
// }
//customInput directive - parentScope.directiveConfig.data: buzz
//--------------------------------------------
//DO NOT USE `$$childHead` as it may not target the element you are expecting; use `element.isolateScope()` instead.
//customInput directive - scope.$$childHead.directiveConfig.parsers: undefined
//customInput directive - scope.$$childHead.directiveConfig.data: bar