我正在尝试从我的自定义指令中获取已评估的属性,但我找不到正确的方法。
我创建了this jsFiddle来详细说明。
<div ng-controller="MyCtrl">
<input my-directive value="123">
<input my-directive value="{{1+1}}">
</div>
myApp.directive('myDirective', function () {
return function (scope, element, attr) {
element.val("value = "+attr.value);
}
});
我错过了什么?
答案 0 :(得分:567)
注意:当我找到更好的解决方案时,我会更新此答案。只要它们保持相关,我也会保留旧答案以供将来参考。最新和最好的答案是第一位的。
angularjs中的指令非常强大,但需要时间来理解它们背后的进程。
创建指令时,angularjs允许您创建一个隔离范围,其中包含一些与父范围的绑定。这些绑定由属性指定,您在DOM中附加元素以及如何在指令定义对象中定义范围属性。
您可以在范围内定义3种类型的绑定选项,并将它们写为前缀相关属性。
angular.module("myApp", []).directive("myDirective", function () {
return {
restrict: "A",
scope: {
text: "@myText",
twoWayBind: "=myTwoWayBind",
oneWayBind: "&myOneWayBind"
}
};
}).controller("myController", function ($scope) {
$scope.foo = {name: "Umur"};
$scope.bar = "qwe";
});
HTML 的
<div ng-controller="myController">
<div my-directive my-text="hello {{ bar }}" my-two-way-bind="foo" my-one-way-bind="bar">
</div>
</div>
在这种情况下,在指令范围内(无论是在链接函数还是控制器中),我们可以像这样访问这些属性:
/* Directive scope */
in: $scope.text
out: "hello qwe"
// this would automatically update the changes of value in digest
// this is always string as dom attributes values are always strings
in: $scope.twoWayBind
out: {name:"Umur"}
// this would automatically update the changes of value in digest
// changes in this will be reflected in parent scope
// in directive's scope
in: $scope.twoWayBind.name = "John"
//in parent scope
in: $scope.foo.name
out: "John"
in: $scope.oneWayBind() // notice the function call, this binding is read only
out: "qwe"
// any changes here will not reflect in parent, as this only a getter .
由于这个答案已被接受,但有一些问题,我将把它更新为更好的答案。显然,$parse
是一种不属于当前范围的属性的服务,这意味着它只需要角度表达式而无法达到范围。
{{
,}}
表达式是在angularjs启动时编译的,这意味着当我们尝试在我们的指令postlink
方法中访问它们时,它们已经被编译。 ({{1+1}}
已在指令中2
。
这就是你想要使用的方式:
var myApp = angular.module('myApp',[]);
myApp.directive('myDirective', function ($parse) {
return function (scope, element, attr) {
element.val("value=" + $parse(attr.myDirective)(scope));
};
});
function MyCtrl($scope) {
$scope.aaa = 3432;
}
<div ng-controller="MyCtrl">
<input my-directive="123">
<input my-directive="1+1">
<input my-directive="'1+1'">
<input my-directive="aaa">
</div>
你应该注意的一件事是,如果你想设置值字符串,你应该用引号括起来。 (见第3条输入)
这是一个小提琴:http://jsfiddle.net/neuTA/6/
对于那些可能像我一样被误导的人,我不会删除它,请注意使用$eval
完全正确的方法,但是$parse
有不同的行为,你可能不需要在大多数情况下使用它。
这样做的方法是再次使用scope.$eval
。它不仅可以编译角度表达式,还可以访问当前作用域的属性。
var myApp = angular.module('myApp',[]);
myApp.directive('myDirective', function () {
return function (scope, element, attr) {
element.val("value = "+ scope.$eval(attr.value));
}
});
function MyCtrl($scope) {
}
您缺少的是$eval
。
http://docs.angularjs.org/api/ng.$rootScope.Scope#$eval
在返回结果的当前作用域上执行表达式。表达式中的任何异常都会被传播(未捕获)。这在评估角度表达式时很有用。
答案 1 :(得分:82)
对于需要在不使用隔离范围的指令中插值的属性值,例如
<input my-directive value="{{1+1}}">
使用属性&#39;方法$observe
:
myApp.directive('myDirective', function () {
return function (scope, element, attr) {
attr.$observe('value', function(actual_value) {
element.val("value = "+ actual_value);
})
}
});
从directive页面
观察插值属性:使用
$observe
观察包含插值的属性的值更改(例如src="{{bar}}"
)。这不仅非常有效,而且它也是轻松获得实际值的唯一方法,因为在链接阶段,插值尚未被评估,因此此时的值设置为{{1 }}
如果属性值只是一个常数,例如
undefined
如果值是数字或布尔值,您可以使用$eval,并且您想要正确的类型:
<input my-directive value="123">
如果属性值是字符串常量,或者您希望该值在您的指令中是字符串类型,则可以直接访问它:
return function (scope, element, attr) {
var number = scope.$eval(attr.value);
console.log(number, number + 1);
});
但是,在您的情况下,由于您希望支持插值和常量,请使用return function (scope, element, attr) {
var str = attr.value;
console.log(str, str + " more");
});
。
答案 2 :(得分:4)
这里的其他答案非常正确,而且很有价值。但有时你只是想要简单:在指令实例化时获得一个普通的旧解析值,而不需要更新,并且不会弄乱孤立范围。例如,将声明性有效负载作为数组或散列对象提供到指令中可能很方便:
my-directive-name="['string1', 'string2']"
在这种情况下,您可以切入追逐并使用一个不错的基本angular.$eval(attr.attrName)
。
element.val("value = "+angular.$eval(attr.value));
工作Fiddle。
答案 3 :(得分:4)
对于同样的解决方案,我一直在寻找Angularjs directive with ng-Model
。
这是解决问题的代码。
myApp.directive('zipcodeformatter', function () {
return {
restrict: 'A', // only activate on element attribute
require: '?ngModel', // get a hold of NgModelController
link: function (scope, element, attrs, ngModel) {
scope.$watch(attrs.ngModel, function (v) {
if (v) {
console.log('value changed, new value is: ' + v + ' ' + v.length);
if (v.length > 5) {
var newzip = v.replace("-", '');
var str = newzip.substring(0, 5) + '-' + newzip.substring(5, newzip.length);
element.val(str);
} else {
element.val(v);
}
}
});
}
};
});
HTML DOM
<input maxlength="10" zipcodeformatter onkeypress="return isNumberKey(event)" placeholder="Zipcode" type="text" ng-readonly="!checked" name="zipcode" id="postal_code" class="form-control input-sm" ng-model="patient.shippingZipcode" required ng-required="true">
我的结果是:
92108-2223
答案 4 :(得分:2)
var myApp = angular.module('myApp',[]);
myApp .directive('myDirective', function ($timeout) {
return function (scope, element, attr) {
$timeout(function(){
element.val("value = "+attr.value);
});
}
});
function MyCtrl($scope) {
}
使用$ timeout因为dom加载后的指令调用所以你的更改不适用
答案 5 :(得分:-4)
这里有很多好的答案,但有时候你只想要一个简单,易用,陈旧的jQuery-ish解决方案。
我的解决方案无法处理DOM的更改。如果属性可能会更改,请不要使用我的方法!
在我的情况下,我有一个元素,需要检索属性(rel)的值。
模板:
<div ng-repeat="elm in array">
<button class="poi-lines-show" rel="li-{{$index}}">button-text</button>
</div>
在我的指令中:
var buttons = element[0].querySelectorAll('button');
for (var i=0; i<buttons.length; i++) {
var target = angular.element(buttons[i]);
console.log(target.attr('rel')); // Outputs 'li-0', 'li-1', 'li-2' etc
}