javascript AngularJS:如何将常量对象绑定到指令
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16947266/
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
AngularJS: how to bind a constant object to a directive
提问by Michael Williamson
I've created a directive with a binding using "scope". In some cases, I want to bind a constant object. For instance, with HTML:
我已经使用“范围”创建了一个带有绑定的指令。在某些情况下,我想绑定一个常量对象。例如,使用 HTML:
<div ng-controller="Ctrl">
<greeting person="{firstName: 'Bob', lastName: 'Jones'}"></greeting>
</div>
and JavaScript:
和 JavaScript:
var app = angular.module('myApp', []);
app.controller("Ctrl", function($scope) {
});
app.directive("greeting", function () {
return {
restrict: "E",
replace: true,
scope: {
person: "="
},
template:
'<p>Hello {{person.firstName}} {{person.lastName}}</p>'
};
});
Although this works, it also causes a JavaScript error:
虽然这有效,但它也会导致 JavaScript 错误:
Error: 10 $digest() iterations reached. Aborting!
(Fiddle demonstrating the problem)
What's the correct way to bind a constant object without causing the error?
在不导致错误的情况下绑定常量对象的正确方法是什么?
采纳答案by Michael Williamson
Here's the solution I came up with, based on @sh0ber's answer:
这是我根据@sh0ber 的回答提出的解决方案:
Implement a custom link
function. If the attribute is valid JSON, then it's a constant value, so we only evaluate it once. Otherwise, watch and update the value as normal (in other words, try to behave as a =
binding). scope
needs to be set to true
to make sure that the assigned value only affects this instance of the directive.
实现自定义link
功能。如果该属性是有效的 JSON,则它是一个常量值,因此我们只对其进行一次评估。否则,照常观察和更新值(换句话说,尝试表现为=
绑定)。scope
需要设置为true
以确保分配的值仅影响该指令的实例。
HTML:
HTML:
<div ng-controller="Ctrl">
<greeting person='{"firstName": "Bob", "lastName": "Jones"}'></greeting>
<greeting person="jim"></greeting>
</div>
JavaScript:
JavaScript:
var app = angular.module('myApp', []);
app.controller("Ctrl", function($scope) {
$scope.jim = {firstName: 'Jim', lastName: "Bloggs"};
});
app.directive("greeting", function () {
return {
restrict: "E",
replace: true,
scope: true,
link: function(scope, elements, attrs) {
try {
scope.person = JSON.parse(attrs.person);
} catch (e) {
scope.$watch(function() {
return scope.$parent.$eval(attrs.person);
}, function(newValue, oldValue) {
scope.person = newValue;
});
}
},
template: '<p>Hello {{person.firstName}} {{person.lastName}}</p>'
};
});
回答by martinpaulucci
You are getting that error because Angular is evaluating the expression every time. '=' is for variable names.
您收到该错误是因为 Angular 每次都在评估表达式。'=' 用于变量名。
Here are two alternative ways to achieve the same think without the error.
这里有两种替代方法可以在没有错误的情况下实现相同的想法。
First Solution:
第一个解决方案:
app.controller("Ctrl", function($scope) {
$scope.person = {firstName: 'Bob', lastName: 'Jones'};
});
app.directive("greeting", function () {
return {
restrict: "E",
replace: true,
scope: {
person: "="
},
template:
'<p>Hello {{person.firstName}} {{person.lastName}}</p>'
};
});
<greeting person="person"></greeting>
Second Solution:
第二种解决方案:
app.directive("greeting2", function () {
return {
restrict: "E",
replace: true,
scope: {
firstName: "@",
lastName: "@"
},
template:
'<p>Hello {{firstName}} {{lastName}}</p>'
};
});
<greeting2 first-name="Bob" last-Name="Jones"></greeting2>
回答by Dan
Another option:
另外一个选择:
app.directive("greeting", function () {
return {
restrict: "E",
link: function(scope,element,attrs){
scope.person = scope.$eval(attrs.person);
},
template: '<p>Hello {{person.firstName}} {{person.lastName}}</p>'
};
});
回答by mirrormx
This is because if you use the =
type of scope field link, the attribute value is being observed for changes, but tested for reference equality (with !==
) rather than tested deeply for equality. Specifying object literal in-line will cause angular to create the new object whenever the atribute is accessed for getting its value — thus when angular does dirty-checking, comparing the old value to the current one always signals the change.
这是因为如果您使用=
范围字段链接的类型,则会观察属性值是否发生变化,但会测试引用相等性(with !==
),而不是深入测试相等性。内联指定对象文字将导致 angular 在访问属性以获取其值时创建新对象——因此,当 angular 进行脏检查时,将旧值与当前值进行比较总是表示更改。
One way to overcome that would be to modify angular's source as described here:
克服这个问题的一种方法是修改 angular 的来源,如下所述:
https://github.com/mgonto/angular.js/commit/09d19353a2ba0de8edcf625aa7a21464be830f02.
https://github.com/mgonto/angular.js/commit/09d19353a2ba0de8edcf625aa7a21464be830f02。
Otherwise, you could create your object in the controller and reference it by name in the element's attribute:
否则,您可以在控制器中创建对象并在元素的属性中按名称引用它:
HTML
HTML
<div ng-controller="Ctrl">
<greeting person="personObj"></greeting>
</div>
JS
JS
app.controller("Ctrl", function($scope)
{
$scope.personObj = { firstName : 'Bob', lastName : 'Jones' };
});
Yet another way is to create the object in the parent element's ng-init
directive and later reference it by name (but this one is less readable):
另一种方法是在父元素的ng-init
指令中创建对象,然后按名称引用它(但这种方法可读性较差):
<div ng-controller="Ctrl" ng-init="personObj = { firstName : 'Bob', lastName : 'Jones' }">
<greeting person="personObj"></greeting>
</div>
回答by Mark Rajcok
I don't particularly like using eval()
, but if you really want to get this to work with the HTML you provided:
我不是特别喜欢使用eval()
,但是如果您真的想让它与您提供的 HTML 一起使用:
app.directive("greeting", function() {
return {
restrict: "E",
compile: function(element, attrs) {
eval("var person = " + attrs.person);
var htmlText = '<p>Hello ' + person.firstName + ' ' + person.lastName + '</p>';
element.replaceWith(htmlText);
}
};
});
回答by Peter Kovacs
I had the same problem, I solved it by parsing the json in the compile step:
我遇到了同样的问题,我通过在编译步骤中解析 json 来解决它:
angular.module('foo', []).
directive('myDirective', function () {
return {
scope: {
myData: '@'
},
controller: function ($scope, $timeout) {
$timeout(function () {
console.log($scope.myData);
});
},
template: "{{myData | json}} a is {{myData.a}} b is {{myData.b}}",
compile: function (element, attrs) {
attrs['myData'] = angular.fromJson(attrs['myData']);
}
};
});
The one drawback is that the $scope
isn't initially populated when the controller first runs.
一个缺点是$scope
当控制器第一次运行时最初没有填充。
Here's a JSFiddlewith this code.
这是带有此代码的JSFiddle。