webentwicklung-frage-antwort-db.com.de

Wie kann eine öffentliche API aus einer Direktive verfügbar gemacht werden, die eine wiederverwendbare Komponente ist?

Wenn Sie über eine Anweisung in eckiger Form verfügen, die eine wiederverwendbare Komponente ist, wie empfiehlt es sich, eine öffentliche API verfügbar zu machen, auf die vom Controller aus zugegriffen werden kann? Wenn es mehrere Instanzen der Komponente gibt, können Sie über den Controller zugreifen

angular.directive('extLabel', function {
    return {
        scope: {
            name: '@',
            configObj: '='
        },
        link: function(scope, iElement, iAttrs) {
            // this could be and exposed method
            scope.changeLabel = function(newLabel) {
                scope.configObj.label = newLabel;
            }
        }
    }
});

Dann wenn:

<ext-label name="extlabel1" config-obj="label1"></ext-label>
<ext-label name="extlabel2" config-obj="label2"></ext-label>
<ext-label name="extlabel3" config-obj="label3"></ext-label>

Wie erhalte ich den Zugriff auf das scope.changeLabel von extLabel2 in einem Controller?

Macht das Sinn?

35
Safajirafa

Geht das für dich?

angular.directive('extLabel', function() {
    return {
        restrict: 'E',
        scope: {
            api: '='
        },
        link: function(scope, iElement, iAttrs) {
            scope.api = {
                    doSomething: function() { },
                    doMore: function() { }
                };
        }
    };
});

Aus dem Elternteil

<ext:label api="myCoolApi"></ext:label>

Und im Controller

$scope.myCoolApi.doSomething();
$scope.myCoolApi.doMore();
22
Andrej Kaurin

Ich mag Andrejs und verwende dieses Muster regelmäßig, möchte aber einige Änderungen vorschlagen

angular.directive('extLabel', function {
    return {
        scope: {
            api: '=?',
            configObj: '='
        },
        // A controller, and not a link function. From my understanding, 
        // try to use the link function for things that require post link actions 
        // (for example DOM manipulation on the directive)
        controller: ['$scope', function($scope) {

          // Assign the api just once
          $scope.api = {
            changeLabel: changeLabel
          };

          function changeLabel = function(newLabel) {
            $scope.configObj.label = newLabel;
          }
        }]
    }
});



<ext-label name="extlabel1" config-obj="label1"></ext-label>
<ext-label api="label2api" name="extlabel2" config-obj="label2"></ext-label>
<ext-label name="extlabel3" config-obj="label3"></ext-label>

Im Controller natürlich label2api.changeLabel('label')

6
Vall3y

Dieses Problem hatte ich beim Schreiben einer Direktive zur Instanziierung eines dygraph / chart in meinen Angular -Anwendungen. Obwohl der Großteil der Arbeit durch Datenbindung erledigt werden kann, benötigen einige Teile der API Zugriff auf das Dygraph-Objekt selbst. Ich habe es durch $emit()ing einer Veranstaltung gelöst:

'use strict';
angular.module('dygraphs', []);

angular.module('dygraphs').directive('mrhDygraph', function ($parse, $q) {
    return {
        restrict: 'A',
        replace: true,
        scope: {data: '=', initialOptions: '@', options: '='},
        link: function (scope, element, attrs) {
            var dataArrived = $q.defer();
            dataArrived.promise.then(function (graphData) {
                scope.graph = new Dygraph(element[0], graphData, $parse(scope.initialOptions)(scope.$parent));
                return graphData.length - 1;
            }).then(function(lastPoint) {
                scope.graph.setSelection(lastPoint);
                scope.$emit('dygraphCreated', element[0].id, scope.graph);
            });
            var removeInitialDataWatch = scope.$watch('data', function (newValue, oldValue, scope) {
                if ((newValue !== oldValue) && (newValue.length > 0)) {
                    dataArrived.resolve(newValue);
                    removeInitialDataWatch();
                    scope.$watch('data', function (newValue, oldValue, scope) {
                        if ((newValue !== oldValue) && (newValue.length > 0)) {
                            var selection = scope.graph.getSelection();
                            if (selection > 0) {
                                scope.graph.clearSelection(selection);
                            }
                            scope.graph.updateOptions({'file': newValue});
                            if ((selection >= 0) && (selection < newValue.length)) {
                                scope.graph.setSelection(selection);
                            }
                        }
                    }, true);
                    scope.$watch('options', function (newValue, oldValue, scope) {
                        if (newValue !== undefined) {
                            scope.graph.updateOptions(newValue);
                        }
                    }, true);
                }
            }, true);
        }
    };
});

Zu den Parametern des dygraphCreated-Ereignisses gehören die Element-ID sowie das Dygraph-Objekt, sodass mehrere Dygraphs innerhalb desselben Bereichs verwendet werden können.

5
Max

Meiner Meinung nach sollte ein Elternteil keinen Kinderbereich haben. Woher wissen Sie, welche Sie verwenden und welche nicht. Ein Controller sollte nur auf seinen eigenen Bereich oder seine übergeordneten Bereiche zugreifen. Es bricht sonst die Kapselung.

Wenn Sie Ihr Label ändern möchten, müssen Sie lediglich den Variablenwert label1/label2/label3 ändern. Wenn die Datenbindung aktiviert ist, sollte es funktionieren. Innerhalb Ihrer Direktive können Sie $watchen, wenn Sie bei jeder Änderung etwas Logik benötigen.

angular.directive('extLabel', function {
    return {
        scope: {
            name: '@',
            configObj: '='
        },
        link: function(scope, iElement, iAttrs) {
            scope.$watch("configObj", function() {
                // Do whatever you need to do when it changes
            });
        }
    }  
});
2
Benoit Tremblay

Verwenden Sie diese Anweisungen für das Element, das Sie vor und nach dem nächsten Element verwenden möchten:

<carousel>
 <slide>
   <button class="action" carousel-next> Next </button>
   <button class="action" carousel-prev> Back </button>
 </slide>
</carousel>

.directive('carouselNext', function () {
       return {
        restrict: 'A',
        scope: {},
        require: ['^carousel'],
        link: function (scope, element, attrs, controllers) {
            var carousel = controllers[0];
            function howIsNext() {
                if ((carousel.indexOfSlide(carousel.currentSlide) + 1) === carousel.slides.length) {
                    return 0;
                } else {
                    return carousel.indexOfSlide(carousel.currentSlide) + 1;
                }
            }
            element.bind('click', function () {
                carousel.select(carousel.slides[howIsNext()]);
            });
        }
    };
})

.directive('carouselPrev', function () {
    return {
        restrict: 'A',
        scope: {},
        require: ['^carousel'],
        link: function (scope, element, attrs, controllers) {
            var carousel = controllers[0];
            function howIsPrev() {
                if (carousel.indexOfSlide(carousel.currentSlide) === 0) {
                    return carousel.slides.length;
                } else {
                    return carousel.indexOfSlide(carousel.currentSlide) - 1;
                }
            }
            element.bind('click', function () {
                carousel.select(carousel.slides[howIsPrev()]);
            });
        }
    };
})