我想在使用AngularJs和UI Bootstrap的动态生成的标签页的内容中使用ng-include。
我这里有一个Plunker: http://plnkr.co/edit/2mpbovsu2eDrUdu8t7SM?p=preview
angular.module('core').controller('HeaderForProductDetailsController', ['$scope'
function($scope) {
$scope.somevalue = 'Some test string'; //this does not bind to template, yet console.log() will output it just fine.
}
]);
JS代码:
<div id="mainCntr" style="padding: 20px;">
<uib-tabset>
<uib-tab ng-repeat="tab in tabs" active="tab.active" disable="tab.disabled">
<uib-tab-heading>
{{tab.title}} <i class="glyphicon glyphicon-remove-sign" ng-click="removeTab($index)"></i>
</uib-tab-heading>
{{tab.content}}
</uib-tab>
</uib-tabset>
</div>
在Plunker中,点击&#34;添加标签&#34;按钮。它调用$ scope中的一个函数,它将一个新选项卡推送到集合,但传入一些包含ng-include指令的动态生成的内容。预期的输出是ng-include将显示在选项卡内容区域内。
由于
答案 0 :(得分:4)
在您的Plunker中,您正在使用ng-bind-html
,它不会为您编译HTML。您可以创建一个为您执行此操作的新指令。
ng-bind-html
的源代码:
var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
return {
restrict: 'A',
compile: function ngBindHtmlCompile(tElement, tAttrs) {
var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
return (value || '').toString();
});
$compile.$$addBindingClass(tElement);
return function ngBindHtmlLink(scope, element, attr) {
$compile.$$addBindingInfo(element, attr.ngBindHtml);
scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
// we re-evaluate the expr because we want a TrustedValueHolderType
// for $sce, not a string
element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
});
};
}
};
}];
为新指令选择一个名称,例如compile-html
。
将tAttrs.ngBindHtml
替换为tAttrs.compileHtml
(或您选择的任何名称)。
您需要将$sce.getTrustedHtml
替换为$sce.trustAsHtml
,否则您将获得Error: [$sce:unsafe] Attempting to use an unsafe value in a safe context.
然后你需要拨打$compile
:
$compile(element.contents())(scope);
完整指令:
app.directive('compileHtml', ['$sce', '$parse', '$compile',
function($sce, $parse, $compile) {
return {
restrict: 'A',
compile: function ngBindHtmlCompile(tElement, tAttrs) {
var ngBindHtmlGetter = $parse(tAttrs.compileHtml);
var ngBindHtmlWatch = $parse(tAttrs.compileHtml, function getStringValue(value) {
return (value || '').toString();
});
$compile.$$addBindingClass(tElement);
return function ngBindHtmlLink(scope, element, attr) {
$compile.$$addBindingInfo(element, attr.compileHtml);
scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
element.html($sce.trustAsHtml(ngBindHtmlGetter(scope)) || '');
$compile(element.contents())(scope);
});
};
}
};
}
]);
用法:
<div compile-html="tab.content"></div>
答案 1 :(得分:1)
我的情况可能不那么复杂,所以这个简单的解决方案有效:
sdo.tabs:{
data:[],
active:0,
reset: function(){
var tabs = this.data;
while( tabs.length > 0 ) {
this.removeTab( tabs[tabs.length-1].child.name);
}
this.active = 0;
},
childExists: function( childName ) {
var fromTheTop = this.data.length,
parentName = ( this.active > 0 ? this.data[ this.active - 1 ].child.name : 'zero' );
while( fromTheTop > this.active ) {
var child = this.data[ fromTheTop-1 ].child;
if( child && child.parent === parentName && child.name === childName ) return fromTheTop;
fromTheTop--;
}
return false;
},
removeTab: function( name ) { // will remove any descendents of this tab as well, see recursive call near end
var fromTheTop = this.data.length;
while( fromTheTop > 0 ) {
var tab = this.data[fromTheTop - 1];
if( tab.child.name === name ) {
angular.element( '#'+name ).empty();
this.data.splice( fromTheTop - 1);
return;
}
if( tab.child.parent === name) this.removeTab( tab.child.name );
fromTheTop--;
};
},
/*
* tab is string identifies tab but doesn't show in the UI
* tempmlate is HTML template
* scope is used to compile template
* title is string or function for UI tab title, appears in the tab row
*/
create: function( tab, template, scope, title ) {
var childName = tab;
var tabs = this.data;
tab = this.childExists( childName );
if( tab === false ) {
tab = tabs.length + 1;
} else { // recycling a tab, kill it & its descendents
this.removeTab( childName );
}
tabs[tab-1] = {
title:function(){
if( angular.isFunction(title) ) return title();
return title;
},
child: {
parent:( this.active > 0 ? this.data[ this.active - 1 ].child.name : 'zero' ),
name:childName
}
};
var ct = $timeout( function() {
angular.element( '#'+tabs[tab-1].child.name ).html( $compile( template )( scope ) );
sdo.tabs.active = tab;
return; // return nothing to avoid memory leak
});
scope.$on('$destroy', function() {
$timeout.cancel( ct );
});
return ct; // ct is a promise
}
}
HTML
<uib-tabset active="tabs.active">
<uib-tab index='0' heading="{{title}}">
<ng-view></ng-view>
</uib-tab>
<uib-tab ng-repeat="tab in tabs.data track by tab.child.name" heading="{{tab.title()}}" index='$index+1' >
<div id="{{tab.child.name}}"></div>
</uib-tab>
</uib-tabset>
在我的情况下,第一个选项卡由Angular路由器填充,这就是选项卡数组是tabs.active