在这个angularjs的项目里,我把controller分类两类,一个是页面级别的controller,一个是对话框级别的controller。页面级别的controller就是用户直接点菜单,路由到某个页面,需要用到的。对话框级别的就是在页面中使用bootstrap对话框组件需要的controller。
页面级别controller
define(['require','angular','modules/hardware/disk/disk.service','modules/alert/alert/list/list.service'],function (require,ng){ var module = ng.module('app.hardware.disk'); module.controller('DiskDetailCtrl',DiskDetailCtrl); function DiskDetailCtrl($scope,$interval,$filter,$mdDialog,modalUtils,chartUtils,diskSrv,alertListSrv){ $scope.vm = {}; activate(); function activate(){ } } DiskDetailCtrl.$inject = ['$scope','$interval','$filter','$mdDialog','modalUtils','chartUtils','diskSrv','alertListSrv']; });
省略了具体的业务逻辑,只是展示一下controller的代码结构,具体代码的规范可以参考前面的文章。这里之所以使用$inject这种方式,还有一个原因是在单元测试的时候,因为整个应用使用了requirejs这种异步加载机制,有的controller里面会用ngload异步加载一些文件,那么跑测试的时候,无法控制在加载完成后在运行test case,所以用$controller的方法测试controller会报错。
对话框级别的controller
在使用bootstrap对话框组件的时候,会有很多参数,而且用起来比较繁琐,所以应该自己封装一下——
modalUtils.showDlg({ tpl:'modules-lhv/network/extranet/extranet-creation.html',deps:'modules/network/extranet/extranet-creation.controller',ctrl:'ExtranetCreationCtrl',size:"md" }).then(function(result){ },function(){ });
function showDlg(dlgParams){ var deferred = $q.defer(); var $uibModal = $injector.get("$uibModal"),modalParams = { templateUrl:$templateCache.get(dlgParams.tpl) ? dlgParams.tpl : (dlgParams.tpl.indexOf("/") != 0 ? cmpConfig.appPath + dlgParams.tpl : dlgParams.tpl),controller:dlgParams.ctrl,backdrop:'static',resolve:{ params: function(){ return dlgParams.params || {}; } },size: dlgParams.size || "md",windowClass: dlgParams.windowClass || "",}; if(dlgParams.deps){ modalParams.resolve["$$deps$$"] = function(){ var deferred = $q.defer(),$$deps$$ = angular.isArray(dlgParams.deps) ? dlgParams.deps : [dlgParams.deps]; require($$deps$$,function(){ deferred.resolve(); }); return deferred.promise; } } var modalInstance=$uibModal.open(modalParams); modalInstance.result.then(function (result) { deferred.resolve(result); },function(reason){ deferred.reject(reason); }); return deferred.promise; } function showSmallDlg(dlgParams){ dlgParams.size = "sm"; return showDlg(dlgParams); } function showConfirmDlg(options){ ...... } function showErrorDlg(options){ ...... } function showInfoDlg(options){ ...... }主要想说的是,bootstrap的对话框组件需要在使用前把controller加载进来,如果在页面级别的controller里面把对话框需要的controller通过define提前加载进来,会造成不必要的资源浪费,因为用户可能根本不去使用某些对话框提供的功能。所以上面最重要的功能就是利用resolve方法去动态加载controller。最好还能对info,error,confirm等类型对话框做一层统一的封装,方便调用。
这里还要提一下controller继承的问题,controller本身不提供继承的功能,但是还是有方法可以实现的,可以参考一下这篇文章:
$controller('BaseController',{ $scope: $scope });前提是BaseController需要提前用define加载进来,然后把这句话写在controller定义函数的最一开头就可以了。其实就是把父controller里$scope上的东西加到了当前controller的$scope上。