3

Using the process outlined here, I'm trying to inject Angular 1 services into an Angular 4 app. The app is bootstrapped in hybrid mode (and works as I have some Angular 4 components and services running).

Whenever I try to inject the Angular 1 service, I get Cannot read property 'get' of undefined.

upgraded-providers.ts:

import {LinksService} from "./+services/links/links";

export function linksServiceFactory(i: any) {
  return i.get('bfLinksService');         // <--- Errors here!
}
export const linksServiceProvider = {
  provide: LinksService,
  useFactory: linksServiceFactory,
  deps: ['$injector']
};

My Angular 4 service which is trying to use LinksService looks like:

@Injectable()
export class EntityService {

    constructor (
        private http: Http,
        private links: LinksService
    ) {

    }

    get(id: string): Observable<OrgDetails> {
        // Do something
    }
}

And finally LinksService (the Angular 1 service, written in Typescript) looks like:

export class LinksService {

    static $inject = ["$log", "$location", PROPERTIES_SERVICE];

    private contentHost : string;
    private thisAppHost : string;

    constructor (private $log : ng.ILogService, private $location : ng.ILocationService, private props : IPropertiesService) {
        this.init();
    }

    // Service functions elided
}

The bootstrap and module stuff:

@NgModule({
    imports: [
        BrowserModule,
        HttpModule,
        UpgradeModule,
    ],
    declarations: [
        AppComponent,
        OrgSummaryComponent,
    ],
    providers: [
        EntityService,
        linksServiceProvider
    ],
    bootstrap: [
        AppComponent,
    ],
})
export class AppModule {
    ngDoBootstrap() {
        // Does nothing by design.
        // This is to facilitate "hybrid bootstrapping"
    }
}

platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
    const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
    upgrade.bootstrap(document.body, [AppModuleName], {strictDi: false});
});

The Angular 1 (legacy) stuff all works fine.

It seems like Angular cant find the $injector, but shouldn't that be there regardless?

Many thanks for any suggestions, Jeff

jeffeld
  • 125
  • 1
  • 10
  • Why don't you just rewrite it in angular 4? – Mike Tung May 09 '17 at 12:55
  • This is just part of a large and complex app. A big bang rewrite isn't an option right now (time/resource constraints). – jeffeld May 09 '17 at 12:58
  • Hello, do you have imported UpgradeModule at Angular module declaration, where you have registered linksServiceProvider? – Stanislav Šolc May 09 '17 at 12:59
  • Just edited the question to include. Thanks for pointing it out. – jeffeld May 09 '17 at 13:02
  • It's a hard question for me By the way, may I ask how is your experience with Angular >1? (I mean after 2 version) Do you like it more than Angular 1? – Mohammad Kermani May 09 '17 at 13:07
  • This is my first foray into Angular 4 (I skipped 2 because of the long beta and churn it had). Angular 1... must be at least 5 years now. This project is to see if there is a reasonable upgrade path from 1 to 4, and if we should start to use 4 for new features and migrate all the code base in the medium term. So far, it's making me nervous. – jeffeld May 09 '17 at 13:10
  • Maybe you can check whether AngularJS core was bootstraped at first. You should have somewhere in index script element with reference to AngularJS asset, check whether createInjector function is executed – Stanislav Šolc May 09 '17 at 13:42
  • Not too sure what you're asking me there. If I don't try to inject the Angular 1 service, everything works fine and I get a page which is a mixture of seperate Angular 1 components, services, directives and filters AND seperate Angular 2 compoents and services. Where is all craps out is trying to use (as described in the documents) an Angular 1 service in an Angular 2 component. – jeffeld May 09 '17 at 14:09
  • Hi, as i understand hybrid Angular application, you have to have script tag somewhere in the index.html file with reference to Angular.js external script. Inside the angular.js file is bootstrap function, which call internal functions createInjector or createInternalIjector, these functions must be executed for proper bootstraping of AngularJS environment. I think Angular.js bootstrap is called when you call upgrade.bootstrap, check it by debugger – Stanislav Šolc May 09 '17 at 15:22
  • Ah, ok. I have both versions of Angular in a Webpack vendor bundle. Well check when back in office tomorrow. – jeffeld May 09 '17 at 16:46

2 Answers2

3

Two days of my life I won't get back but...

Just found this:

https://github.com/angular/angular.io/issues/3317

Basically the documentation is wrong. By adding a constrcutor to the app module with the call to upgrade.bootstrap in it, everything works.

export class AppModule {

    constructor(upgrade: UpgradeModule) {
        upgrade.bootstrap(document.body, [AppModuleName], {strictDi: true});
    }

    // Does nothing by design.
    // This is to facilitate "hybrid bootstrapping"
    ngDoBootstrap() {}
}

platformBrowserDynamic().bootstrapModule(AppModule);

Thank you to those who responded.

jeffeld
  • 125
  • 1
  • 10
  • 1
    Wait does this work for using AngularJS services inside Angular services? I got it to work for Angular components, but keep getting the error for Angular services – Andrew Luhring Aug 11 '17 at 21:55
0

Actually the better way to instantiate AngularJS is after:

platformBrowserDynamic().bootstrapModule(AppModule)
  .then(platformRef => {
    const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
    upgrade.bootstrap(document.body, ['app'], { strictDi: false });
  })
  .catch(err => console.log(err));
David Good
  • 21
  • 2