2

I'm using ocLazyLoad to load my modules on demand in Angular. These modules are totally different and we should check using the server which module should we load. Before Using ocLazyLoad I was loading all concatenated js files of these separate modules in my main View. So all of them we're loading.

Now as it's obvious I'm loading these files on demand, which mean it should read data from the server and see which modules should be loaded and load a megabyte File and most importantly load it before angular begins to compile the View.

I was using ocLazyLoad's promise to $compile the view (body) but since it was being done twice or even more sometimes my directives weren't working.

So I think I have two options:

  1. Make angular manually compile the view (which I searched a lot and I couldn't find how!!) after the modules are injected and loaded by ocLazyLoad!

  2. Read the list of needed modules from the server and use LazyLoad in the maybe run phase of the app or even before angular.bootstrap. (I've done this already but since the $http request is being done async It works sometimes and it loads before angular compile and sometimes it doesn't)

I would appreciate it if you could help me with this.

spa.run(['$rootScope', '$location', '$route', '$localStore', '$templateCache', 'Analytics', 'preflightValue', '$ocLazyLoad', '$http',
'$compile', function($rootScope, $location, $route, $localStore, $templateCache, Analytics, preflightValue, $ocLazyLoad, $http, $compile ) {
    $rootScope.$on('cfpLoadingBar:completed', function(event, args) {
        angular.element($('body')).addClass('cfp-done');
    });

    $http({
        method: 'POST',
        url: url,
        data: {
            route: "/dashboard"
        },
        headers: {
            // My Headers
        }
    }).success(function (data, status, header, config) {
        var currentModules = $ocLazyLoad.getModules();
        for (var i = 0; i < data.data.cloudwares.length; i++) {
            var moduleName = data.data.cloudwares[i];
            if (currentModules.indexOf(moduleName) === -1 && moduleName !== 'bot-manager') {
                preflightValue.addModule(moduleName);
            }
        }
        $ocLazyLoad.load(preflightValue.modulesList()).then(function () {
            preflightValue.emptyList();
        });
    });
}]);

// Update

Please pay attention that we're not using ui-router or ngRouter. We're getting the state of our route from the server each time using $resource.

mamsoudi
  • 3,999
  • 1
  • 15
  • 24
  • if you could elaborate on what your view looks like and how you bootstrap the initial spa app I could get a better idea of what the best solution would be for your use-case. – vileRaisin Aug 29 '16 at 15:12
  • @vileRaisin Since the whole system is made of so many services and controllers that are connected to each other, I'm afraid I can't do that! The main problem here is that I can't tell angular to wait for the $http request to finish then load the needed modules and finally go to run(). I've moved the lazy loading to $routeProvider resolve but only and only if I tell it statically which files it should load it will do it. But I can't apparently find a way to make a $http request to the server, get needed modules and then pass it to $ocLazyLoad, all before angular compiles the view! – mamsoudi Aug 30 '16 at 04:49
  • @vileRaisin I even tried this plugin called angular-deferred-bootstrap which allows you to make a $http request before angular is bootstrapped! It passes the data to a constant which later I inject as a Constant to my $oclazyload function. Everything is working perfectly. We have the data and $oclazyload is working fine before angular begins the compile! but there's some weird issue I don't get why it happens! $ocLazyLoad reloads itself and "ng" module "$invoke" service which I believe prevents angular from compiling directives. And this time problem is solved but nothing is being shown! – mamsoudi Aug 30 '16 at 04:55
  • There are a couple solutions, however, I need to understand your view, because most likely you need to change your view. One way that would be easy would be to have two separate angular apps on your page, the first is loading lazyLoad, once that is done loading, you can then bootstrap the rest of your app onto a separate part of the view. This means you need to separate in the view where these apps are bootstrapped. – vileRaisin Aug 30 '16 at 10:19
  • Another way, that might work depending on what your usecase is, is to have a wrapper directive surrounding your view, and is set to terminal. This wrapper directive will then only start compiling once you have all your modules bootstrapped. Similarly there are other ways to approach this, but again, without understanding your view, it is almost impossible to understand what a good solution is. – vileRaisin Aug 30 '16 at 10:19
  • Please note that your problem is because you are using ocLazyLoad, which is itself an angular service. So you need angular to load your angular. Now, this isn't neccessary a difficult issue to overcome. I also don't really understand the "problem", lazyLoad allows you to asynchronously load modules, after your app has been loaded, which is an opportunity, not a problem – vileRaisin Aug 30 '16 at 10:21
  • But it is far easier to not use ocLazyLoad, but to have a SystemJS or requireJS bootstrap code, which will hold the logic to load all your modules before angular has ever loaded. – vileRaisin Aug 30 '16 at 10:22
  • @vileRaisin Actually we have a Core app which handles routing system and Also we have a directive named "page" which is the one you call it the wrapper directive! We use this Core modules to load other modules. for example a module that is online storage and has different Views and directives to itself. An E-Learning Module and lots of other things! These all act like a CMS! We define Boxes on Server and with each routechange we give domain to API and receive which module and boxes should be loaded! it's a very complicated system! – mamsoudi Aug 30 '16 at 10:54
  • @vileRaisin our problem is that we can't make angular wait and let us read these data from API then use the same response to load needed modules using $ocLazyLoad, then put boxes into their position! I'm looking for a way to Send the request, wait for response use the response to load modules using lazyload and when modules were completed loading let angular go and compile the view, read directives and do its jobs! That's it! – mamsoudi Aug 30 '16 at 10:57
  • @vileRaisin If I statically tell which modules we need to $ocLazyLoad in resolve Function of $routeProvider, it will load them and there will be no problem because ocLazyload uses promises to tell resolve and Angular when it's done loading modules! But the problem is this request to server! If I could somehow read this data then pass it to $ocLazyLoad once it was done and make angular compile view once LazyLoad was done it would be perfect! – mamsoudi Aug 30 '16 at 11:01
  • The solution to your problem is simple. In fact, you already have the solution. If you can provide some code, for instance your $routeProvider resolve attempt, because there is no reason the logic you just explained can't be done in a resolve. You can technically run the apollo missions all in that resolve function, so I hardly doubt your logic is more complicated than putting an earth human into orbit. However, I can not help you if you do not actually show some code, or how things are structured, especially the fact that you still haven't shown me how your views come into play. – vileRaisin Aug 30 '16 at 15:52
  • @vileRaisin LOL! I got the answer to my question on how to do it before angular starts compiling the view, here: http://stackoverflow.com/questions/39219448/use-a-routeprovider-resolve-function-inside-another-one/ Thanks for your help BTW! After solving this issue I'm getting this weird problem of 3 or 4 times view compile on $routeChange but I guess it's another question! Thanks a lot! – mamsoudi Aug 31 '16 at 04:48

2 Answers2

2

In your config file try to state the route with lazyload event

app
.config(function ($stateProvider, $urlRouterProvider,ParseProvider){

        .state ('home', {
            url: '/home',
            // templateUrl: 'views/home.html',
            templateUrl: 'views/home.html',
            resolve: {
                loadPlugin: function($ocLazyLoad) {
                    return $ocLazyLoad.load ([
                        {
                            name: 'css',
                            insertBefore: '#app-level',
                            files: [
                                'vendors/bower_components/fullcalendar/dist/fullcalendar.min.css',
                            ],

                        },
                        {
                            name: 'vendors',
                            insertBefore: '#app-level-js',
                            files: [
                                'vendors/sparklines/jquery.sparkline.min.js',
                                'vendors/bower_components/jquery.easy-pie-chart/dist/jquery.easypiechart.min.js',
                                'vendors/bower_components/simpleWeather/jquery.simpleWeather.min.js'
                            ]
                        }
                    ])
                }
            }
        })
})

from this you can load any scripts to your view.

Mohamed Nizar
  • 780
  • 9
  • 30
  • Thanks for your answer pal. But we're not using ui-router or ngRouter. What I'm looking for is to make angular wait for lazyload completion and then begin to compile directives , etc. – mamsoudi Aug 29 '16 at 03:56
  • If you would please read my comments on the Question above! Thanks! I'm actually using your solution but still facing some issues! – mamsoudi Aug 30 '16 at 04:56
  • what are them!can you tell them,attached the out put of console.log() – Mohamed Nizar Aug 30 '16 at 05:13
1

I Actually Solved this Issue by asking another question! All I had to do was to return two promises!

Find the solution Here: Use a $routeProvider resolve function inside another one

Community
  • 1
  • 1
mamsoudi
  • 3,999
  • 1
  • 15
  • 24