Run multiple Angular app in One page - javascript

Assuming there is already an existing angular running in the page. I would like to inject/add an isolated angular app into it (which runs in isolation with the existing angular app without interference).
For example, I would like to 1) insert a custom element say <app-root-two></app-root-two> in the page then 2) initialise/bootstrap that app (or vice versa).
How would I go about achieving this?
I know back in AngularJs it is possible because you can retrieve the DOM element and use angular.boostrap(<dom-element>) to initialise it but I don't think Angular has the same manual bootstrapping pattern. It is abstracted and it goes directly to DOM to find the root element, typically <app-root> in the page.
The current angular version I am working with is version 5.2 and Angular CLI 1.6.6. I have tried the .angular-cli.json file for generating multiple app however it targets two separate "index.html" files, that is two app in one project, not necessarily in one page.

You need a different root element on your second AppModule. Then simply import your second app scripts (runtime, styles, etc) but delete window.webpackJsonp first.
For example
<app-one></app-one>
<app-two></app-two>
<script type="text/javascript" src="app-one/runtime.js"></script>
<script type="text/javascript" src="app-one/es2015-polyfills.js" nomodule></script>
<script type="text/javascript" src="app-one/polyfills.js"></script>
<script type="text/javascript" src="app-one/styles.js"></script>
<script type="text/javascript" src="app-one/vendor.js"></script>
<script type="text/javascript" src="app-one/main.js"></script>
<script>delete window.webpackJsonp</script>
<script type="text/javascript" src="app-two/runtime.js"></script>
<script type="text/javascript" src="app-two/es2015-polyfills.js" nomodule></script>
<script type="text/javascript" src="app-two/polyfills.js"></script>
<script type="text/javascript" src="app-two/styles.js"></script>
<script type="text/javascript" src="app-two/vendor.js"></script>
<script type="text/javascript" src="app-two/main.js"></script>
Though - to date - this works, the framework is clearly not designed for this. More complex apps with further chunking may have issues with the app's runtime that you're essentially changing when deleting webackJsonp object.
Polyfills that go to the global prototypes you may be able to skip reimporting.

Take a look at overall-structural-guidelines
You can simply load one app but orchestrate ( lazy load ) many different modules that would behave as Apps. Each sub major module would have all the modules, services, components etc that it needs and it would be isolated.

Upon looking into the source code, I had to do a bit of override. AngularJs does two things automatically: 1) bootstrap any "ng-app" 2) add a tag. To prevent any conflict. I commented both bits out. Instead I took the content of tag and placed it in my scss file and bootstrap my custom element manually
The other thing is Angularjs is loaded within the context of chrome extension content script therefore any window global defined directly in the content script will not bleed to the user page.
On top of that, I did use shadow dom to further isolate the application so that no css/js thing bleed in/out. As long as I don't modify any common aspects of the page I should be fine, e.g. location. Any global events binding I need to add/remove based on the lifecycle. The end result would look something like this:
<custom-element>
#shadow-dom
<!-- stylesheet if any -->
<!-- js script if any -->
<bootstrapped-angular-element>

Related

Next JS Script Component Vs normal script tag with async and defer

What's the difference between next js <Script /> component rendering strategies (afterInteracive, beforeInteractive, lazyLoad) and using normal <script /> tag with async and defer?
afterInteractive, beforeInteractive and lazyLoad handles script and decide when it's loaded (from docs). It also differ in 'place' where it loads the script. beforeInteractive loads your script in <head> of your project. afterInteractive loads your script in <body> of your project.
Basically, it's just Nextjs way to handle scripts in your app. Main difference is that you should not use script tag in head (in Nextjs) but place it anywhere else and use right strategy so Nextjs knows where to place it.

How to include an Angular app dynamically into the DOM?

We created a widget as an Angular app, which our customers should be able to easily load and integrate into their own website.
The most straightforward way (which works) to do this is simply to tell them to include the default HTML tags from the index.html on their website:
<base href="/">
<app-root></app-root>
<script src="https://ourdomain.com/widget/runtime.js" type="module"></script><script src="https://ourdomain.com/widget/polyfills.js" type="module"></script><script src="https://ourdomain.com/widget/main.js" type="module"></script>
However, we would like to minimize the above code and provide them a one-liner which includes a JavaScript that loads the code dynamically into the DOM, e.g. <div id="widget"></div><script src="https://ourdomain.com/widget/start.js"></script>. The script would simply consist of:
<script>
document.getElementById('widget').innerHTML = '<base href="/"><app-root></app-root>...';
</script>
The tags are loaded correctly into the DOM but the Angular app i.e. the scripts which are dynamically included into the DOM don't load.
How can this problem be solved? Is there a method in main.js which needs to be called additionally to bootstrap the Angular app?
The Angular app is deployed and hosted on our server, e.g. on https://ourdomain.com/widget. The goal is that anyone can load and plug the app into their own website using the above approach.
It turned out to work just like that:
<script>
document.write('<base href="/"><app-root></app-root>...');
</script>

