将 AngularJS 范围变量从指令传递到控制器的最简单方法?

Posted

技术标签:

【中文标题】将 AngularJS 范围变量从指令传递到控制器的最简单方法?【英文标题】:Easiest way to pass an AngularJS scope variable from directive to controller? 【发布时间】:2012-10-30 09:38:30 【问题描述】:

将 AngularJS 范围变量从指令传递到控制器的最简单方法是什么?我见过的所有示例似乎都如此复杂,难道没有一种方法可以让我从指令中访问控制器,并设置其中一个作用域变量吗?

【问题讨论】:

见***.com/questions/17900201/…了解更多 【参考方案1】:

2014/8/25 编辑: Here 是我创建它的地方。

感谢@anvarik。

这里是JSFiddle。我忘记了我在哪里分叉的。但这是一个很好的例子,向您展示了 = 和 @ 之间的区别

<div ng-controller="MyCtrl">
    <h2>Parent Scope</h2>
    <input ng-model="foo"> <i>// Update to see how parent scope interacts with component scope</i>    
    <br><br>
    <!-- attribute-foo binds to a DOM attribute which is always
    a string. That is why we are wrapping it in curly braces so
    that it can be interpolated. -->
    <my-component attribute-foo="foo" binding-foo="foo"
        isolated-expression-foo="updateFoo(newFoo)" >
        <h2>Attribute</h2>
        <div>
            <strong>get:</strong> isolatedAttributeFoo
        </div>
        <div>
            <strong>set:</strong> <input ng-model="isolatedAttributeFoo">
            <i>// This does not update the parent scope.</i>
        </div>
        <h2>Binding</h2>
        <div>
            <strong>get:</strong> isolatedBindingFoo
        </div>
        <div>
            <strong>set:</strong> <input ng-model="isolatedBindingFoo">
            <i>// This does update the parent scope.</i>
        </div>
        <h2>Expression</h2>    
        <div>
            <input ng-model="isolatedFoo">
            <button class="btn" ng-click="isolatedExpressionFoo(newFoo:isolatedFoo)">Submit</button>
            <i>// And this calls a function on the parent scope.</i>
        </div>
    </my-component>
</div>
var myModule = angular.module('myModule', [])
    .directive('myComponent', function () 
        return 
            restrict:'E',
            scope:
                /* NOTE: Normally I would set my attributes and bindings
                to be the same name but I wanted to delineate between
                parent and isolated scope. */                
                isolatedAttributeFoo:'@attributeFoo',
                isolatedBindingFoo:'=bindingFoo',
                isolatedExpressionFoo:'&'
                    
        ;
    )
    .controller('MyCtrl', ['$scope', function ($scope) 
        $scope.foo = 'Hello!';
        $scope.updateFoo = function (newFoo) 
            $scope.foo = newFoo;
        
    ]);

【讨论】:

很好的解释和例子!我想知道为什么文档如此复杂?......还是我不是一个伟大的程序员 请注意,这个小提琴的工作原理是一样的,但如果你将 angular 版本更改为更新的版本(即从 1.0.1 到 1.2.1),它将不再工作。语法一定有所改变。 最后一个清晰的例子是有意义的。 2 小时头痛在 10 秒内解决。 在方法解释如何将值从控制器传递到指令而不是从指令到控制器时,为什么每个人都投票赞成这个答案? isolatedBindingFoo:'=bindingFoo' 可以将数据从指令传递到控制器。或者您可以使用服务。在你对某人投反对票之前,如果你不明白,欢迎你先问。【参考方案2】:

等到 angular 计算完变量

我对此进行了很多摆弄,即使在范围内使用"=" 定义的变量也无法使其工作。以下是三种解决方案,具体取决于您的情况。


解决方案 #1


我发现变量在传递给指令时还没有被角度评估。这意味着您可以在模板中访问和使用它,但不能在链接或应用控制器函数中使用它,除非我们等待它被评估。

如果您的变量正在更改,或者通过请求获取,您应该使用$observe$watch

app.directive('yourDirective', function () 
    return 
        restrict: 'A',
        // NB: no isolated scope!!
        link: function (scope, element, attrs) 
            // observe changes in attribute - could also be scope.$watch
            attrs.$observe('yourDirective', function (value) 
                if (value) 
                    console.log(value);
                    // pass value to app controller
                    scope.variable = value;
                
            );
        ,
        // the variable is available in directive controller,
        // and can be fetched as done in link function
        controller: ['$scope', '$element', '$attrs',
            function ($scope, $element, $attrs) 
                // observe changes in attribute - could also be scope.$watch
                $attrs.$observe('yourDirective', function (value) 
                    if (value) 
                        console.log(value);
                        // pass value to app controller
                        $scope.variable = value;
                    
                );
            
        ]
    ;
)
.controller('MyCtrl', ['$scope', function ($scope) 
    // variable passed to app controller
    $scope.$watch('variable', function (value) 
        if (value) 
            console.log(value);
        
    );
]);

