AngularJS 指令属性从控制器访问

Posted

技术标签:

【中文标题】AngularJS 指令属性从控制器访问【英文标题】:AngularJS directives attributes access from the controller 【发布时间】:2013-03-01 05:26:39 【问题描述】:

我正在尝试访问控制器函数中指令的属性。但是,当我访问它时,它是未定义的。我注意到,如果我做一个简单的计时器,它就可以工作。有没有办法只在指令及其作用域准备好并设置为可以使用之后才执行代码?

我做了一个小提琴。确保您的控制台已打开。 http://jsfiddle.net/paulocoelho/uKA2L/1/

这是我在小提琴中使用的代码:

<div ng-app="testApp" >
    <testcomponent text="hello!"></testcomponent>
</div>
var module = angular.module('testApp', [])
    .directive('testcomponent', function () 
    return 
        restrict: 'E',
        template: '<div><p>text This will run fine! </p></div>',
        scope: 
            text: '@text'
        ,
        controller: function ($scope, $element) 
            console.log($scope.text); // this will return undefined
            setTimeout(function () 
                console.log($scope.text);    // this will return the actual value...
            , 1000);
        ,
        link: function ($scope, $element, $attrs) 
            console.log($scope.text);
            setTimeout(function () 
                console.log($scope.text);
            , 1000);
        
    ;
);

【问题讨论】:

【参考方案1】:

有效的是,如果你设置了

scope.text = $attrs.text;

在链接和控制器功能中。这只会在最初起作用,因为没有 2way 数据绑定。不过你可以使用$attrs.observe。

见小提琴:http://jsfiddle.net/JohannesJo/nm3FL/2/

【讨论】:

这将导致 linting 失败。因为attrs.text 未知。 @DougChamberlain 您可以使用 JSDoc 来解决这个问题。 @param string attrs.text 之类的东西应该可以解决您的问题。【参考方案2】:

在隔离作用域中,不能在链接函数中访问使用“@”定义的局部作用域属性。正如@remigio 已经提到的那样,这种本地范围属性在那时是undefined。必须使用 $attrs.$observe() 或 $scope.$watch() 来异步获取(插值)值。

如果您在属性中传递一个常量值(即,不需要插值,即该属性的值不包含任何 ),则不需要 '@' 或 $observer 或 $手表。您可以按照@hugo 的建议使用 $attrs.attribute_name 一次,或者如果您传递一个数字或布尔值并且想要获得正确的类型,您可以使用 $scope.$eval($attrs .attribute_name) 一次。

如果您使用“=”将本地范围属性数据绑定到父范围属性,则该属性的值将在链接函数中可用(不需要 $observe 或 $watch 或 $eval)。

【讨论】:

【参考方案3】:

从 Angular 1.3 开始,您可以使用bindToController。这是我如何使用它的示例。在这里,我将属性添加到范围,然后使用bindToController 在控制器内部使用它:

var module = angular.module('testApp', [])
    .directive('testcomponent', function () 
    return 
        restrict: 'E',
        template: '<div><p>text This will run fine! </p></div>',
        scope: 
            text: '@text'
        ,
        controller: function () 
            console.log(this.text);
        ,
        controllerAs: 'vm',
        bindToController: true
    ;
);

Angular 1.3 为指令定义引入了一个新属性 名为 bindToController 的对象,它完全按照它所说的那样做。什么时候 在使用 controllerAs 的具有隔离范围的指令中设置为 true, 组件的属性绑定到控制器而不是 范围。这意味着,Angular 确保,当控制器 实例化后,隔离作用域绑定的初始值为 可用于此,并且将来的更改也会自动 可用。

【讨论】:

@rjh 你在调用这样的指令时传递了text 吗? &lt;testcomponent text="hello!"&gt;&lt;/testcomponent&gt;【参考方案4】:

而不是使用$scope 来获取指令属性值,我个人更喜欢将$attrs 用于controller 函数,或者仅在link 函数的第三个参数处使用attrs。通过以下代码从controller 获取属性值时我没有超时:

var module = angular.module('testApp', [])
    .directive('testcomponent', function () 
    return 
    restrict: 'E',
    template: '<div><p>text This will run fine! </p></div>',
    scope: 
        text: '@text'
    ,
    controller: ['$scope','$attrs', function ($scope, $attrs) 
        console.log($attrs.text); // just call to the $attrs instead $scope and i got the actual value
        $scope.text = $attrs.text; //assign attribute to the scope
    ]
    ;
);

【讨论】:

【参考方案5】:

链接函数在 $digest 循环之前被调用,此时范围变量是未定义的。查看this chapter 和this other 以了解链接功能如何运作。您只使用链接函数来定义指令的监视和/或行为,而不是操作模型,这是在控制器中完成的。

【讨论】:

这并不完全正确。范围变量由 post-link 函数运行时定义,并且可以在链接函数中操作数据模型。仅当您计划使用它通过 require 属性与另一个指令进行通信时,才需要在指令上使用控制器。控制器实际上首先运行,然后是预链接,一直向下运行 dom 树到叶子,然后后链接回到根。请参阅此线程以进行澄清。 ***.com/questions/24615103/…【参考方案6】:

如果您从指令访问此值以使用指令插入视图中,您可以使用 $compile api 访问此属性并执行类似的操作

var string = "<div> " + scope.text + "</div>";
$compile(string)(scope, function(cloned, scope)
       element.append(cloned);
);

【讨论】:

以上是关于AngularJS 指令属性从控制器访问的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS指令隔离范围和父范围

angularjs中的CKEditor自定义插件

从 AngularJS 指令访问属性

在 AngularJS 中从没有隔离范围的指令调用控制器函数

来自控制器的访问指令方法

如何在模块化的angularjs范围内测试指令?