angular2 binding applies only after mouse movement

I'm a new angular2 development and currently facing a rendering issue with my application. I use #angular#2.0.0-rc.1 for my app and router-deprecated#2.0.0-rc1 for my routing, whenever I click on the a link, the static content of the page loads immediately and the binding (dynamic content) happens only when I do some interaction with the mouse like click or hover over a link. I tried various options and still couldn't figure it out.
Any help would be appreciated.
The order in which you include the JS files is important.
This issue happened when I didn't.
<script src="/lib/shim.min.js"></script>
<script src="/lib/system.js"></script>
<script src="/lib/system-polyfills.js"></script>
<script src="/lib/Reflect.js"></script>
<script src="/lib/zone.js"></script>
As mentioned by bryanm, the order of the js files is important and the placement of those script tags also matters. In my environment with angular2.rc.4, the order was
<script src="node_modules/es6-shim/es6-shim.js">
<script src="node_modules/reflect-metadata/Reflect.js">
<script src="node_modules/systemjs/dist/system.src.js">
<script src="node_modules/zone.js/dist/zone.js">
It has to be placed at the end of the body tag just above loading the systemjs config script.

Why won't AngularJS work with multiple defer scripts?

I have the following at the bottom of my HTML:
<script defer="defer" src="http://localhost:8080/bower_components/jquery/dist/jquery.min.js"></script>
<script defer="defer" src="http://localhost:8080/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script defer="defer" src="http://localhost:8080/apps/promotion/active.js">
// "Gulped" angular, ngAnimate, ui.bootstrap, and my angular app; in that order.
</script>
</body>
</html>
At random times, I will get this error when I refresh the page:
Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.4.9/$injector/modulerr?p0=activePromos&p1=Err…20(http%3A%2F%2Flocalhost%3A8080%2Fapps%2Fpromotion%2Factive.js%3A1%3A7124)
Sometimes it will happen for multiple refreshes in a row, and sometimes it will work for multiple refreshes in a row. Nevertheless, there are times when I get the error and it's getting annoying.
What I found out is the following: If I remove the jquery and bootstrap scripts so that I only have the one script (active.js) with the defer attribute, it always work. I am trying to load the scripts after the page is done loading in the specified order.
Should I be doing this a different way (requirejs?)? I assumed using defer and putting the scripts in order would help since I've done it before, but not with AngularJS. I am mainly trying to take advantage of parallel downloads from the browser instead of having one huge JS file, since the page only has 1 image and 2 CSS files.
The angular app will not be able to initialize properly until after all of the required JavaScript files are loaded.
Since you are deferring the load of those files, you will need to wait until all of the files are loaded, and then manually initialize the app using AngularJS's bootstrap function.

Is it possible to put AngularJS Controllers into multiple files whilst avoiding loads of script tags in the HTML file?

I have been reading some answers and Brian Ford about how to break out my controllers into multiple files so I can keep everything a bit more organised and easy-to-find.
I am somewhat new to all of this, and just can't get my head around something.
If I create Controller1.js, Controller2.js, Controller3.js, etc, do I need to then have Script tags in my HTML file for each one e.g.:
<script src="app/js/base.js"></script>
<script src="app/js/app.js"></script>
<script src="app/js/config.js"></script>
<script src="app/js/services.js"></script>
<script src="app/js/controller1.js"></script>
<script src="app/js/controller2.js"></script>
<script src="app/js/controller3.js"></script>
... and so on for all 57 controllers I have?
I'm building an app using a theme and it comes with an example. In it he has
<script src="app/js/base.js"></script>
<script src="app/js/app.js"></script>
at the bottom of his index.html file - and that's it. There's reference to Gulp and Grunt, but I'm not familiar with these tools. I've also stumbled into RequireJS. Head spinning about which way to go.
Any pointers or can anyone explain in a bit more dumb-ass friendly language how this is done?

Categories

Resources