【发布时间】:2016-02-17 02:27:25
【问题描述】:
我正在寻找从服务器动态加载我的应用内容的解决方案。
我的场景:
假设我们有 2 个用户(A 和 B),我的应用由不同的模块组成,比如可以说一个 shoppingList 和一个计算器,现在我的目标是用户从数据库登录到我的应用我获得用户权限和根据他拥有的权利,我将从服务器加载视图的 html 和逻辑部分的控制器文件,同时我会创建 html 和 ctrl 所需的状态。所以基本上我的应用程序与登录非常一致,其他所有内容都根据用户权限从服务器中提取。
我用什么:
- 科尔多瓦
- AngularJs
- 离子框架
为什么我需要它是动态的:
1) 拥有一个仅包含登录逻辑的应用程序的可能性,因此在修复错误或添加模块时,我只需将文件添加到服务器,为用户提供权限,无需更新即可应用程序。
2)用户只拥有他需要的功能,他不需要拥有一切,当他只有1个模块的权利时。
3) 应用程序现在变得非常大,这意味着每个模块都有大约 5-10 个状态,有自己的 html 和控制器。目前计划了 50 个不同的模块,因此您可以进行计算。
我看了这个以获得一些灵感:
AngularJS, ocLazyLoad & loading dynamic States
到目前为止我尝试了什么:
我创建了 1 个包含整个模块的 Html 文件,所以我只有 1 个 http 请求:
假设这是我在用户登录后服务器的响应
HTML 部分:
var rights= [A,B,C,D]
angular.forEach(rights, function (value, key) {
$http.get('http://myServer.com/templates/' + value + '.html').then(function (response) {
//HTML file for the whole module
splits = response.data.split('#');
//Array off HTMl strings
for (var l = 1; l <= splits.length; l++) {
//Putting all Html strings into templateCache
$templateCache.put('templates/' + value +'.html', splits[l - 1]);
}
}
});
控制器部分:
var rights= [A,B,C,D]
angular.forEach(rights, function (value, key) {
$http.get('http://myServer.com/controller/' + value + '.js').then(function (response) {
// 1 file for the whole module with all controllers
splits = response.data.split('#');
//Array off controller strings
for (var l = 1; l <= splits.length; l++) {
//Putting all Controller strings into templateCache
$templateCache.put('controllers/' + value +'.js', splits[l - 1]);
}
}
});
加载控制器后,我尝试注册它们:
$controllerProvider.register('SomeName', $templateCache.get('controllers/someController));
这是行不通的,因为这只是一个字符串...
定义提供者:
.config(function ($stateProvider, $urlRouterProvider, $ionicConfigProvider, $controllerProvider) {
// turns of the page transition globally
$ionicConfigProvider.views.transition('none');
$stateProviderRef = $stateProvider;
$urlRouterProviderRef = $urlRouterProvider;
$controllerProviderRef = $controllerProvider;
$stateProvider
//the login state is static for every user
.state('login', {
url: "/login",
templateUrl: "templates/login.html",
controller: "LoginCtrl"
});
//all the other states are missing and should be created depending on rights
$urlRouterProvider.otherwise('/login');
});
Ui-Router部分:
//Lets assume here the Rights Array contains more information like name, url...
angular.forEach(rights, function (value, key) {
//Checks if the state was already added
var getExistingState = $state.get(value.name)
if (getExistingState !== null) {
return;
}
var state = {
'lang': value.lang,
'params': value.param,
'url': value.url,
'templateProvider': function ($timeout, $templateCache, Ls) {
return $timeout(function () {
return $templateCache.get("templates" + value.url + ".html")
}, 100);
},
'ControllerProvider': function ($timeout, $templateCache, Ls) {
return $timeout(function () {
return $templateCache.get("controllers" + value.url + ".js")
}, 100);
}
$stateProviderRef.state(value.name, state);
});
$urlRouter.sync();
$urlRouter.listen();
目前的情况:
我已经设法加载 html 文件并将它们存储在 templateCache 中,甚至加载它们,但前提是状态是预定义的。我在这里注意到的是,有时可以说当我从列表中删除一个项目并返回时再次查看该项目可能与缓存有关我不太确定...
我已设法加载控制器文件并将控制器保存在 templateCache 中,但我真的不知道如何将 $ControllerPrioviderRef.register 与我存储的字符串一起使用...
创建状态确实有效,但控制器不适合,所以我无法打开任何视图...
PS:我还查看了 require.js 和 OCLazyLoad 以及这个示例 dynamic controller example
更新:
好的,所以我设法加载了 Html ,用 Controller 创建了 State 一切似乎都工作正常,除了控制器似乎根本不工作,没有错误,但似乎不执行任何控制器逻辑。目前,从之前下载的文件中注册控制器的唯一解决方案是使用 eval(),,这更像是一种 hack,而不是正确的解决方案。
代码如下:
.factory('ModularService', ['$http', ....., function ( $http, ...., ) {
return {
LoadModularContent: function () {
//var $state = $rootScope.$state;
var json = [
{
module: 'Calc',
name: 'ca10',
lang: [],
params: 9,
url: '/ca10',
templateUrl: "templates/ca/ca10.html",
controller: ["Ca10"]
},
{
module: 'SL',
name: 'sl10',
lang: [],
params: 9,
url: '/sl10',
templateUrl: "templates/sl/sl10.html",
controller: ['Sl10', 'Sl20', 'Sl25', 'Sl30', 'Sl40', 'Sl50', 'Sl60', 'Sl70']
}
];
//Load the html
angular.forEach(json, function (value, key) {
$http.get('http://myserver.com/' + value.module + '.html')
.then(function (response) {
var splits = response.data.split('#');
for (var l = 1; l <= value.controller.length; l++) {
$templateCache.put('templates/' + value.controller[l - 1] + '.html', splits[l - 1]);
if (l == value.controller.length) {
$http.get('http://myserver.com//'+value.module+'.js')
.then(function (response2) {
var ctrls = response2.data.split('##');
var fullctrl;
for (var m = 1; m <= value.controller.length; m++){
var ctrlName = value.controller[m - 1] + 'Ctrl';
$controllerProviderRef
.register(ctrlName, ['$scope',...., function ($scope, ...,) {
eval(ctrls[m - 1]);
}])
if (m == value.controller.length) {
for (var o = 1; o <= value.controller.length; o++) {
var html = $templateCache
.get("templates/" + value.controller[o - 1] + ".html");
var getExistingState = $state.get(value.controller[o - 1].toLowerCase());
if (getExistingState !== null) {
return;
}
var state = {
'lang': value.lang,
'params': value.param,
'url': '/' + value.controller[o - 1].toLowerCase(),
'template': html,
'controller': value.controller[o - 1] + 'Ctrl'
};
$stateProviderRef.state(value.controller[o - 1].toLowerCase(), state);
}
}
}
});
}
}
});
});
// Configures $urlRouter's listener *after* your custom listener
$urlRouter.sync();
$urlRouter.listen();
}
}
}])
任何帮助表示赞赏
【问题讨论】:
-
为什么不加载所有内容并根据用户访问权限隐藏未使用的菜单项?模板并没有占用太多空间。
-
好吧,在这种情况下,他们的应用程序会变得非常大,所以我有必要这样做。
-
我个人不会那样做。现在已经不是 2000 年代初期了。现在都是胖客户端 html5+ajax 调用。我把所有的东西都放了。客户端上的所有模块。和 50 个模块,尤其是 html/css/javascript 是个笑话。甚至在移动设备上。
-
这不是问题,目标是为每个用户提供 1 个应用程序,并且能够在不重新部署应用程序的情况下更改、修改、添加、删除内容(不通过应用程序商店) ,目前的问题是我必须将应用程序重新部署到每台设备,每次进行错误修复、更改、添加时
标签: javascript angularjs requirejs angular-ui-router oclazyload