【问题标题】:How to get evaluated attributes inside a custom directive如何在自定义指令中获取评估属性
【发布时间】:2012-09-04 11:15:19
【问题描述】:

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

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

我错过了什么?

【问题讨论】:

标签: javascript binding angularjs directive


【解决方案1】:

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

更好的答案:

angularjs 中的指令非常强大,但需要时间来理解它们背后的进程。

在创建指令时,angularjs 允许您创建一个隔离范围,其中包含一些与父范围的绑定。这些绑定由您在 DOM 中附加元素的 属性 以及如何在 指令定义对象 中定义 scope 属性来指定。

您可以在范围内定义 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>​​​​​​​​

您应该注意的一件事是,如果您想设置值字符串,您应该将它用引号括起来。 (见第三个输入)

这里是小提琴: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

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

【讨论】:

  • 感谢您的回复,但这不是解决方案。我已经用你的代码更新了小提琴。 jsfiddle.net/neuTA/3
  • 在 Chrome 中尝试使用 scope.$parse: Object # has no method '$parse' 时出现此错误。如果我注入 $parse 服务 -- function($parse) { return function (scope ... -- 然后尝试:"value = " + $parse(attr.value) -- 这似乎对我不起作用要么。
  • @Mark 你是对的,奇怪的是它在小提琴示例 (jsfiddle.net/neuTA/4) 中有效,但在我拥有的代码中无效......角度版本?
  • 在“更好的答案”部分,$scope.text 将在链接函数中未定义。答案目前的措辞方式听起来不会是不确定的。您必须使用 $observe() (或者 $watch() 实际上也可以在这里工作)来异步查看插值。请参阅我的回答以及stackoverflow.com/questions/14876112/…
  • "Still OK" Answer 中,$parse 服务似乎被注入然后从未使用过。我错过了什么吗?
【解决方案2】:

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

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

来自directive 页面,

观察插值属性:使用$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

【讨论】:

  • 这是您找到的唯一解决方案吗?
  • 是的,既然指令页面推荐这种方法,我就是这样做的。
  • +1,这是 IMO 的最佳答案,因为它不会在指令上强制范围,并且还涵盖 $observe 的属性更改
【解决方案3】:

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

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

在这种情况下,您可以切入正题,只使用一个不错的基本angular.$eval(attr.attrName)

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

工作Fiddle

【讨论】:

  • 我不知道您是否使用了旧的 Angular 版本,但您所有的代码示例都是无效的 javascript(my-directive-name=) 或无效的 Angular(angular.$eval 没有'不存在),所以 -1
  • Ummm...鉴于这篇文章已有一年多的历史,如果某些内容自弃用就不足为奇了。但是,在 10 秒的 Google 搜索中可以找到大量关于 $eval 的资料,包括 right here at SO。您引用的另一个示例是 HTML 调用,而不是 Javascript。
  • $scope.$eval(attr.val) 在 Angular 1.4 中工作。需要将 $scope 注入到指令链接函数中。
【解决方案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

【讨论】:

    【解决方案5】:
    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 加载后调用,所以你的更改不适用

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-03-03
      • 1970-01-01
      • 1970-01-01
      • 2020-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多