Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sub app be injected global service is an error #123

Closed
HsienW opened this issue Aug 24, 2020 · 3 comments
Closed

Sub app be injected global service is an error #123

HsienW opened this issue Aug 24, 2020 · 3 comments

Comments

@HsienW
Copy link

HsienW commented Aug 24, 2020

Hi Planet team

It's so sorry to bother you, but I'm confused by this library although these questions may not all come from it, and I have not found an answer. May i get some help.

I have a difficult case which was organized from an old angularjs and angular8, besides it's was also limited in the extensive refactoring to resolve in code of micronization.

Issue:

When I installed planet for it, it was up and running, I get this error message.
image

I have tested this way of writing under angularjs and angular8 code without planet library, it can work, but after using planet, the aforementioned error occurred.

After searching, it was found that the reasons for this error message are known as the following 6 types:

  1. Barrel index
  2. Circularity dependency
  3. Forgot to enable polyfills import'core-js/es6/reflect'
  4. Injectable decorator incorrect usage (EX: missing @ or capital & lower case error etc...)
  5. Tsconfig does not configure emitDecoratorMetadata
  6. Decorate parameter type use any in your constructor

The first 5 have been excluded, I suspect it is the last, because of this Configuring Dependency Injection in Angular
But I am confused, whether a certain configuration of planet causes parameter type to fail?

Code Structure:

1. There is a common service exported from angularjs

(File name: angular1-root-module.js)

(function () {

  angular.module('angular1', [
    'angular1.export-service'
  ]);

  angular.module('angular1.export-service', []);

  angular.module('angular1.export-service').factory('Angular1ExportService', Angular1ExportService);

  Angular1ExportService.$inject = [];

  function Angular1ExportService() {
    function outPutString() {
      return 'I from Angular1 export service string';
    }
    return {
      outPutAngular1String: outPutString,
    };
  }
})();

2. Inject into the class named Angular1InjectorService through the factory provider and depend on angularjs's $injector

export function Angular1InjectorServiceFactory(injector: any) {
  return new Angular1InjectorService(injector);
}

export const Angular1InjectorServiceProvider = {
  provide: Angular1InjectorService,
  useFactory: Angular1InjectorServiceFactory,
  deps: ['$injector']
};
@Injectable()
export class Angular1InjectorService {

  // I think probably this injector of type is any cause
  constructor(private angular1Injector: any) {
  }

  getService(serviceName: String) {
    return this.angular1Injector.get(serviceName);
  }
}

3. Then inject into the common AppBaseService

@Injectable()
export class AppBaseService {

  readonly angular1InjectorService: Angular1InjectorService;
  readonly testService: any;

  constructor(readonly injector: Injector) {
    this.angular1InjectorService = this.injector.get(Angular1InjectorService);
    this.testService = this.angular1InjectorService.getService('Angular1ExportService');
  }

  testGetAngular1String() {
    console.log('app base service is work!');
    return this.testService.outPutAngular1String();
  }
}

4. Then the service of the sub app inherits AppBaseService, and obtains the method that exists in angularjs

export class App1RootService extends AppBaseService {

  constructor(readonly injector: Injector) {
    super(injector);
  }

  GetLogAngular1String() {
    console.log('app1 root service is work!');
    return this.testGetAngular1String();
  }
}

5. portal root planet config

    this.planet.registerApps([
      {
        name: 'app1',
        hostParent: '#app-host-container',
        routerPathPrefix: '/app1',
        selector: 'app1-root-container',
        resourcePathPrefix: '/static/app1',
        preload: settings.app1.preload,
        switchMode: settings.app1.switchMode,
        loadSerial: true,
        manifest: '/static/app1/manifest.json',
        scripts: [
          'main.js'
        ],
        styles: [
        ],
      }
    ]);

6. sub app1 main config

defineApplication('app1', (portalApp: PlanetPortalApplication) => {
  return platformBrowserDynamic([
    {
      provide: PlanetPortalApplication,
      useValue: portalApp
    },
    {
      provide: AppRootContext,
      useValue: portalApp.data.appRootContext
    }
  ])
    .bootstrapModule(App1RootModule)
    .then(appModule => {
      return appModule;
    })
    .catch(error => {
      console.error(error);
      return null;
    });
});

Issue related resources:

EXCEPTION: Can't resolve all parameters
Uncaught Error: Can't resolve all parameters for
After upgrade Angular to v8: Can't resolve all parameters for Component:

Intact issue code:

Stackblitz
Github

hope you could give me solution, and thanks for your hospitable help

Sincerely planet user.

@why520crazy
Copy link
Member

why520crazy commented Aug 28, 2020

I guess it's because only import UpgradeModule and bootstrap ng1 in the portal, so the $injector service of NG1 can only be used in portal, for a deeper understanding, need to look at the mechanism of @angular/upgrade/static.

The simple solution is:

  1. remove Angular1InjectorService from app1 's provider
  2. inject Angular1InjectorService in portal's root app component, set angular1InjectorService to global data by this.planet.setPortalAppData method:
this.planet.setPortalAppData({
      appRootContext: this.appRootContext,
      angular1InjectorService: this.angular1InjectorService
    });
  1. add Angular1InjectorService provide in app1's main.ts, use global(portal) angular1InjectorService value
defineApplication('app1', (portalApp: PlanetPortalApplication) => {
  return platformBrowserDynamic([
    ...
    {
      provide: Angular1InjectorService,
      useValue: portalApp.data.angular1InjectorService
    }
    ...
  ])
    .bootstrapModule(App1RootModule)
    .then(appModule => {
      return appModule;
    })
    .catch(error => {
      console.error(error);
      return null;
    });
});

@HsienW
Copy link
Author

HsienW commented Aug 28, 2020

@why520crazy Your solution is work and it's well done, thank you very much!

@why520crazy
Copy link
Member

@why520crazy Your solution is work and it's well done, thank you very much!

you are welcome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants