javascript 如何在没有*隔离范围的指令中获得双向数据绑定?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23803871/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get two way data binding in a directive *without* an isolate scope?
提问by mhelvens
Using scope: { ... }
in a directive introduces an isolate scope, which does not prototypically inherit from its parent scope. But I have always used it for a different reason: a convenient way to declare HTML attributes with two way data binding:
scope: { ... }
在指令中使用会引入一个隔离作用域,它通常不会从其父作用域继承。但我总是出于不同的原因使用它:一种使用两种数据绑定声明 HTML 属性的便捷方法:
scope: {
attr1: '=',
attr2: '?='
}
To get a non-isolate scope, you have to use scope: true
, which does not offer the opportunity to declare such attributes. I now find myself needing a directive with a non-isolate scope, but with two way binding. What's the best way to achieve this?
要获得非隔离作用域,您必须使用scope: true
,它不提供声明此类属性的机会。我现在发现自己需要一个具有非隔离作用域但具有双向绑定的指令。实现这一目标的最佳方法是什么?
Example:My use-case is something like this, in the view of the outer-directive
:
示例:我的用例是这样的,在以下方面看来outer-directive
:
<div ng-repeat="e in element">
<inner-directive two-way-attr="e.value"></inner-directive>
</div>
But inner-directive
is in the same module as outer-directive
. It doesn't need to be encapsulated with an isolate scope. In fact, I need to use $scope
inheritance for other purposes, so an isolate scope is not an option. It's just that using an HTML attribute to establish this two-way communication is extremely convenient.
但inner-directive
与outer-directive
. 它不需要用隔离作用域封装。事实上,我需要将$scope
继承用于其他目的,因此隔离范围不是一个选项。只是使用一个 HTML 属性来建立这种双向通信非常方便。
采纳答案by mhelvens
The answer by pixelbits helped me figure this out big time, but taken as a direct answer to my original question, it seems overly complicated. After looking into it, the solution is really quite simple.
pixelbits 的回答帮助我弄清楚了这一点,但作为对我最初问题的直接回答,它似乎过于复杂。仔细研究之后,解决方案真的很简单。
Take a directive with an isolate scope like this:
取一个具有隔离范围的指令,如下所示:
scope: { model: '=myModel' },
link: function(scope, element, attr) {
//...
}
The following is equivalent, except that the scope is not isolate:
以下是等效的,除了范围不是隔离的:
scope: true,
link: function(scope, element, attr) {
scope.model = scope.$parent.$eval(attr.myModel);
//...
}
See a working example here: http://jsfiddle.net/mhelvens/SZ55R/1/
在此处查看一个工作示例:http: //jsfiddle.net/mhelvens/SZ55R/1/
回答by pixelbits
It is possible to have both a non-isolate scope and an isolate scope in the samedirective. You might want to do this, for example, if you have a mix of both non-isolated templates (meaning they should not look for bindings through scope inheritance), and isolated templates (they should look for bindings in its own scope only) and they are both defined in the same directive.
在同一指令中可以同时具有非隔离作用域和隔离作用域。例如,如果您混合使用非隔离模板(意味着它们不应通过作用域继承查找绑定)和隔离模板(它们应仅在其自身的作用域中查找绑定)和它们都在同一个指令中定义。
In order to setup both isolate scope and non-isolate scope, you can do the following:
为了设置隔离范围和非隔离范围,您可以执行以下操作:
- In your directive definition, specify
scope=true
In your link function, compile and link your template against the scope parameter. When you do this, the bindings are evaluated against the non-isolate scope (meaning it resolves bindings through prototypical scope inheritance).
link: function(scope, element, attr) { // this template should look for 'model' using scope inheritance var template2 = angular.element('<div> Prototypical Scope: {{ model }}</div>'); // add the template to the DOM element.append(template2); // compile and link the template against the prototypical scope $compile(template2)(scope); }
The advantage of prototypical scope inheritance is that you don't have to explicitly import bindings into your directives' current scope. As long as it is defined in the current scope or any scope higher up the inheritance chain (all the way up to the root scope), the angular run-time will be able to resolve it.
In the same link function, define an isolated scope using
scope.$new(true)
. You can establish a two-way binding of your model by importing a model into your isolated scope -isolatedScope.model = scope.$eval(attr.model)
:link: function(scope, element, attr) { // this template should look for 'model' in the current isolated scope only var template = angular.element('<div>Isolate Scope: {{model}}</div>'); // create an isolate scope var isolatedScope = scope.$new(true); // import the model from the parent scope into your isolated scope. This establishes the two-way binding. isolatedScope.model = scope.$eval(attr.model); // add the template to the DOM element.append(template); // compile and link the template against the isolate scope $compile(template)(isolatedScope); }
The advantage of the isolate scope is that any bindings that exist (ie. are in-scope) are the ones that you explicitly import. Contrast this with non-isolate scope - where the bindings do not need to be explicitly defined on the current scope - it could be inherited from any scope higher up the chain.
- 在您的指令定义中,指定
scope=true
在您的链接函数中,针对范围参数编译和链接您的模板。执行此操作时,将针对非隔离作用域评估绑定(这意味着它通过原型作用域继承解析绑定)。
link: function(scope, element, attr) { // this template should look for 'model' using scope inheritance var template2 = angular.element('<div> Prototypical Scope: {{ model }}</div>'); // add the template to the DOM element.append(template2); // compile and link the template against the prototypical scope $compile(template2)(scope); }
原型作用域继承的优点是您不必将绑定显式导入指令的当前作用域。只要它在当前作用域或继承链更高的任何作用域(一直到根作用域)中定义,角度运行时就能够解决它。
在同一个链接函数中,使用
scope.$new(true)
. 您可以通过将模型导入隔离范围来建立模型的双向绑定 -isolatedScope.model = scope.$eval(attr.model)
:link: function(scope, element, attr) { // this template should look for 'model' in the current isolated scope only var template = angular.element('<div>Isolate Scope: {{model}}</div>'); // create an isolate scope var isolatedScope = scope.$new(true); // import the model from the parent scope into your isolated scope. This establishes the two-way binding. isolatedScope.model = scope.$eval(attr.model); // add the template to the DOM element.append(template); // compile and link the template against the isolate scope $compile(template)(isolatedScope); }
隔离范围的优点是任何存在(即在范围内)的绑定都是您显式导入的绑定。将此与非隔离作用域进行对比——其中绑定不需要在当前作用域上显式定义——它可以从链上更高的任何作用域继承。
回答by Sam
I wrote this. You use it like this:
我写了这个。你像这样使用它:
twowaybinder.attach($scope, $attrs.isDeactivated, 'isDeactivated');
twowaybinder.attach($scope, $attrs.isDeactivated, 'isDeactivated');
.factory('twowaybinder', function ($parse) {
function twoWayBind($scope, remote, local){
var remoteSetter = $parse(remote).assign;
var localSetter = $parse(local).assign;
$scope.$parent.$watch(remote, function (value) {
localSetter($scope, value);
});
$scope.$watch(local, function (value) {
remoteSetter($scope, value);
});
}
return {
attach : twoWayBind
};
});
It will give u true two-way binding from scope values. Note I dont think that $scope.$parent is neccessary, as in an inherited or no scope scenario any expression should resolve on the current scope. You would only need to call $parent in an isolated scope in which case you wouldn't use this, you would use the isolated scope config.
它会给你真正的双向绑定范围值。注意我不认为 $scope.$parent 是必要的,因为在继承或无作用域的情况下,任何表达式都应该在当前作用域上解析。您只需要在隔离范围内调用 $parent 在这种情况下您不会使用它,您将使用隔离范围配置。
回答by Amin Rahimi
you may use two directives if gg is an object then "=" points to one place of memory!
如果 gg 是一个对象,则您可以使用两个指令,然后“=”指向一个内存位置!
angular.module('mymodule', []).directive('a', function($parse, $modal) {
return {
restrict : 'A',
scope : {
gg : "="
},
require : "b",
link : function(scope, element, attrs, bCtrl) {
scope.$watch('gg',function(gg){
bCtrl.setset(scope.gg);
}
}
}
});
angular.module('mymodule').directive('b', function($parse, $modal) {
return {
restrict : 'A',
/*
* scope : { showWarn : "=" },
*/
controller : function($scope) {
$scope.bb = {};
this.setset = function(nn) {
$scope.bb=nn;
};
}
});