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?
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();
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')
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.
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 $watch
en, 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
});
}
}
});
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()]);
});
}
};
})