首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >从服务器加载html和Controller并创建动态UI - router

从服务器加载html和Controller并创建动态UI - router
EN

Stack Overflow用户
提问于 2016-01-28 00:05:47
回答 4查看 2.7K关注 0票数 16

我正在寻找一个解决方案,以动态加载我的应用程序内容从服务器。

我的场景是:

假设我们有2个用户(A和B),我的应用程序由不同的模块组成,比如shoppingList和计算器,现在我的目标是用户从数据库登录到我的应用程序我得到用户权限,根据他拥有的权限,我将从服务器加载视图的html和逻辑部分的控制器文件,同时我将创建html和ctrl所需的状态。所以基本上我的应用程序是非常小的,一致的登录和其他一切都是从服务器上拉取决于用户权限。

我使用的是:

科尔多瓦

  • AngularJs

  • Ionic

为什么我需要它都是动态的:

1)有可能有一个只包含登录逻辑的应用程序,所以当修复错误或添加模块时,我只需将文件添加到服务器,给用户它的权利,它就在那里,而不需要更新应用程序。

2)用户只有他需要的功能,当他只有一个模块的权利时,他不需要拥有所有的功能。

3) App目前变得非常大,这意味着每个模块都有大约5-10个状态,有自己的html和控制器。目前有50个不同的模块计划,所以你可以做数学计算。

我看这篇文章是为了得到一些灵感:

AngularJS, ocLazyLoad & loading dynamic States

到目前为止,我尝试了以下内容:

我创建了一个包含整个模块的Html文件,所以我只有一个http请求:

假设这是我在用户登录后从服务器得到的响应

HTML部件:

代码语言:javascript
复制
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]);

          }
        }
     });

控制器部分:

代码语言:javascript
复制
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]);

          }
        }
     });

加载控制器后,我尝试注册它们:

代码语言:javascript
复制
$controllerProvider.register('SomeName', $templateCache.get('controllers/someController));

这不起作用,因为这只是一个字符串...

定义提供程序:

代码语言:javascript
复制
.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-路由器部分:

代码语言:javascript
复制
//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中,甚至加载它们,但只有当状态为predefined.What时,我才会注意到,有时让我们说,当我从列表中删除一个项目并返回到视图时,该项目再次出现可能这与缓存有关我不是很确定……

我已经设法加载控制器文件并将控制器保存在templateCache中,但我真的不知道如何将$ControllerPrioviderRef.register与我存储的字符串一起使用……

创建状态确实有效,但是控制器不适合,所以我无法打开任何视图……

PS:我还研究了require.js和OCLazyLoad,以及这个dynamic controller example示例

更新:

好的,我设法加载了Html,用Controller创建了State,一切似乎都很好,除了控制器似乎根本不工作,没有错误,但似乎控制器逻辑没有执行。目前,从之前下载的文件中注册控制器的唯一解决方案是使用eval(),,这更像是一种技巧,而不是一个合适的解决方案。

代码如下:

代码语言:javascript
复制
.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();

        }
    }
}])

感谢您的任何帮助

EN

回答 4

Stack Overflow用户

发布于 2016-02-02 16:34:59

好的,让我们从头开始。

所有的应用程序逻辑都应该包含在服务器上,并通过API提供服务-通过REST、SOAP或类似的API调用。通过这样做,您可以减少构建到UI中的逻辑量,从而减少客户端的压力。这基本上使您的客户端应用程序成为呈现代理,仅包含由后端API提供的数据和逻辑的模型和视图。

正如foreyez在他/她的评论中所说,这不是任何现代(或半现代)设备的问题。

如果你坚持不一次加载所有的布局,你当然可以把它们分成几部分,然后根据用户权限在登录后加载。通过这样做,您可以减少内存中的数据量,即使这种改进充其量也是值得怀疑的。

票数 4
EN

Stack Overflow用户

发布于 2016-02-13 02:14:56

我可以建议您对加载状态的方式进行一些更改吗?

编写一个脚本,返回一个包含用户可以访问的状态的json。

例如。

resources/routing-config.yourLangage?user=user-id-12345

这将返回一个依赖于登录用户的json文件。结构可以是这样的:

代码语言:javascript
复制
    [
      {
        "name": "home",
        "url": "/home",
        "templateUrl": "views/home.html",
        "controller": "HomeController",
        "dependencies": ["scripts/home/controllers.js", "scripts/home/services.js", "scripts/home/directives.js"]
      },
      {
        "name": "user",
        "url": "/user",
        "templateUrl": "views/user.html",
        "controller": "UserController",
        "dependencies": ["scripts/user/controllers.js", "scripts/user/services.js", "scripts/home/directives.js"]
      }
    ]

