Multiple versions of AngularJS in one page - angularjs

What issues might I experience in having two different versions of AngularJS loaded into one page?
Obviously this seems like a stupid thing to do, but my use case is a page that uses AngularJS incorporating a third-party component that drags in its preferred version of AngularJS.
Update:
Found some info:
https://groups.google.com/forum/#!msg/angular/G8xPyD1F8d0/u1QNDNvcwW4J
https://github.com/angular/angular.js/pull/1535

Angular is really not prepared to co-exist with other version. But it's feasible.
First of all load angular library and make sure that before loading window.angular is empty:
<script src="vendor/angular/1.2.0/angular.min.js"></script>
<script src="app/app2.js"></script>
<script>
var angular2 = angular;
window.angular = null; // here we're cleaning angular reference
</script>
<script src="vendor/angular/1.0.5/angular.js"></script>
<script src="app/app1.js"></script>
<script>
var angular1 = angular;
</script>
Note that each application (app1.js, app2.js) for each version of angular should be loaded immediately after loading angular library.
Each JavaScript file of the application shoud be wrapped in self executing function (function(angular) { ... })(angular). Look at the example of app2.js:
(function(angular) {
angular.module('myApp2', []).
controller('App2Ctrl', function($scope) {
$scope.$watchCollection('[a, b, c]', function() {
console.log(angular.version.full);
});
});
})(angular);
Note that here I'm using $watchCollection which is only available for angular 1.2.x. By providing scope of anonymous function for each file you are forcing application to reach angular property instead of window.angular property.
Finally you have to bootstrap the application using manuall method:
<body>
<div id="myApp1" ng-controller="App1Ctrl">
</div>
<div id="myApp2" ng-controller="App2Ctrl">
</div>
<script>
angular1.bootstrap(document.getElementById('myApp1'), ['myApp1']);
angular2.bootstrap(document.getElementById('myApp2'), ['myApp2']);
</script>
</body>
Working plunker here. After running please check console window to see logged versions of angular used.

Great question! Like you, we were unable to uncover much on this topic...we are in the process of deploying a version of Angular with our product which will be embedded within client websites that could also have Angular already loaded.
Here is what we have done:
Modify the Angular source - do not use "window.angular" or "angular" in your implementation, choose some other variable or object property to house it. If you do use "window.angular" and/or "angular", it could break both applications if the versions are different.
Rename all delivered objects (directives, etc); otherwise, the other version of angular could attempt to process your directives.
Rename all CSS classes used by Angular (ng-cloak, etc). This will allow you to style your version of Angular separately from the other version.
Manually bootstrap your application, as described by 'kseb' above.
If you are going to completely name space AngularJS as I have described here, take care to not do a global search and replace because angular does need a "window" reference for registering events, and a few other places.
I just finished doing this at work and I am in the process of testing. I will update this answer with my results.

Matt Burke describes a process to wrap the Angular JS libs in a function to create a closure. Downside is that you cannot load Angular via a public CDN as you have customized the download.
http://www.mattburkedev.com/multiple-angular-versions-on-the-same-page/

Angular 2 will provide a new router with similar features to UI router, but that will also allow to have some routes in Angular 1 and others in Angular 2.
This router is currently being backported to Angular 1, see here a presentation from the developer of the new router explaining how this will work.
The idea behind a common cross-version router with support for both version is to help users upgrade from Angular 1 to Angular 2.

Related

How to use a directive as an entry point when using angular's bootstrap function?

I have an angular 1 app that's being bootstrapped onto a Java web page (legacy app) using ng-app tags. I'm trying to create a hybrid app using Angular 2's downgrade capabilities.
In order to do this I need to remove ng-app tags and use the UpgradeModule from #angular/upgrade/static and bootstrap using the upgrade.bootstrap(document.body, ['myapp']). However, most of the components of the app, including the entry point of the app, are just plain old angular 1.2 directives.
From the examples I've seen, they are using the controller="MenuCtrl" syntax to add components to the page. Is it possible to use directives as the entry point to the app? e.g.
<div my-menu-directive></div>
Currently, nothing is showing up in the app since I've removed the ng-app tags, but the app is definitely being bootstrapped. I'm just not seeing any of the directives.
Fixed this by wrapping the bootstrap statement in angular.element() like so:
angular.element(function() {
upgrade.bootstrap(document.body, ['myApp'], { strictDi: true });
});

Angular Dynamically Inject Module Dependency

