如何通过自定义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; } }); } }; } }; });
代码和规格是一个要点