How to include an Angular app dynamically into the DOM? - javascript

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>

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 add my angular app in another simple web pages?

I want to integrate my angular app in many others simple web pages, but without iframe
In the next code we see a simple and external html web page called "Shoes Store".
"Shoes Store" is a web that sells shoes. And my goal is in <div id="my-angular-app"></div> to add my entire my-angular-app in that div.
As you can see, first, we need a async petition for then instantiate in a varible the my-angular-app.
The goal is to do something like next html. See how my-angular-app is called async
<!doctype html>
<html lang="en">
<head>
<!--external web page-->
<title>Shoes Store</title>
</head>
<body>
<div id="my-angular-app"></div>
<script async src="http://localhost:4201/my-angular-app.min.js?secret=abcdfg"></script>
// see how myAngularApp is instanciated (many times as you want)
<script>
myAngularApp = new MyAngularApp(document.getElementById('my-angular-app'), {
someParams: {x: 'x', y: 'y'},
otherParams: 1
});
</script>
</body>
</html>
As you can see, I want implement the same architecture of google maps api, but with my angular app.
Imagine that you are the owner of google-maps and no are implementations yet, and the goal is implement the same way as nowsdays works, but with a angular-app.
the result will most something like this:
see this diagram
page1, page2, page3 can integrate to my-angular-app and they can instantiate all entire app, many times using javascript, instead iframe tag
Please, the next implementations are inviables:
No iframe
No angular elements
No Webpack 5 Module federation
someone have an example to integrate this ?
very much apreciated
Currently Angular is not terribly well fitted for that use case. But you can build an angular element and bundle the required other dependencies.
The "element" represents the application root element, but you can have additional compenents, even routing, down the component tree as usual. (You have a root element in every angular app, as well.)
Here is an example repository that shows how to build and embed the element: https://github.com/trion-development/corona-covid19-simulator
The interesting part is the concatenation of all dependencies in https://github.com/trion-development/corona-covid19-simulator/blob/master/package.json#L12

Run multiple Angular app in One page

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>

ReactJs external JavaScript files not working

I'm using a external JavaScript library called Masonry (Cascading grid layout library) https://masonry.desandro.com/.
I have created a demo page using this library and everything seems to work fine, However once i incorporate this library in a React app it doesn't work.
Scripts
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://unpkg.com/masonry-layout#4/dist/masonry.pkgd.min.js"></script>
<!-- <script src="../src/assets/js/JQuery/masonry.js"></script> -->
<script>
$(window).on('load', function(){
var $content = $('.content-container').masonry({
// options
itemSelector: '.masonry',
percentPosition: true,
singleMode: true
});
$content.imagesLoaded().progress( function() {
$content.masonry('layout');
});
console.log('Works!')
});
</script>
</html>
I have tried two methods, adding an external JavaScript file masonry.js and adding the code in a script tag within the index.html page. whenever i use the external JavaScript file it doesn't work at all (the console.log('Works!') doesn't even show in the console). But if i use the code within the Script tag in the index.html page the masonry works occasionally if i do a few page refreshes and the console.log('Works!') shows up in the console every time.
I'm not sure if its because Reactjs has a different way in adding external JavaScript libraries / files, but i have searched online what is the correct way to set up external JavaScript files in a react app and it came up with multiple methods so i'm kind of confused to witch is the correct / best.
Also i have checked the Network in the browser developer tools and the external library / JS file imports seems to be loading in fine.
Just a note: the .content-container child elements change on button clicks in the Reactjs but not in the demo page.

Dynamically adding and removing javascript/css with Jquery (or other library)

I am trying to compare having a 1 page app with clientside routing to having a asp mvc app which just routes to html files, to see which is more appropriate for my current project. As I have no need for any Asp Mvc features its all javascript/html which communicates with a web service.
However one problem I can forsee with the one page app is that my site isnt really 1 page, so I would be having to have on main index.html which contained all shared resources. Then dynamically load in new pages based on the hashbang and add in any required scripts and css. This doesn't seem to hard as Jquery I believe provides a .load() method or something similar to get external resources... my problem though is getting rid of them once I am done...
Is there any way to do this, so you target ONLY certain script/link tags, can you give them Ids or something?
Any help on this would be great...
== EDIT ==
Added a simple example to show what I mean:
<!-- Script already in page -->
<script type="text/javascript" src="scripts/script1.js"></script>
<!-- Dynamically added script -->
<script type="text/javascript">
// some javascript
</script>
How can you tell which ones you should remove? If you could apply an id or uniqueness to each script then it may be ok, but thats what i am getting at with this question.
There are zero benefits to "removing resources." When a script has been loaded, removing the script tag from the page later has no purpose--it won't improve your browser performance at all, nor will it harm it to keep the files around.
Simply add your resources as needed and write your code such that it won't execute erroneously.
I'm not shre i understand why you would like to do that but link element (for css) and script (for js) are elements like any other and they can be deleted with remove().

Categories

Resources