然后让我们编写一个服务,它将读取用户被允许访问的状态:

代码语言:javascript
复制
app.factory('routingConfig', ['$resource',
  function ($resource) {
    return $resource('resources/routing-config.yourLangage', {}, {
      query: {method: 'GET',
              params: {},
              isArray: true,
              transformResponse: function (data) {
                  // before that we give the states data to the app, let's load all the dependencies
                  var states = [];
                  angular.forEach(angular.fromJson(data), function(value, key) {
                    value.resolve = {
                        deps: ['$q', '$rootScope', function($q, $rootScope){
                          // this will be resolved only when the user will go to the relative state defined in the var value
                          var deferred = $q.defer();

                          /*
                            now we need to load the dependencies. I use the script.js javascript loader to load the dependencies for each page.
                            It is very small and easy to be used
                            http://www.dustindiaz.com/scriptjs
                          */
                          $script(value.dependencies, function(){ //here we will load what is defined in the dependencies field. ex: "dependencies": ["scripts/user/controllers.js", "scripts/user/services.js", "scripts/home/directives.js"]
                            // all dependencies have now been loaded by so resolve the promise
                            $rootScope.$apply(function(){
                              deferred.resolve();
                            });
                          });

                          return deferred.promise;
                        }]
                      };
                    states.push(value);
                  });
                  return states;
                }
            }
    });
  }]);

然后让我们配置应用程序:

代码语言:javascript
复制
app.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', '$filterProvider', '$provide', '$compileProvider',
  function ($stateProvider, $urlRouterProvider, $locationProvider, $filterProvider, $provide, $compileProvider) {

    // this will be the default state where to go as far as the states aren't loaded
    var loading = {
        name: 'loading',
        url: '/loading',
        templateUrl: '/views/loading.html',
        controller: 'LoadingController'
    };

    // if the user ask for a page that he cannot access
    var _404 = {
        name: '_404',
        url: '/404',
        templateUrl: 'views/404.html',
        controller: '404Controller'
    };

    $stateProvider
      .state(loading)
      .state(_404);


    // save a reference to all of the providers to register everything lazily
    $stateProviderRef = $stateProvider;
    $urlRouterProviderRef = $urlRouterProvider;
    $controllerProviderRef = $controllerProvider;
    $filterProviderRef = $filterProvider;
    $provideRef = $provide;
    $compileProviderRef = $compileProvider;


    //redirect the not found urls
    $urlRouterProvider.otherwise('/404');

  }]);

现在让我们在app.run中使用这个服务:

代码语言:javascript
复制
app.run(function ($location, $rootScope, $state, $q, routingConfig) {

  // We need to attach a promise to the rootScope. This will tell us when all of the states are loaded.
  var myDeferredObj = $q.defer();
  $rootScope.promiseRoutingConfigEnd = myDeferredObj.promise;

  // Query the config file
  var remoteStates = routingConfig.query(function() {
    angular.forEach(remoteStates, function(value, key) {
      // the state becomes the value
      $stateProviderRef.state(value);
    });
      // resolve the promise.
      myDeferredObj.resolve();
  });

  //redirect to the loading page until all of the states are completely loaded and store the original path requested
  $rootScope.myPath = $location.path();
  $location.path('/loading'); //and then (in the loading controller) we will redirect to the right state

  //check for routing errors
  $rootScope.$on('$stateChangeError', 
    function(event, toState, toParams, fromState, fromParams, error){
      console.log.bind(console);
  });

  $rootScope.$on('$stateNotFound', 
    function(event, unfoundState, fromState, fromParams){ 
        console.error(unfoundState.to); // "lazy.state"
        console.error(unfoundState.toParams); // {a:1, b:2}
        console.error(unfoundState.options); // {inherit:false} + default options
  });

});

最终,LoadingController:

代码语言:javascript
复制
app.controller('LoadingController', ['$scope', '$location', '$rootScope',
  function($scope, $location, $rootScope) {

    //when all of the states are loaded, redirect to the requested state
    $rootScope.promiseRoutingConfigEnd.then(function(){
      //if the user requested the page /loading then redirect him to the home page
      if($rootScope.myPath === '/loading'){
        $rootScope.myPath = '/home';
      }
      $location.path($rootScope.myPath);
    });

}]);

