如何在自定义指令中获取评估的属性


363

我正在尝试从我的自定义指令中获取一个评估的属性,但是我找不到正确的方法。

我已经创建了这个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);
    }
});

我想念什么?


您可以点击以下链接,以更好地了解指令。undefinednull.com/2014/02/11/...
人员Prasanna Sasne

Answers:


573

注意:我会找到更好的解决方案来更新此答案。只要它们仍然相关,我还将保留旧答案以供将来参考。最新最好的答案是第一位的。

更好的答案:

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.$ro​​otScope.Scope#$eval

在当前范围内执行表达式并返回结果。表达式中的任何异常都会传播(未捕获)。这在评估角度表达式时很有用。


感谢您的答复,但这不是解决方案。我已经用您的代码更新了小提琴。jsfiddle.net/neuTA/3
Shlomi Schwartz

在Chrome浏览器中,尝试使用scope。$ parse时出现此错误。Object#<Object>没有方法'$ parse'。如果我注入$ parse服务-function($ parse){return function(scope ...-然后尝试:“ value =” + $ parse(attr.value)-对我来说似乎不起作用无论是。
马克Rajcok

@Mark你是对的,奇怪的是它在小提琴示例(jsfiddle.net/neuTA/4)中有效,但在我有...角版本的代码中却没有?
Shlomi Schwartz 2012年

2
在“更好的答案”部分,$scope.text链接功能中未定义。答案目前的措辞方式,听起来好像是不确定的。您必须使用$ observe()(或$ watch()实际上也可以在此处使用)异步查看插值。见我的回答也stackoverflow.com/questions/14876112/...
马克Rajcok

1
“仍然正常”答案中,似乎该$parse服务已注入,然后从未使用过。我想念什么吗?
superjos

83

对于需要在不使用隔离范围的指令中插入的属性值,例如,

<input my-directive value="{{1+1}}">

使用属性的方法$observe

myApp.directive('myDirective', function () {
  return function (scope, element, attr) {
    attr.$observe('value', function(actual_value) {
      element.val("value = "+ actual_value);
    })
 }
});

指令页面上,

观察插值属性:$observe用于观察包含插值的属性的值变化(例如src="{{bar}}")。这不仅非常有效,而且还是轻松获取实际值的唯一方法,因为在链接阶段尚未评估插值,因此此时将值设置为undefined

如果属性值只是一个常量,例如,

<input my-directive value="123">

如果值是数字或布尔值,并且需要正确的类型,则可以使用$ eval

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");
});

但是,根据您的情况,由于要支持插值和常量,请使用$observe


这是您找到的唯一解决方案吗?
Shlomi Schwartz 2012年

4
是的,并且由于指令页面推荐了这种方法,所以这就是我的方法。
Mark Rajcok 2012年

7
+1,这是IMO的最佳答案,因为它不会在指令上强制作用域,而且还可以使用$ observe覆盖属性更改
BiAiB 2015年

4

这里的其他答案非常正确且有价值。但是有时您只是想简单:在指令实例化时获得一个普通的旧解析值,而无需更新,也不会弄乱隔离范围。例如,以数组或哈希对象的形式在指令中提供声明式有效载荷可能很方便:

my-directive-name="['string1', 'string2']"

在这种情况下,您可以使用简单的basic来进行追赶angular.$eval(attr.attrName)

element.val("value = "+angular.$eval(attr.value));

工作小提琴


我不知道您是否使用了旧的角度版本,但是您所有的代码示例都是无效的javascript(my-directive-name =)或无效的angular(角度。$ eval不存在),所以-1
BiAiB 2015年

嗯...鉴于此职位已有一年多的历史了,因此自从不赞成使用某些内容后,就不足为奇了。但是,进行10秒钟的Google搜索会发现有关$ eval的大量内容,包括SO的内容。您引用的另一个示例是HTML而不是Java语言的调用。
XML

$ scope。$ eval(attr.val)在角度1.4中工作。需要将$ scope注入到指令链接函数中。
Martin Connell

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

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加载后指令调用,因此您的更改不适用

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.