I've developed a commenting plugin for Umbraco that uses angular. As such the main angular app for the site has to inject the comment systems module for it to work.
E.g.
var theirSite = angular.module('someApp', []);
Injected
var theirSite = angular.module('someApp', ['theCommentSystemModule'];
In my comment system,
angular.module('theCommentSystemModule']....;
Is there any way my module can automatically detect the angular app and inject itself without the code for the site having to be updated? I want it to just work with nothing but the script link.
For Example: say these are the scripts
<script src="...angular.js">
<script src="...services.js">
<script src="...directives.js">
<script src="...commentsPlugin.js">
<script src="...theirApp.Js">
So what I basically need, is some kind of callback from angular when the app is being bootstrapped, so I can inject the comment systems module into the app as a depedency module so that it will initialize in their bootstrap layer.
Or maybe, alternatively, I bootstrap the page myself in the plugin for itself? Can there be two apps running at once, e.g. if I bootstrap and their app also bootstrap's .
It can be done by using undocumented requires module property. This way new dependencies can be added to the module after it was defined but before it was bootstapped.
Since 'ng' is the only known and defined module ATM (it also has already defined requires array), tamper it:
angular.module('ng').requires.push('theCommentSystemModule');
Though it is more appropriate to let the users load the module by themselves.

Angular bootstrapping lost

I am working with an existing application that I would like to add angular to. The application is using a custom proprietary SPA framework + dojo. The application is built with mainly dojo modules and heavily utilizes AMD modules.
I have imported angular in the head with
<script type="text/javascript" src="lib/angular/angular.js"></script>
I have also added
<html ng-app="myApp">
<script>
angular.module('myApp', [])
</script>
to my index.html.
I have also tried manually bootstrapping via
var app = angular.module('myApp', []);
angular.element(document).ready(function() {
angular.bootstrap(document, ['myApp']);
});
but still
{{1+1}}
Does not evaluate. It remains as {{1+1}}
The only way I get get it to (sort of) work is in my partial view (rendered inside body of index.html) and I manually bootstrap the application via
var app = angular.module('myApp', []);
angular.element(document).ready(function() {
angular.bootstrap(document, ['myApp']);
});
But as soon as I leave the page and come back, the bootstrapping is gone. {{1+1}} shows as {{1+1}} not 2. If I run the above code again, I get an error saying document is already bootstrapped.
No errors are thrown in console..
I am not sure what to try next. Any help? Thanks
Is the page content dynamic, are the other frameworks adding HTML to the page that has Angular syntax in then you are expecting to be evaluated? If so that is the issue.
Please note that Angular is a fully featured framework and that frameworks generally conflict with each other. For Angular to work you need to add Angular code to the page using Angular APIs, such as ng-include, other directives, or a controller and manually compile the HTML being added.
When is the partial view actually rendered?
Unless you actually pass the partial through Angular's $parse service (which happens automatically on bootstrap), Angular can't evaluate the expressions. So, if you are adding the partial to the DOM after the bootstrap, Angular will never process it.
using dojo, you would need to pass the content through the $parse service first, i.e.:
require(["dojo/html"], function(){
content = $parse(someAngularContent);
html.set(node, content);
});

Can not open datepicker in angularjs using bootstrap UI

Hello I am using UI Bootstrap for displaying datepicker in my app.
this is my reference order:
<!--ANGULAR CORE-->
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.18/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.18/angular-route.min.js"></script>
<!--APPLICATION INIT-->
<script src="app/js/app.js"></script>
<!--JQUERY-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<!--BOOTSRAP UI-->
<script src="app/js/libs/ui-bootstrap-tpls-0.11.0.min.js"></script>
I use the tpls version because it supposes to include the templates.
I inject the dependency like that:
angular.module('globapp', ['ngRoute', 'ui.bootstrap'])
when I try to popup the datepicker it doesn't show. In the chrome developer I can see that the code searches for template folder, and I recieve 404 error (datepicker.html, popup.html).
I searched about that in the internet, and everyone tells the same thing: if I use the tpls version, it should provide me the default templates.
thanks
Your app.js has your app init -so that's where your creating your angular module and are hoping to inject bootstrap-ui as a dependency but that script hasn't been loaded yet as it's last in the list.
This would be the first thing to check. Load your scripts in order of least dependent first so jquery first then your core angular, then your plugin libraries and then your app scripts.

angularjs how to set <script src="controller"> depending on the route in the index.html

I have been working on an angular.js app that is growing wit many controllers,
all of the files are included in the index.html file, even if the current view does not use one of them, this apply to providers and other modules too.
how do i call only the controller that is needed depending on the routes, in the index.html?
i have an index.html file with the many script tags:
<script src="controller1.js"></script>
<script src="controller2.js"></script>
<script src="controller3.js"></script>
Update:
A better explanation of the question + answer.
http://weblogs.asp.net/dwahlin/archive/2013/05/22/dynamically-loading-controllers-and-views-with-angularjs-and-requirejs.aspx
What you are looking for is asynchronous modules and a loader that can pull them from the server. RequireJS is the first one that springs to mind. A seed project with examples of how to marry RequireJS and AngularJS can be found here.
You should let angular handle it for you, based on the route or url. you best option is to look at the routeProvider, the documentation is here.
usage looks like this:
$routeProvider.when('/Book/:bookId/ch/:chapterId', {
templateUrl: 'chapter.html',
controller: ChapterCntl
});
Another option would be using Ui router, which is an extension of the routeprovider. here is the project page.

Resources