Как я могу динамически добавить директиву в AngularJS?
у меня есть очень урезанная версия того, что я делаю, которая решает проблему.
у меня простой directive. Всякий раз, когда вы нажимаете на элемент, он добавляет еще один. Однако сначала он должен быть скомпилирован, чтобы правильно его отобразить.
мои исследования привели меня к $compile. Но все примеры используют сложную структуру, которую я действительно не знаю, как применить здесь.
скрипки здесь: http://jsfiddle.net/paulocoelho/fBjbP/1/
и JS здесь:
var module = angular.module('testApp', [])
.directive('test', function () {
return {
restrict: 'E',
template: '<p>{{text}}</p>',
scope: {
text: '@text'
},
link:function(scope,element){
$( element ).click(function(){
// TODO: This does not do what it's supposed to :(
$(this).parent().append("<test text='n'></test>");
});
}
};
});
решение Джоша Дэвида Миллера:
http://jsfiddle.net/paulocoelho/fBjbP/2/
7 ответов:
У вас есть много бессмысленных jQuery там, но $ compile service на самом деле супер просто в этом случае:
.directive( 'test', function ( $compile ) { return { restrict: 'E', scope: { text: '@' }, template: '<p ng-click="add()">{{text}}</p>', controller: function ( $scope, $element ) { $scope.add = function () { var el = $compile( "<test text='n'></test>" )( $scope ); $element.parent().append( el ); }; } }; });вы заметите, что я также изменил вашу директиву, чтобы следовать некоторым лучшим практикам. Дайте мне знать, если у вас есть вопросы по любому из них.
в дополнение к идеальному примеру Riceball LEE добавления нового элемент-директива
newElement = $compile("<div my-directive='n'></div>")($scope) $element.parent().append(newElement)добавление нового
динамическое добавление директив на angularjs имеет два стиля:
добавьте директиву angularjs в другую директиву
- вставка нового элемента (директивы)
- вставка нового атрибута (директивы) в элемент
вставка нового элемента (директивы)
это просто. И вы можете использовать в "link"или " compile".
var newElement = $compile( "<div my-diretive='n'></div>" )( $scope ); $element.parent().append( newElement );вставка нового атрибута в элемент
это трудно, и сделать меня головная боль в течение двух дней.
использование "$compile " вызовет критическую рекурсивную ошибку!! Возможно, он должен игнорировать текущую директиву при повторной компиляции элемента.
$element.$set("myDirective", "expression"); var newElement = $compile( $element )( $scope ); // critical recursive error. var newElement = angular.copy(element); // the same error too. $element.replaceWith( newElement );Итак, я должен найти способ вызвать функцию директивы "link". Очень трудно получить полезные методы, которые скрыты глубоко внутри закрытия.
compile: (tElement, tAttrs, transclude) -> links = [] myDirectiveLink = $injector.get('myDirective'+'Directive')[0] #this is the way links.push myDirectiveLink myAnotherDirectiveLink = ($scope, $element, attrs) -> #.... links.push myAnotherDirectiveLink return (scope, elm, attrs, ctrl) -> for link in links link(scope, elm, attrs, ctrl)Теперь, это хорошо работает.
function addAttr(scope, el, attrName, attrValue) { el.replaceWith($compile(el.clone().attr(attrName, attrValue))(scope)); }
принятый ответ Джоша Дэвида Миллера отлично работает, если вы пытаетесь динамически добавить директиву, которая использует встроенный
template. Однако, если ваша директива используетtemplateUrlего ответ не будет работать. Вот что сработало для меня:.directive('helperModal', [, "$compile", "$timeout", function ($compile, $timeout) { return { restrict: 'E', replace: true, scope: {}, templateUrl: "app/views/modal.html", link: function (scope, element, attrs) { scope.modalTitle = attrs.modaltitle; scope.modalContentDirective = attrs.modalcontentdirective; }, controller: function ($scope, $element, $attrs) { if ($attrs.modalcontentdirective != undefined && $attrs.modalcontentdirective != '') { var el = $compile($attrs.modalcontentdirective)($scope); $timeout(function () { $scope.$digest(); $element.find('.modal-body').append(el); }, 0); } } } }]);
Джош Дэвид Миллер прав.
PCoelho, в случае, если вы задаетесь вопросом, что
$compileделает за кулисами и как вывод HTML генерируется из директивы, пожалуйста, посмотрите нижеThe
$compileсервис компилирует фрагмент HTML("< test text='n' >< / test >"), который включает директиву("тест" как элемент) и создает функцию. Затем эта функция может быть выполнена с областью видимости, чтобы получить "вывод HTML из директивы".var compileFunction = $compile("< test text='n' > < / test >"); var HtmlOutputFromDirective = compileFunction($scope);подробнее с здесь примеры кода : http://www.learn-angularjs-apps-projects.com/AngularJs/dynamically-add-directives-in-angularjs
вдохновленный многими из предыдущих ответов, я придумал следующую директиву "stroman", которая заменит себя любыми другими директивами.
app.directive('stroman', function($compile) { return { link: function(scope, el, attrName) { var newElem = angular.element('<div></div>'); // Copying all of the attributes for (let prop in attrName.$attr) { newElem.attr(prop, attrName[prop]); } el.replaceWith($compile(newElem)(scope)); // Replacing } }; });важно: зарегистрируйте директивы, которые вы хотите использовать с
restrict: 'C'. Вот так:app.directive('my-directive', function() { return { restrict: 'C', template: 'Hi there', }; });вы можете использовать такой:
<stroman class="my-directive other-class" randomProperty="8"></stroman>для этого:
<div class="my-directive other-class" randomProperty="8">Hi there</div>Protip. если вы не хотите использовать директивы, основанные на классах, то вы можете изменить
'<div></div>'Для что-то, что вам нравится. Например, есть фиксированный атрибут, который содержит имя желаемой директивы вместоclass.
Comments