这是 html(记住括号!):

<div ng-controller="MyCtrl">
    <div your-directive=" someObject.someVariable "></div>
    <!-- use ng-bind in stead of  , when you can to avoids FOUC -->
    <div ng-bind="variable"></div>
</div>

请注意,如果您使用的是$observe 函数,则不应在范围内将变量设置为"="。另外,我发现它将对象作为字符串传递,因此如果您传递对象,请使用 solution #2scope.$watch(attrs.yourDirective, fn) (,如果您的变量不是,则使用 #3变化)。


解决方案 #2


如果您的 变量是在例如另一个控制器,但只需要等到 angular 评估它后再将其发送到应用控制器,我们可以使用$timeout 等到$apply 运行。我们还需要使用$emit 将其发送到父作用域应用控制器(由于指令中的隔离作用域):

app.directive('yourDirective', ['$timeout', function ($timeout) 
    return 
        restrict: 'A',
        // NB: isolated scope!!
        scope: 
            yourDirective: '='
        ,
        link: function (scope, element, attrs) 
            // wait until after $apply
            $timeout(function()
                console.log(scope.yourDirective);
                // use scope.$emit to pass it to controller
                scope.$emit('notification', scope.yourDirective);
            );
        ,
        // the variable is available in directive controller,
        // and can be fetched as done in link function
        controller: [ '$scope', function ($scope) 
            // wait until after $apply
            $timeout(function()
                console.log($scope.yourDirective);
                // use $scope.$emit to pass it to controller
                $scope.$emit('notification', scope.yourDirective);
            );
        ]
    ;
])
.controller('MyCtrl', ['$scope', function ($scope) 
    // variable passed to app controller
    $scope.$on('notification', function (evt, value) 
        console.log(value);
        $scope.variable = value;
    );
]);

这是 html(没有括号!):

<div ng-controller="MyCtrl">
    <div your-directive="someObject.someVariable"></div>
    <!-- use ng-bind in stead of  , when you can to avoids FOUC -->
    <div ng-bind="variable"></div>
</div>

解决方案 #3


如果您的变量没有改变并且您需要在指令中对其进行评估,您可以使用$eval 函数:

app.directive('yourDirective', function () 
    return 
        restrict: 'A',
        // NB: no isolated scope!!
        link: function (scope, element, attrs) 
            // executes the expression on the current scope returning the result
            // and adds it to the scope
            scope.variable = scope.$eval(attrs.yourDirective);
            console.log(scope.variable);

        ,
        // the variable is available in directive controller,
        // and can be fetched as done in link function
        controller: ['$scope', '$element', '$attrs',
            function ($scope, $element, $attrs) 
                // executes the expression on the current scope returning the result
                // and adds it to the scope
                scope.variable = scope.$eval($attrs.yourDirective);
                console.log($scope.variable);
            
         ]
    ;
)
.controller('MyCtrl', ['$scope', function ($scope) 
    // variable passed to app controller
    $scope.$watch('variable', function (value) 
        if (value) 
            console.log(value);
        
    );
]);

这是 html(记住括号!):

<div ng-controller="MyCtrl">
    <div your-directive=" someObject.someVariable "></div>
    <!-- use ng-bind instead of  , when you can to avoids FOUC -->
    <div ng-bind="variable"></div>
</div>

另外,看看这个答案:https://***.com/a/12372494/1008519

FOUC(无样式内容闪现)问题参考:http://deansofer.com/posts/view/14/AngularJs-Tips-and-Tricks-UPDATED

有意者:here's an article on the angular life cycle

【讨论】:

有时一个简单的ng-if="someObject.someVariable" 在指令(或以指令作为属性的元素)上就足够了——指令只有在someObject.someVariable 被定义后才会生效。

以上是关于将 AngularJS 范围变量从指令传递到控制器的最简单方法?的主要内容,如果未能解决你的问题,请参考以下文章

将范围变量从控制器绑定到指令而不使用$ watch

AngularJS自定义验证指令 - 如何避免使用隔离范围

AngularJS:将函数从控制器传递到指令的多种方法

如何将变量从 jQuery 传递到 AngularJs 函数

AngularJS指令隔离范围和父范围

指令的angularjs typescript控制器类中未定义的范围变量