Nobita Gascón
Nobita Gascón

Reputation: 73

How to add this AngularJS HTML template to my Angular 8 project

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

Answers (2)

Thierry Vilmart
Thierry Vilmart

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

Dino
Dino

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:

UPGRADING WITH WEB COMPONENTS: FROM ANGULARJS TO ANGULAR

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.

  1. In your Angular 8 app, create folder assets/web-components/my-angularjs-app
  2. Copy the file you generated from AngularJS (main.js) to a folder you just created
  3. Import the file in angular.json - Add this to scripts: assets/web-components/my-angularjs-app/main.js
  4. Your AngularJS app is now imported but there is one more thing we have to do before you can use it in your components. You have to let Angular know that there will be some selectors which Angular might not be aware of. To do this, go to your app.module.ts and add schemas: [CUSTOM_ELEMENTS_SCHEMA]
  5. You can now use your AngularJS app anywhere you prefer by using the selector you declared (This part is in the link I posted). <my-angularjs-app></my-angularjs-app>

Upvotes: 2

Related Questions