web-dev-qa-db-ger.com

Die einfachste Möglichkeit, eine AngularJS-Bereichsvariable von der Direktive an den Controller zu übergeben?

Wie kann eine AngularJS-Bereichsvariable am einfachsten von der Direktive an den Controller übergeben werden? Alle Beispiele, die ich gesehen habe, scheinen so komplex zu sein, gibt es nicht eine Möglichkeit, über eine Direktive auf einen Controller zuzugreifen und eine seiner Bereichsvariablen festzulegen?

98
winduptoy

Bearbeitet am 25.08.2014: hier hier habe ich gegabelt.

Vielen Dank @anvarik.

Hier ist die JSFiddle . Ich habe vergessen, wo ich das gegabelt habe. Dies ist jedoch ein gutes Beispiel, das Ihnen den Unterschied zwischen = und @ zeigt.

<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;
        }
    }]);
150
maxisam

Warten Sie, bis angular die Variable ausgewertet hat

Ich habe viel damit herumgespielt und konnte es nicht zum Laufen bringen, auch nicht mit der Variablen, die mit "=" Im Gültigkeitsbereich definiert wurde. Hier sind drei Lösungen, die von Ihrer Situation abhängen.


Lösung Nr. 1


Ich fand , dass die Variable nicht von angular noch ausgewertet wurde, als sie an die Direktive übergeben wurde. Dies bedeutet, dass Sie Sie können darauf zugreifen und es in der Vorlage verwenden, jedoch nicht innerhalb der Link- oder App-Controller-Funktion, es sei denn, wir warten auf die Auswertung.

Wenn sich Ihre Variable ändert oder durch eine Anfrage abgerufen wird, sollten Sie $observe oder - verwenden. $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);
        }
    });
}]);

Und hier ist der HTML-Code (denken Sie an die Klammern!):

<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>

Beachten Sie, dass Sie die Variable im Gültigkeitsbereich nicht auf "=" Setzen sollten, wenn Sie die Funktion $observe verwenden. Außerdem habe ich festgestellt, dass Objekte als Zeichenfolgen übergeben werden. Wenn Sie also Objekte übergeben, verwenden Sie Lösung 2 oder scope.$watch(attrs.yourDirective, fn) (, oder # 3 , wenn sich Ihre Variable nicht ändert).


Lösung Nr. 2


Wenn Ihre Variable in z. ein anderer Controller , muss aber nur warten, bis angular ausgewertet hat, bevor es an den App-Controller gesendet wird, wir können $timeout um zu warten, bis der $apply ausgeführt wurde. Außerdem müssen wir $emit verwenden, um ihn an den übergeordneten App-Controller zu senden (aufgrund der Isolation) Geltungsbereich der Richtlinie):

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

Und hier ist der HTML-Code (keine Klammern!):

<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>

Lösung Nr. 3


Wenn sich Ihre Variable nicht ändert und Sie sie in Ihrer Direktive auswerten müssen, können Sie $eval Verwenden = Funktion:

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

Und hier ist der HTML-Code (denken Sie an die Klammern!):

<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>

Schauen Sie sich auch diese Antwort an: https://stackoverflow.com/a/12372494/1008519

Referenz für das FOUC-Problem (Flash mit nicht gestylten Inhalten): http://deansofer.com/posts/view/14/AngularJs-Tips-and-Tricks-UPDATED

Für die Interessierten: hier ist ein Artikel über den angular Lebenszyklus

70
mlunoe