在工作中遇到了一个需求 —— 使用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对象关联起来,最终实现双向绑定。