通过这种方式,一切都是超级灵活和延迟加载的。

我已经写了3个不同的用户门户,我可以很容易地扩展到我想要的所有用户门户。

票数 3
EN

Stack Overflow用户

发布于 2016-02-09 14:50:08

我已经开发了一个应用程序,并将这些事情牢记在心。这是我的架构。

文件夹结构:

代码语言:javascript
复制
WebApp
|---CommonModule
    |---common-module.js //Angular Module Defination
    |---Controllers     //Generally Nothing, but if you have a plan to
                        //extend from one CommonController logic to several 
                        //module then it is usefull

    |---Services        //Common Service Call Like BaseService for all $http 
                        //call, So no Module Specific Service will not use 
                        //$http directly. Then you can do several common 
                        //things in this BaseService. 
                        //Like Error Handling, 
                        //CSRF token Implementation, 
                        //Encryption/Decryption of AJAX req/res etc.

    |---Directives      //Common Directives which you are going to use 
                        //in different Modules
    |---Filters         //Common Filters

    |---Templates       //Templates for those common directives

    |---index.jsp       //Nothing, Basically Redirect to 
                        //Login or Default Module

    |---scripts.jsp     //JQuery, AngularJS and Other Framworks scripts tag.
                        //Along with those, common controlers, services, 
                        //directives and filtes. 

    |---templates.jsp   //Include all common templates.

    |---ng-include.jsp  //will be used in templates.jsp to create angular 
                        //template script tag.
|---ModuleA
    |---moduleA-module.js //Angular Module Definition, 
                          //Use Common Module as Sub Module
    |---Controllers
    |---Services
    |---Directives
    |---Filters
    |---Templates
    |---index.jsp 
    |---scripts.jsp 
    |---templates.jsp
|---ModuleB
    |--- Same as above ...

注意:__:大写表示文件夹。我想在ModuleA旁边会有一个适用于您的案例的LoginModule,或者您也可以使用CommonModule。

Mehu将如下所示。

代码语言:javascript
复制
<a href="/ModuleA/">Module A</a> <!--Note: index.jsp are indexed file 
                                 //for a directive -->
<a href="/ModuleB/">Module B</a>

这些JSP页面中每一个实际上都是独立的angular应用程序。使用以下代码。

ModuleA/index.jsp

代码语言:javascript
复制
<!-- Check User Permission Here also for Security 
     If permission does not have show Module Unavailable Kind of JSP.
     Also do not send any JS files for this module.
     If permission is there then use this following JSP
-->
<!DOCTYPE HTML>
<html  lang="en" data-ng-app="ModuleA">
    <head> 
        <title>Dynamic Rule Engine</title>
        <%@ include file="scripts.jsp" %> 
        <%@ include file="templates.jsp" %> <!-- Can be cached it in
                                                 different way --> 
    </head>
    <body>
        <%@ include file="../common.jsp" %>
        <div id="ngView" data-ng-view></div>
        <%@ include file="../footer.jsp" %>
    </body>
</html>

ModuleA/scripts.jsp

代码语言:javascript
复制
<%@ include file="../CommonModule/scripts.jsp" %> <!-- Include Common Things
                                              Like Jquery Angular etc  -->
<scripts src="Controlers/ModlueAController1.js"></script>
.....

ModuleA/templates.jsp

代码语言:javascript
复制
<%@ include file="../CommonModule/templates.jsp" %> 
<!-- Include Common Templates for common directives -->
<jsp:include page="../CommonModule/ng-include.jsp"><jsp:param name="src" value="ModuleA/Templates/template1.jsp" /></jsp:include>
.....

CommonModule/ng-include.jsp

代码语言:javascript
复制
<script type="text/ng-template" id="${param.src}">
    <jsp:include page="${param.src}" />
</script>

但这种方法的主要问题是当用户更改模块时,页面将被刷新。

EDIT:有一个包含模块减速的ModuleA.module.js文件,如下所示。

代码语言:javascript
复制
angular.module('ModuleA.controllers', []);
angular.module('ModuleA.services', []);
angular.module('ModuleA.directives', []);
angular.module('ModuleA.filters', []);
angular.module('ModuleA', 
       ['Common', 
        'ModuleA.controllers' , 
        'ModuleA.services' , 
        'ModuleA.directives' , 
        'ModuleA.filters'])
    .config(['$routeProvider', function($routeProvider) {
        //$routeProvider state setup
    }])
    .run (function () {

    });
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35042277

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档