如何通过自定义Angular指令有条件地应用模板?

DEMO

考虑下面的指令:

angular.module('MyApp').directive('maybeLink', function() { return { replace: true, scope: { maybeLink: '=', maybeLinkText: '=' }, template: '<span>' + ' <span ng-hide="maybeLink" ng-bind-html="text"></span>' + ' <a ng-show="maybeLink" href="#" ng-bind-html="text"></a>' + '</span>', controller: function($scope) { $scope.text = $scope.maybeLinkText.replace(/\n/g, '<br>'); } }; }); 

该指令将<span><a>到DOM(一次只能看到一个)。

我怎样才能重写指令,使它将<span> DOM <span><a>到DOM,但不是两个?


UPDATE

好吧,我想我可以用ng-if这样的话:

 template: '<span>' + ' <span ng-if="!maybeLink" ng-bind-html="text"></span>' + ' <a ng-if="maybeLink" href="#" ng-bind-html="text"></a>' + '</span>' 

但是,在这种情况下,怎么能摆脱周围?


更新2

这里是使用$compile的指令的一个版本。 它没有周围的<span> ,但双向数据绑定也不起作用。 我真的很想知道如何解决双向数据绑定问题。 有任何想法吗?

DEMO

 angular.module('MyApp').directive('maybeLink', function($compile) { return { scope: { maybeLink: '=', maybeLinkText: '=' }, link: function(scope, element, attrs) { scope.text = scope.maybeLinkText.replace(/\n/g, '<br>'); if (scope.maybeLink) { element.replaceWith($compile('<a href="#" ng-bind-html="text"></a>')(scope)); } else { element.replaceWith($compile('<span ng-bind-html="text"></span>')(scope)); } } }; }); 

您可能可以使用template function 。 根据文件 :

您可以将模板指定为表示模板的string,也可以将其指定为具有两个参数tElement和tAttrs(在下面的编译函数api中描述)的函数,并返回表示模板的string值


 function resolveTemplate(tElement, tAttrs) { } angular.module('MyApp').directive('maybeLink', function() { return { //... template: resolveTemplate, //... }; }); 

我认为这是注入基于范围属性的dynamic模板的最干净的方式

 angular.module('app') .directive('dynamic-template', function () { return { template:'<ng-include src="template"/>', restrict: 'E', link: function postLink(scope) { scope.template = 'views/dynamic-'+scope.type+'.html'; } }; }) 

最后我提出了以下版本:

 angular.module('MyApp').directive('maybeLink', function($compile) { return { scope: { maybeLink: '=', maybeLinkText: '=' }, link: function(scope, element, attrs) { scope.$watch('maybeLinkText', function(newText) { scope.text = newText.replace(/\n/g, '<br>'); }); scope.$watch('maybeLink', function() { var newElement; if (scope.maybeLink) { newElement = $compile('<a href="#" ng-bind-html="text"></a>')(scope); } else { newElement = $compile('<span ng-bind-html="text"></span>')(scope); } element.replaceWith(newElement); // Replace the DOM element = newElement; // Replace the 'element' reference }); } }; }); 

我会用ng-switch

就像是

  template: '<span ng-switch on="maybeLink">' + ' <span ng-switch-when="http://www.yahoo.com" ng-bind-html="text"></span>' + ' <a ng-switch-when="http://google.com" href="#" ng-bind-html="text"></a>' + '</span>', 

要么

  template: '<span ng-switch on="maybeLink">' + ' <span ng-switch-when={{maybeLink.length == 0}} ng-bind-html="text"></span>' + ' <a ng-switch-when={{maybeLink.length > 0}} href="#" ng-bind-html="text"></a>' + '</span>', 

所以这是方向

Plunker

你可以使用ng-if来代替

以下是工作示例

工作演示

指令代码:

 angular.module('MyApp').directive('maybeLink', function() { return { replace: true, scope: { maybeLink: '=', maybeLinkText: '=' }, template: '<span>' + ' <span ng-if="!maybeLink.link" ng-bind-html="text"></span>' + ' <a ng-if="maybeLink.link" href="#" ng-bind-html="text"></a>' + '</span>', controller: function($scope) { $scope.text = $scope.maybeLinkText.replace(/\n/g, '<br>'); } }; }); 

以下是提供dynamic更新的解决scheme。 用法:

<a rewrite-as-span="true"></a>

<a rewrite-as-span="false"></a>

<a rewrite-as-span="yourFn()"></a>

等等

 app.directive('rewriteAsSpan', function($compile){ return { restrict: 'A', template: '<span />', replace: true, // we transclude the element because when it gets replaced with the span // we want all the properties from the original element transclude: 'element', compile: function(tElement, tAttrs){ return { post: function(scope, element, attrs, controller, transclude){ var rewrittenEl, originalEl; transclude(scope, function(clone){ originalEl = clone; }); scope.$watch(attrs.rewriteAsSpan, function(value){ if (value === undefined || value === true){ if (!rewrittenEl){ // lazy compile and cache the rewritten element transclude(scope, function(clone){ rewrittenEl = tElement; rewrittenEl.html(clone.html()); // remove this directive because the $compile would get infinite rewrittenEl.removeAttr('rewrite-as-span'); $compile(rewrittenEl)(scope); }); } element.replaceWith(rewrittenEl); element = rewrittenEl; } else { element.replaceWith(originalEl); element = originalEl; } }); } }; } }; }); 

代码和规格是一个要点