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

win*_*toy 98 angularjs angularjs-directive ng-controller

将AngularJS范围变量从指令传递给控制器​​的最简单方法是什么?我见过的所有例子看起来都很复杂,是不是我可以从指令访问控制器,并设置其中一个范围变量?

max*_*sam 150

编辑于2014/8/25: 是我分叉的地方.

谢谢@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>
Run Code Online (Sandbox Code Playgroud)
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;
        }
    }]);
Run Code Online (Sandbox Code Playgroud)

  • 很棒的解释和例子!我想知道为什么文档如此复杂?...或者我是不是一个伟大的程序员? (29认同)
  • 当方法解释如何将值从控制器传递给指令而不是从指令传递给控制器​​时,为什么每个人都投票给这个答案? (4认同)
  • 请注意,这个小提琴的工作原理如下,但是如果将角度版本更改为更新的角度版本(即从1.0.1到1.2.1),它将不再起作用.关于语法必须改变一些东西. (2认同)
  • 最后一个明确的例子是有道理的.2小时头痛在10秒内解决. (2认同)
  • isolatedBindingFoo:'= bindingFoo'可以将数据从指令传递给控制器​​.或者你可以使用服务.在您投票之前,如果您不理解,欢迎您首先询问. (2认同)

mlu*_*noe 70

等到angular已经评估了变量

我有很多摆弄这个问题,即使使用"="范围中定义的变量也无法使其工作.根据您的具体情况,这里有三种解决方案.


解决方案#1


我发现变量在传递给指令时没有按角度进行评估.这意味着您可以访问它并在模板中使用它,但不能在链接或app控制器功能中使用它,除非我们等待它被评估.

如果您的变量正在更改,或者通过请求获取,您应该使用$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);
        }
    });
}]);
Run Code Online (Sandbox Code Playgroud)

这是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>
Run Code Online (Sandbox Code Playgroud)

请注意"=",如果使用该$observe函数,则不应将变量设置为范围.此外,我发现它将对象作为字符串传递,因此如果您传递对象,请使用解决方案#2scope.$watch(attrs.yourDirective, fn)(如果您的变量未更改,则使用#3).


解决方案#2


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

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;
    });
}]);
Run Code Online (Sandbox Code Playgroud)

这是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>
Run Code Online (Sandbox Code Playgroud)

解决方案#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);
        }
    });
}]);
Run Code Online (Sandbox Code Playgroud)

这是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>
Run Code Online (Sandbox Code Playgroud)

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

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

感兴趣的是:这是关于角度生命周期的文章