Reputation: 73
The problem is that I have lots of HTML templates that include < script > tags with AngularJS code in them. My current project is using Angular 8, and one critical part of it consists basically in usign all the AngularJS templates that I have inside this new project doing as little work as possible (due to the fact that in the future other users will have to be able to add new templates to the project).
I have to be able to add this HTML AngularJS templates to my current project. For that I am using ngUpgrade, but it has been quite misleading and I have not been able o achieve this.
Here is one of the templates, simplified as much as possible for this question:
HTML
<body>
<script>
angular.module('myApp', [])
.controller('myController', function ($scope, $timeout) {
$scope.local = 'es';
BigFunction($scope, $timeout);
});
var texts = {
title: {
en: 'A simple title',
};
// other constanst go here
function BigFunction(scope, timeout) {
scope.texts = texts;
scope.$watch('content', function(end, ini){
// some logic when 'content' changes
}, true);
// more logic
}
<script>
<div>
<!-- Lots of tags using ng-bind and other AngularJS tools -->
</div>
</body>
I have to integrate it touching it as little as possible. I don't know if I should separate the logic of the script from the HTML, or if I could import it as it is right now and work. Take into account that I have no previous experience working with AngularJS, I am an Angular 2+ developer.
If I have to separate the logic from the template, where do I put the angular.module? And the constants?
Upvotes: 3
Views: 4144
Reputation: 284
I recommend the ng-book, it has a full chapter about hybrid apps. Note the UpgradeAdapter in the book is deprecated. But many concepts are still valid.
NgUpgrade is the official package to do what you want.
The first thing you must do is to put the script in a proper file. And not in the HTML. Then you can do serious coding.
You must follow the NgUpgrade doc to make the 2 apps run. https://angular.io/guide/upgrade#bootstrapping-hybrid-applications
you need one bootstrap for AngularJS:
angular.bootstrap(document.body, ['heroApp'], { strictDi: true });
And one bootstrap for Angular 8:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
platformBrowserDynamic().bootstrapModule(AppModule);
You will notice the NgModule has a reference line towards AngularJs.
The code they give is for JIT compilation.
A production build in AOT compilation will look like this:
import { enableProdMode } from '@angular/core';
import { platformBrowser } from '@angular/platform-browser';
const { AppModuleNgFactory } = require('../aot/src/app/AppModule.ngfactory');
enableProdMode();
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
--
You must know a directive in AngularJS corresponds to what is meant by component in Angular 8.
You have 2 options.
inject Angular 8 components in ANgular JS directives
inject Angular JS directives in ANgular 8 components.
I recommend to upgrade ANgularJs Components inside Angular 8 components. Like that in the future you converge towards moving to Angular 8 only.
It will require some work to copy each AngularJS component in an Angular 8 component.
To reduce work, run Angular JS as it is. And put Angular 8 directives outside of the templates of AngularJS.
<div id="angularjs-root"></div>
<div my-unaltereted-angular8-component></div>
It may be I am wrong and you cannot put them deparately. But it is worth a try.
Myself, I inject DOM elements dynamically from Angular8 to a JQuery application. But you cannot do that in AngularJS since it has lifecycle for all nodes. HOwever, with some carefulness, removing change detection rendering for the node, a huge tree of nodes from Angular 8 could be injected in the template of an ANgularJs template, and this wihtout downgrading.
This is what I use.
addComponentToElement({ component, element }: { component: any, element: any }) {
// Create a component reference from the component
const componentRef = this.componentFactoryResolver
.resolveComponentFactory(component)
.create(this.injector);
// Attach component to the appRef so that it's inside the ng component tree
this.appRef.attachView(componentRef.hostView);
// Get DOM element from component
const domElem = (componentRef.hostView as EmbeddedViewRef<any>)
.rootNodes[0] as HTMLElement;
// Append DOM element to the body
element.appendChild(domElem);
// detect changes
componentRef.changeDetectorRef.detectChanges();
}
The AppModule will need to add each component inside entryComponents:
entryComponents: [ InjectedCOmponent1m InjectedCOmponent2]
Upvotes: 2
Reputation: 8292
I would suggest you using Web Components
Basically you would have to wrap the AngularJS application as a Web Component and then import it to your Angular 8 app. You would end up with something like this
<my-angularjs-app></my-angularjs-app>
It could be imported in any component in your Angular 8 application.
There is no official solution on how to do it, but there are good examples there. I would suggest you following this one:
Once you are there scroll down until you see Exposing AngularJS Components As Custom Elements
After you manage to bundle up the AngularJS application as a web component, having the whole application in one script (main.js), you would have to copy it to your Angular 8 app.
angular.json
- Add this to scripts: assets/web-components/my-angularjs-app/main.js
app.module.ts
and add schemas: [CUSTOM_ELEMENTS_SCHEMA]
<my-angularjs-app></my-angularjs-app>
Upvotes: 2