- 使用 $compile 服务编译您动态加载的 html 内容,同时将其绑定到作用域。
- 建议你做一个指令。您可以使用属性传入部分的 url。
特别是指令的链接属性是这样的:
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function(html) {
ele.html(html);
$compile(ele.contents())(scope);
});
}
详见answer to this question,它提供了一个plunker demo。
希望这会有所帮助。
编辑
我想写更多来回应@Víťa Plšek - angular.cz 的回答。
我曾经做过更动态的事情,就是在partial中加载javacsript!
曾几何时,我基于angularjs做了一个单页应用。每个菜单功能都是使用 ajax 动态加载的部分。当然,每个菜单功能都是一个单独的角度控制器。为了使代码更易于管理,我没有将所有控制器的代码合并到一个文件中,而是从 index.html 中一次性加载它们。相反,我让每个部分使用自定义指令指定其自己的控制器的 js 代码并进行延迟加载。
所以单页应用程序的主页使用自定义指令来包含动态加载的部分:
<body>
...
<dynamic-partial src={{selected_partial_url}}>
</dynamic-partial>
...
</body>
,而每个部分都存储在一个单独的 html 文件中。它的内容是这样的:
<lazy-load-script src="js/controllers/dynamic-controller1.js" >
</lazy-load-script>
<div ng-controller="DynamicController1">
...
</div>
现在,有一个问题:如果我们一次编译部分文件,会出现一个错误,说DynamicController1 没有定义。是真的。我们必须先加载dynamic-controller1.js,然后在js文件加载完成后编译<div ng-controller="DynamicController1"></div>部分。
所以指令DynamicPartial的代码是这样的:
"use strict";
angular.module('MyApp')
.directive('DynamicPartial', [ "$compile", function( $compile ) {
return {
restrict: 'E',
scope: {
src: '@'
},
link: function (scope, element, attr) {
console.log( "Linking web-terminal. src = " + scope.src );
scope.onLazyLoadDone = function(){
// compile the other html elements in the partial, and put them in <dynamic-partial> element.
element.html( $compile( scope.other_elements_html )(scope) );
}
attr.$observe( 'src', function( value ){ // fetch new partial as soon as 'src' attribute changes:
console.log( "'src' attribute changed. Fetching new partial: " + value );
if( "" == scope.src ) {
element.addClass("ng-hide");
return;
}
else
element.removeClass("ng-hide");
$.ajax({
dataType: 'text',
timeout: 5000,
url: scope.src
})
.done(function (data) {
console.log( "Successfully fetched terminal file, length = " + data.length);
// compile the <lazy-load-script> tag first:
var lazy_load_element = $('<div/>').append( $(data)).find( "lazy-load-script, [lazy-load-script]" );
if( lazy_load_element.length > 0 ) { // lazy-load-script element found:
// Here we pragmatically set the "on-loaded" attribute for the <lazy-load-script> element found in the loaded partial, so that we can get called when the javascript file specified by <lazy-load-script> element finishes loading.
lazy_load_element.attr("on-loaded", "onLazyLoadDone()");
$compile($('<div/>').append(lazy_load_element).html())(scope);
}
// Save the remaining DOM elements in the partial, which will be compiled after the lazy-load is done.
scope.other_elements_html = $('<div/>').append( $(data).filter(':not([lazy-load],lazy-load)')).html();
if( 0 == lazy_load_element.length )
scope.onLazyLoadDone();
})
.fail(function (jqXHR, textStatus, errorThrown) {
console.error("Failed fetching menu from server: " + errorThrown.message);
});
});
if( undefined == scope.src || 'not defined' == scope.src ) {
return;
}
}
};
}]);
<lazy-load-script>的代码如下。关键是使用onLoaded 范围属性来指定对父控制器的回调。
"use strict";
angular.module('SyncreonApp')
.directive('lazyLoad', [ "$ocLazyLoad", function( $ocLazyLoad ) {
return {
restrict: 'EA',
scope: {
src: '@',
onLoaded: '&'
},
link: function (scope, element, attr) {
//console.log( "Linking lazyLoadScript, url to load = " + scope.src );
if( undefined != scope.src && '' != scope.src ){
$ocLazyLoad.load( scope.$parent.$parent.getBasePath() + scope.src )
.then(function () {
//Javascript lazy load done, calling back to parent controller, so that parent will continue with compiling other parts of the partial.
scope.onLoaded();
});
}
else
console.error( "Illegal src attribute in directive lazyLoad");
}
};
}]);