在工作中遇到了一个需求 —— 使用angular在一个页面中,要求点击左侧菜单显示的页面需要以tab(选项卡)的形式展现到页面中,这样方便用户使用不同的功能能来回切换。与ext tab选项卡的效果一致。
由于前期选型,使用的是angular技术作为前端的框架,如果使用ui-router的方式,这样不满足需求,因为内容会被重置,不能保留之前用户的操作,所以必须考虑其他的解决办法。
最后,找到了 ng-include 指令,异步加载HTML代码,这样才能将用户的操作保留在浏览器中。
代码如下:
<ng-include src="'../template/common/orderList.html'" ng-controller="orderListController"></ng-include>
/**
* 创建了一个indexController
*/
angular.module("klwkOmsApp")
.controller("orderListController", ["$scope", "$rootScope", "$state", "WAP_CONFIG",
function ($scope, $rootScope, $state, WAP_CONFIG) {
function init() {
//加载下拉框
$('#orderList').selectPlug();
//点击高级搜索展开
$('.advancedSearchBtn').click(function () {
$('#simpleSearch').hide();
$('#advancedSearch').slideDown(500);
});
//点击取消 高级搜索收起
$('.advancedSearchCancelBtn').click(function () {
$('#simpleSearch').show();
$('#advancedSearch').slideUp(200);
});
//制单时间展开收起
$('.timeSpreadBtn').click(function () {
if($(this).html()==='展开'){
$('.timeSpread').slideDown(100);
$(this).html('收起');
$('.hide1').hide();
$('.hide2').css('display','inline-block');
}else{
$('.timeSpread').slideUp(100);
$(this).html('展开');
$('.hide1').show();
$('.hide2').hide();
}
})
}
init();
}]);
1、src 是引入文件的地址,如果有单引号,表示是字符串,如果没有引号,表示是变量,
注意:路径是相对于文件本身,不是模板的路径。
2、ng-controller 表示引入的控制器的名字.
只需要在模块化中引入该控制器即可。
上面这种方式如果是第一次刷新加载就没有什么问题,但是,如果我是页面加载完之后异步加载HTML代码,页面就会报错,在是因为 compile会对HTML代码进行编译,将指令转为浏览器认识的HTML代码,但是代码转义完了之后还没有将代码放到DOM树种,然后controller会对DOM树做相关的事件绑定,例如绑定事件等,一旦找不相关的DOM节点,就有可能报错,导致controller执行不成功,无法完成双向绑定。
下面这个例子是对上面问题解决办法:
/**
* 创建了一个indexController
* */
angular.module("klwkOmsApp")
.controller('publicController', ["$scope","$rootScope","$state","WAP_CONFIG","$compile",
function($scope,$rootScope, $state, WAP_CONFIG,$compile) {
var stateController = {
'index.orderList':{
url: '/orderList',
templateUrl:'../template/orderManage/orderList.html',
controller: "orderListController"
},
'index.allocationNoticeBill':{
url: '/allocationNoticeBill',
templateUrl:'../template/orderManage/allocationNoticeBill.html',
controller: "allocationNoticeBillController"
}
};
$scope.topTabs = {};
// 添加 tab 面板
$scope.addTabPanel = function(uiSref){
// 添加 tab 导航
if($scope.topTabs[uiSref] === undefined){
$scope.topTabs[uiSref] = uiSref;
var el=$compile('<ng-include id="'+uiSref+'_panel" src="\''+stateController[uiSref].templateUrl+'\'" onload="loadController(\''+uiSref+'\')" ></ng-include>')($scope);
$("#topTabPanel").append(el);
console.dir(el);
}
};
// ng-include 代码加载完毕之后执行的代码
$scope.loadController = function(uiSref){
console.log("loadController : " + uiSref);
$compile('<div ng-controller="allocationNoticeBillController">'+$("#"+uiSref+"_panel").contents()+'</div>')($scope.$new());
}
}
]);
代码说明:
1、使用ng-clude 先引用 src文件,页面加载进来之后,执行onload方法
2、onload 方法将编译之后的 html包裹在 一个有ng-controller指令的div中,代码如下
<div ng-controller="allocationNoticeBillController">include编译之后的代码</div>
上面这种方式非常的繁琐,逻辑也复杂,不便于理解,最后和同事讨论,找到了一个简单的解决办法
在ng-include的目标页面中最外层添加一个div,这个div 中有ng-controller标签 。
<!doctype html>
<html ng-app="HelloAngular">
<head>
<meta charset="utf-8">
</head>
<body>
<div ng-controller="helloNgCtrl">
<p>{{greeting.text}},Angular</p>
<button ng-click="addFile()">动态添加文件</button>
<div id="newFileContent">
<div ng-include="'file1.html'"></div>
</div>
</div>
</body>
<script src="js/angular-1.3.0.js"></script>
<script src="NgModule1.js"></script>
</html>
var helloModule=angular.module('HelloAngular', []);
helloModule.controller('helloNgCtrl', ['$scope', function($scope){
$scope.greeting = {
text: 'Hello'
};
$scope.addFile = function(){
}
}]);
helloModule.controller('newFile', ['$scope', function($scope){
$scope.username = "huangbiao";
$scope.newFunc = function(){
alert(this.username);
};
}]);
备注:html不能有body标签,否则controller执行不成功,原因还没有深入了解,现象如此。
了解angular的双向绑定的步骤:
1、先用$compile服务 将HTML编译成目标HTML
2、然后执行指令的 link函数,将目标HTML 与 $scope对象关联起来,最终实现双向绑定。