如何在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>");
});
}
};
});
Josh David Miller的解决方案: http://jsfiddle.net/paulocoelho/fBjbP/2/ < / p >
176063 次浏览

这里有很多无意义的jQuery,但是$compile服务在这里实际上是超级简单的:

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

您会注意到,为了遵循一些最佳实践,我也重构了您的指令。如果你有任何问题,请告诉我。

在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 );

所以,我必须找到一种方法来调用指令“链接”函数。要获得隐藏在闭包深处的有用方法是非常困难的。

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)

现在,它工作得很好。

除了完善Riceball LEE添加一个新的element-directive的例子

newElement = $compile("<div my-directive='n'></div>")($scope)
$element.parent().append(newElement)

向现有元素添加一个新的attribute-directive可以通过以下方式完成:

假设你希望动态地将my-directive添加到span元素中。

template: '<div>Hello <span>World</span></div>'


link: ($scope, $element, $attrs) ->


span = $element.find('span').clone()
span.attr('my-directive', 'my-directive')
span = $compile(span)($scope)
$element.find('span').replaceWith span

希望这能有所帮助。

function addAttr(scope, el, attrName, attrValue) {
el.replaceWith($compile(el.clone().attr(attrName, attrValue))(scope));
}

Josh David Miller说得对。

如果你想知道$compile在幕后做什么,以及HTML输出是如何从指令生成的,请看看下面

$compile服务编译包含指令("test"作为元素)的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 < / p >

如果你试图动态添加一个使用内联template的指令,Josh David Miller给出的接受答案非常有用。然而,如果你的指令利用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);
}
}
}
}]);

从之前的许多答案中受到启发,我提出了以下“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