I have a distributed AngularJs library module, that is been used in other AngularJs applications that I have no control over.
After researching I see that For an AngularJs application, you can load a json settings by ajax request and then synchronously bootstrap the app afterward.
For a module I provide for other to use, it is not that simple. Looking at AngularJs injector code, I don't see any asynchronous mechanism coming into play when loadModules act.
The json will be used to declare a constant provider for my sub module. It changes between different clients.
Has someone else found a trick or solution on how to load json settings for Angularjs module (not application) prior to the module availability to an Angularjs application?
For anyone that is interested, I have solved my problem by indirect solution. Another script loading tag above the sub module script tag. The other script include building an angular module that provides the constants for the other module which declare its dependency on it.
That way, synchronous order of first loading the configuration module and then the module is preserved. Not a direct solution but good enough for production usage.
Related
I am starting a side-project based in Sails to try it. Most of the pages are server-side rendered via EJS and don't require javascript on the front-end (my landing page doesn't, my "about" page certainly doesn't etc). However, I have a few pages that have quite a lot client-side functionality and I want to use Angular, because I am mostly familiar with that framework. The routing to these pages is again handled in the server and there's really no meaning in bundling them as a SPA.
So I am trying to wrap my mind around these concerns:
Where to place the Angular app's scripts?
Is /assets/js/dependencies still the proper place? Wouldn't placing them there make the Grunt task inject them in layout.ejs and thus in every page?
How to conditionally load the Angular base and it's components (controllers, services, etc)?
Sails uses views/layout.ejs as a base layout for loading project-wide styles, templates and scripts. Each page's controller handles injecting the body part into this layout according to the view "partial" that has been developed for that page. Is this view "partial" .ejs file the appropriate place to conditionally load the Angular app files in only the pages that require them?
How to add min/conctact/uglify of Angular' script sources in Grunt tasking?
All the Angular related files will need to be concatenated, minified/uglified for production. This will need to be a new js concatenated file to be loaded in appropriate pages apart from the "generic" js file that currently Sails tasks create and is loaded in every page. So we're essentially talking about two concatenated js files for the client side. One that is globally loaded, and the Angular one that only the pages that need it load. Which parts of the build/tasking procedure will require modifications? Some examples or resources to check would be highly useful here.
Where to place the Angular app's scripts?
Is /assets/js/dependencies still the proper place?
No, just put your angular.min.js in your dependencies folder, but not your Angular app's script. You need to put all you Angular app in the assets/js folder ( or in a sub-folder, but not in dependencies )
To be sure that each file of your app will be loaded in the right order (for example you need to load first the Js file which inject your angular app's dependencies), you can modify the tasks/pipeline.js file, and specify the order you want : You need to modify the jsFilesToInject array which contains all the Js files to load in the right order.
For example for your project :
var jsFilesToInject = [
// Load sails.io before everything else
'js/dependencies/sails.io.js',
// loading angularJS
'js/dependencies/angular.min.js',
// all the rest in dependencies
'js/dependencies/**/*.js',
// loading first AngularModule definition
'js/app/app.module.js',
// all the rest of the angular application
'js/app/**/*.js'
];
For your other question I think you need to look at the tasks/config/sails-linker.js file, that inject all the Js scripts in the <!--SCRIPTS--> tags in your HTML code.
I hope that it will help you and that I'm not too late !
I'm working on an Ionic project and trying to use Angular-UI's angular-google-maps.
However, since the regular, blocking way of loading the Maps JS API occasionally takes too long
the app times out.
I'm trying to make angular-google-maps 'load' only when Google Maps' script finishes loading async, by using the defer attribute and loading the script asynchronously.
The problem is that the module is initialised before 'google' is available and it breaks.
I'm looking for a way to delay the initialization of this module until it is possible to use.
Is there a way of having a 'proxy' or 'alias' module that injects the needed module when needed?
Or is there another way to control dependancy injection conditionally?
Thanks!
Thanks to the great article from Dan Wahlin, I managed to implement lazy loading of Angular's controllers and services. However, there does not seem to be a clean way to lazy load independent modules.
To better explain my question, assume that I have an app would be structure as below without RequireJS:
// Create independent module 'dataServices' module with 'Pictures' object
angular.module("dataServices", []).factory("Pictures", function (...) {...});
// Create 'webapp' ng-app, with dependency to 'dataServices', defining controllers
angular.module("webapp", ['dataServices'])
.controller("View1Controller", function (...) {...})
.controller("View2Controller", function (...) {...});
Here is the sample app with RequireJS in Plunker:
http://plnkr.co/aiarzVpMJchYPjFRrkwn
The core of the problem is that Angular does not allow adding dependency to ng-app post instantiation. As result, my solution is to use angular.injector to retrieve the instance of Picture object to be used in my View2Controller. See js/scripts/controllers/ctrl2.js file.
This creates 2 problems for me:
The injected services runs outside of angular and therefore all async call must end with $scope.$apply()
Messy code where some object can be injected using standard angular syntax while others require the explicit use of injector.
Have any of you figured out how to lazy load independent module using RequireJS and somehow hook this module in angular so normal angular dependency injection syntax can be used?
Note:
The question is on lazy loading of independent module. One simple solution to this specific example is to create "Pictures" object using cached $providers during ng-app.config but that is not what I am looking for. I am looking for solution that works with 3rd party module such as angular-resource.
I finalized my own implementation called angularAMD and here is the sample site that uses it:
http://marcoslin.github.io/angularAMD/
It handles config functions and out of order module definitions.
Hopefully this can help other looking for something to help them with RequireJS and AngularJS integration.
Take a look at my project in GitHub: angular-require-lazy
This project is intended to demonstrate an idea and motivate discussions. But is does what you want (check expenses-view.js, it loads ng-grid lazily).
I am very interested in comments, ideas etc.
(EDIT) The ng-grid Angular module is lazy loaded as follows:
expenses-view.js is loaded lazily, when the /expenses route is activated
expenses-view.js specifies ng-grid as a dependency, so RequireJs loads ng-grid first
ng-grid is the one that calls angular.module(...)
In order to accomplish this, I replaced (proxied actually) the real angular.module method with my own, that supports laziness. See bootstrap.js and route-config.js (the functions initLazyModules() and callRunBlocks()).
This implementation has its drawbacks that you should be aware of:
Config functions are not implemented (yet). I do not know if it is possible to lazily provide config-time dependencies.
Order matters in definitions. If service A depends on B but A is defined after B in your module, DI wil fail. This is because the lazyAngular proxy executes definitions immediately, unlike real Angular that makes sure dependencies are resolved before executing the definitions.
It looks like the Node.js module ocLazyLoad defines a way of doing this lazy-loading, though I'm not sure how it fares, performance-wise, compared to the methods in the other answers or hard-coding the dependencies. Any info on this would be appreciated. One interesting thing is that the other answers need RequireJS to operate, while ocLazyLoad doesn't.
It looks like ocLazyLoad defines another provider that injects the dependency after the containing module has already been instantiated. It seems to do this by essentially replicating some low-level Angular behavior, like module loading and providing, hence why it looks so complicated. It looks like it adds just about every core Angular module as a dependency: $compileProvider, $q, $injector, ng, and so many more.
I'm trying to manage the bootstrap process of a large AngularJS/Grails application. Here's what I've come up with, but I'm not so sure it's as clean as it could be, or as efficient. Thoughts?
Load angular-loader in a one-line minified /script
Load jquery explicity in another /script
Load a third-party async loader ($script) and all of the remaining dependencies
When the dependencies have loaded, call angular.bootstrap(document, ['myApp]);
Load my minified, concatenated app-specific javascript in another /script
This seems clunky. What alternatives might there be? I did consider RequireJS, but I don't like how intrusive it is, and I like using a grunt task to concat+uglify my app into a single script.
The general approach that I use is to load the basic components upfront and only load the controller and associated services on demand using RequireJS. Obviously, this is only applicable if you are dealing with large application.
As AngularJS does not natively support on-demand loading and delegate such task to async loader such as RequireJS, I encapsulated the logic need in something I call angularAMD.
Here is a sample site I created to illustrate how angularAMD works:
http://marcoslin.github.io/angularAMD/
I am using Angular JS. I wish to put unrelated code (ie, which is not a factory, service, controler, etc) in additional, separate modules, in a similar way one would with AMD or CommonJS.
At the time of writing, a search for 'Angular.JS make new module' using Google does not return any documentation on making Angular.JS modules.
I have a found a post on the Angular.JS Google Group that seems to indicate that instead of loading dependencies dynamically like other module systems, in Angular.JS dependencies must be inserted as additional script tags.
Is there any documentation on making Angular modules (which is not limited to controllers, services, or other angular concepts)?
Is the statement about script tags true? Do I need to manually add script tags for every module I may use?
Looking further into the various Angular boilerplate apps, apps manually load every part of their apps via script tags. Unlike other systems, Angular 'modules' don't take care of actually loading dependencies, they just inject them once already loaded.