2

I've got a working rails 5.2.0 webpacker app, with a minimal angularjs app booted through the angular AppModule, using UpgradeModule.bootstrap function.

I confirmed the angular app works fine before turning it into a hybrid app. And after initially adding a simple angularjs hybrid booted module, the angularjs booted module is running fine.

I'm now trying to use downgradeComponent to hang an angular component within the booted angularjs root template, following the docs here:

https://angular.io/guide/upgrade#using-angular-components-from-angularjs-code

What do I need to do to ensure the ComponentFactoryResolver is provided to the angular module?

The angular module is still booting the angularjs module, which is still working, but the directive using the downgradeComponent function is failing with a console message suggesting that the angular AppModule where the component is declared does not have a provider for ComponentFactoryResolver.

angularjs:14961
Error: StaticInjectorError(AppModule)[ComponentFactoryResolver]: 
  StaticInjectorError(Platform: core)[ComponentFactoryResolver]: 
    NullInjectorError: No provider for ComponentFactoryResolver!
    at _NullInjector.get (core.js:1003)

Here's the angular module booting the angularjs module, and providing the entry point for the HelloAngularComponent to be used with downgradeComponent. The error is pointing at this angular (v5) typescript file:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { UpgradeModule } from '@angular/upgrade/static';

import { HelloAngularComponent } from './hello_angular.component';

@NgModule({
  declarations: [
    HelloAngularComponent
  ],
  entryComponents: [
    HelloAngularComponent
  ],
  imports: [
    BrowserModule,
    UpgradeModule 
  ],  
  providers: [],
})
export class AppModule {
  constructor(private upgrade: UpgradeModule) { }
  ngDoBootstrap() {
    this.upgrade.bootstrap(document.body, ['hello_angularjs'], {strictDi: true});
  }
}

And here is the hello_angularjs/index.ts module being bootstrapped:

import angular from 'angular';
import uirouter from '@uirouter/angularjs';
import { HelloAngularComponent } from '../hello_angular/app/hello_angular.component';
import { downgradeComponent } from '@angular/upgrade/static';

angular.module('hello_angularjs', [uirouter])
  .controller('LoginMessage', ['$scope', function($scope) {
    'ngInject'; 
    $scope.message = 'Hello Angularjs';
  }])
  .config(['$stateProvider', ($stateProvider) => {
    'ngInject';
    $stateProvider
      .state('home', {
        url: '/',
        template: `<h1>hello_angularjs home template.</h1>
        <hello-angular>Loading Angular component downgraded to angularjs...</hello-angular>`
      })
  }])
  .directive(
    'helloAngular',
    downgradeComponent({ component: HelloAngularComponent }) as angular.IDirectiveFactory
  );

And the simple component being downgraded:

import { Component } from '@angular/core';

@Component({
  selector: 'hello-angular',
  template: `<h1>Hello {{name}}</h1>`
})
export class HelloAngularComponent {
  name = 'Angular (v5)!';
}   
Anatortoise House
  • 4,941
  • 1
  • 22
  • 18

1 Answers1

0

One solution I found was to move the angularjs booted module into the same webpack bundle as the angular 5 module.

With webpacker, that was as simple as removing app/javascripts/packs/hello_angularjs.js and instead importing both hello_angularjs and hello_angular index.ts files into the same pack defined by app/javascript/packs/hello_angular.js

import '../hello_angularjs'
import '../hello_angular'

I could have also just merged the angularjs module and directive calls to the same app.module.ts file where the @NgModule code lives.

Anatortoise House
  • 4,941
  • 1
  • 22
  • 18