AngularJS: Resolve and lazy loading services - javascript

I'm using this method for lazy-loading the controllers/services required for each of my AngularJS routes.
Basically, for each route, I define the dependencies (e.g the controllers, services, etc needed), then a function is added to the resolve of the route definition for that route, that function dynamically loads the javascript files of the dependencies.
This works, however where I run into a problem is this. Suppose that I wanted to lazy-load a service called fooService for the route /foo. However, what if I also wanted to have fooService.getResults() added to the resolve for /foo? This gives an error because perhaps the fooService.js file is not loaded by the time the resolve function for fooService.getResults() is called.
Is there any solution to this?

Related

Loading multiple modules under same parent route in Angular

I' am looking for a way through which I can load multiple modules under same path in Angular. For example, consider I have three modules AModule, BModule and CModule each having its own RouterModule.forChild call. Now I want to mount all these modules under say site route.
One way I have achieved this thing is by wrapping routes in RouterModule.forChild call under site route as follows:
RouterModule.forChild([
{
path: 'site',
children: [{}] // children goes here
}
])
I don't know whether this approach is correct but it is working fine. The only issue which this approach is that I have to specify canActivate in every module I want to mount under site. While this is not a problem, I was looking for a cleaner solution.
I know there is a property loadChildren which could be used to load modules lazily. But I want to load modules eagerly.
I' am using AngularCLI which splits code of module I specify in loadChildren in a separate JavaScript file which is not I want.
I' am using AngularClI v1.2.0 and Angular v4.2.5.
Any help is highly appreciated.
Thanks
I'm not entirely clear on your goal and what you are ultimately trying to achieve, but here are a few thoughts.
You can use the loadChildren and "lazy loading" to load on demand OR eagerly. If you select eagerly loaded routes, as soon as your main route is loaded and your first view is displayed, the other modules marked for eager loading are immediately loaded asynchronously.
I have an example of that here: https://github.com/DeborahK/Angular-Routing in the APM-Final folder.
I'm not clear on why you don't want module splitting. It can significantly improve the startup performance (time to display of the first page) of your application.
In addition to canActivate there is also a canActivateChild so you can put this on the parent and not have to repeat it for each route. The docs for that are here: https://angular.io/api/router/CanActivateChild

Angular 2 router config lazy loaded modules

I'm trying to create a service which uses router configuration to create map of routes based on components. It works fine when you don't use lazy loaded module routes.
But I don't know how to get routes from lazy loaded module. In route object there is just loadChildren string and that's it. I digged little bit into angular2 internals and it is using RouterConfigLoader internally to load lazy loaded routes. But it is not exported from RoutingModule, so I suppose it should not be used from the outside.
Is there any public API which would help me with that?
Thanks
But that's the whole idea of lazy loaded modules. No reference exists to the lazy loaded module, so it ain't loaded on load (can I use the word load some more?).
Which also means no routing is available. Based on the string, angular2 loads the (entire) module, and injects the routing on the fly. If you want to know the routing beforehand, you should either not use lazy modules, or do it by hand

Loading One Controller Per View AngularJS

I have an Spring + AngularJS Web Application with the following angular file structure.
mainmodule.js - where all config and routing's are
controller1.js
controller2.js
my main page is home.jsp where I imported all these files. As project goes bigger, I guess we have little over 50 files overall. So instead of dumping them in home.jsp, I would like to load them in it's corresponding view files. But when I tried to load controller1.js in corresponding JSP file, I get the below error.
[ng:areq] http://errors.angularjs.org/1.4.4/ng/areq?p0=dashboardController&p1=not%20aNaNunction%2C%20got%20undefined
Can someone help me identify what is the issue and how can I achieve this?
BTW I am using ui-router instead of default ngRoute.
One way of dealing with that scenario is to define a resolve property on each route and assign it a function that returns a promise. The function can handle dynamically loading the script containing the target controller and resolve the promise once the load is complete. For example:
$routeProvider
.when('/customers',
{
templateUrl: '/app/views/customers.html',
resolve: resolveController('/app/controllers/customersController.js')
});
But the best solution to your problem would be to use RequireJS framework with AngularJS for dynamically loading controllers per view.
There is very interesting source that explains about this : http://weblogs.asp.net/dwahlin/dynamically-loading-controllers-and-views-with-angularjs-and-requirejs
RequireJS official website: http://requirejs.org

How to retry route request on $stateNotFound event in AngularUI Router

I have a large AngularJS application which is split into different functional modules. It is currently bundled into single JavaScript file and thus all the modules are loaded on initial page load. I want to split the bundle by functional areas and load parts of the application on demand as the user reaches some specific points (views).
I have the bundling and lazy loading sorted out with help of RequireJS and ocLazyLoad. There is last thing left to address though. Each module defines its own routes so if I won't load it at the initial load, the routes for it will be undefined until the user reaches the point that triggers loading of the module.
The issue is that the missing route can be reached directly by simply pasting its URL, in that case AngularUI Router will emit $stateNotFound event. I have a handler for it that will check the requested URL and load appropriate module (along with missing routes). The last missing piece is to, after the module and routes have been loaded, retry the route. Does anyone know how to achieve that ? There is a section in AngularUI Router's FAQ that is meant to explain that but it's not filled in.
You should probably use the "when" function of the $urlRouterProvider instead of catching a $stateNotFound event:
$urlRouterProvider.when('/myUrl', ['$match', '$state', function($match, $state) {
// do something, check for module loaded for example
// ... and then transitionTo
$state.transitionTo(state, $match);
}]);
Delay the $state.transitionTo until you want (after preloading the modules for example).
But if you really want to use the $stateNotFound you can do this:
$rootScope.$on('$stateNotFound', function(event, unfoundState, fromState, fromParams){
event.preventDefault()
// do your module load
// ... and then transitionTo
$state.transitionTo(unfoundState.to, unfoundState.toParams, unfoundState.options);
})

Require dependency only when backbone view is loaded

I am using Backbone with Layout Manager and RequireJS.
View1 depends on 2 dependencies as can be seen below.
The application also has a similar view
named View2, which depends only on 'jquery.fileupload', unlike View1, which has 2 deps.
define(['jquery.fileupload', 'jquery.fileupload-ui'], function (dep1, dep2) {
var View1 = Backbone.View.extend({
...
});
return View1;
});
The problem is that 'jquery.fileupload-ui' (second dependency) seems to be loaded/evaluated by requireJS even if I don't visit a view that depends on it and that causes some plugin errors (I am using basic fileupload plugin in one view, and extended fileupload plugin in another view). It looks like define() pre-loads modules right away.
How can I avoid loading the second dependency at app initialization and load it only inside my view?
I think I could nest require() call into define for View1,
but I am not sure how then I can return a value if calls are nested.
Any time you module load the view1 module, 'jquery.fileupload-ui' will be loaded. If you only need this module in certain cases when you module load view1, you could have view1 require() in 'jquery.fileupload-ui' only if a certain code path is reached.
You can do this by adding a require(['jquery.fileupload-ui'], function(jqui){...}); in the specific method within view1 where you need the library.
I am not sure if this answers your question, but I think it may.

Categories