Skip to content

Tracking: AppModules #9726

Closed
Closed

Description

@tbosch

AppModules introduce a way to group providers, platform directives/pipes and component factories on a higher level than components.

See this design doc for details.

This issue tracks the progress

  • main implementation
  • adjust bootstrap to use it
  • adjust bootstrap for web workers and server platform to support modules
  • create AppModules for web workers and server
  • testing support
  • define FormsModule and RouterModule
  • support for calculating precompile based on providers (needed for the router), so called ANALYZE_FOR_PRECOMPILE
  • deprecate:
    • ComponentResolver and SystemJS based implementations
      • needs (done): router supports ComponentFactoryResolver, precompile and ANALYZE_FOR_PRECOMPILE token`
      • @vsavkin
    • coreBootstrap / coreLoadAndBootstrap
      • needs (done): converting all platforms to modules)
    • providers arrays in platform-browser / platform-browser-dynamic / core/src/application_ref
      • needs (done): converting all platforms to modules)
    • old way of setting platform pipes / directives
      • needs (done): forms and router have app modules
      • console.log in CompilerConfig constructor when non empty pipes / directives are passed in
      • deprecate the symbols for PLATFORM_DIRECTIVES / PLATFORM_PIPES
        is called eagerly.

Activity

  1. added this to the Angular 2 Final milestone on Jun 30, 2016
  2. b-strauss commented on Jul 3, 2016

    @b-strauss

    Could this be used to bundle css that should only be usable and scoped to components inside an app module? For example, commonly used flex styles.

  3. tbosch commented on Jul 6, 2016

    @tbosch
    ContributorAuthor

    @b-strauss Sorry, that is not planned yet.

  4. 9 remaining items

  5. playground commented on Jul 12, 2016

    @playground

    @tbosch with the latest build, how can we bootstrap with custom selector?

    ComponentResolver is deprecated for dynamic compilation. Use ComponentFactoryResolver together with @AppModule/@Component.precompile or ANALYZE_FOR_PRECOMPILE provider instead.

  6. tbosch commented on Jul 26, 2016

    @tbosch
    ContributorAuthor

    We don't have a nice API for this yet, sorry.

    But you can do the following, please read this doc (http://g.co/ng/modules) to understand the concepts before.

    @NgModule({
      imports: [BrowserModule],
      declarations: [MainComponent],
      entryComponents: [MainComponent]
    })
    class MainModule {
      constructor(injector: Injector, cfr: ComponentFactoryResolver, appRef: ApplicationRef) {
        const mainCompFactory = cfr.resolveComponentFactory(MainComponent);
        const compRef = mainCompFactory.create(injector, [], 'myCustomSelector');
        appRef.registerChangeDetector(compRef.changeDetectorRef);
      }
    }
    

    I.e.

    1. create a module that lists the component as an entryComponent
    2. get the ComponentFactory from the ComponentFactoryResolver
    3. create the component
    4. register it in ApplicationRef via the private API ApplicationRef.registerChangeDetector so that the component gets dirty checked
  7. tom-mayer commented on Aug 30, 2016

    @tom-mayer

    @tbosch would it be possible to forward paremeters into the constructor? I only know the elements I want to initialize the component on at runtime (html is fetched via ajax). Probably call something like:
    platformBrowserDynamic().bootstrapModule(MainModule, {selector: 'someSelector'});
    when the html is in the dom and then use the 'selector' parameter in the constructor, as you described.

    From what I can see right now boostrapModule does not allow to forward parameters to the module constructor, is that correct? Would you know a way to work around this until there is an API for this?

  8. tbosch commented on Aug 30, 2016

    @tbosch
    ContributorAuthor

    you can always store data in a top level variable in a module...

    On Tue, Aug 30, 2016 at 9:17 AM Tom Mayer [email protected] wrote:

    @tbosch https://github.com/tbosch would it be possible to forward
    paremeters into the constructor? I only know the elements I want to
    initialize the component on at runtime (html is fetched via ajax). Probably
    call something like:
    platformBrowserDynamic().bootstrapModule(MainModule, {selector:
    'someSelector'});
    when the html is in the dom and then use the 'selector' parameter in the
    constructor, as you described.

    From what I can see right now boostrapModule does not allow to forward
    parameters to the module constructor, is that correct? Would you know a way
    to work around this until there is an API for this?

    —
    You are receiving this because you were mentioned.
    Reply to this email directly, view it on GitHub
    #9726 (comment),
    or mute the thread
    https://github.com/notifications/unsubscribe-auth/AAqKf1SM5iXw03lU2zi5iV6bAdOvNKIwks5qlFZugaJpZM4JCUve
    .

  9. tom-mayer commented on Aug 31, 2016

    @tom-mayer

    @tbosch thanks for the pointers, after digesting your answer I noticed that I didn't even need a custom selector when using the approach you described!

    For some context, I tried to instantiate multiple instances of the same root component.
    http://stackoverflow.com/questions/39231943/multiple-instances-of-the-same-root-application-in-angular-2

  10. tom-mayer commented on Sep 1, 2016

    @tom-mayer

    @tbosch Out of curiosity, you snippet worked fine in the constructor of the module. However when I put it into ngOnBootstrap of the module, it didn't start the component lifecycle (breakpoint in ngOnInit of the comonent). I also tried it as a separate method to dynamically attach components to the DOM, are there any additional steps required to start the component?

  11. tbosch commented on Sep 2, 2016

    @tbosch
    ContributorAuthor

    Not that I know of...

  12. tom-mayer commented on Sep 2, 2016

    @tom-mayer

    Interesting, if I wrap it into a zone.run in ngDoBootstrap it works just fine. A well,... thanks for the great work so far on angular2 !

  13. diestrin commented on Sep 6, 2016

    @diestrin
    Contributor

    Hey @tbosch, following @playground question about custom selectors, I have created a code to dynamically bootstrap modules in my page (we have a custom set up that lazy load the components as they apear in the screen).

    This code works fine and do the task, but I have a problem, when I include an NgModule in the imports of one of the bootstrapped modules, the injector doesn't recognize the services declared in the imported module. Only if I include the NgModule (the one with a service) in the root module, it gets injected correctly.

    Here's a summary of the code that bootstraps with custom selector

    @NgModule({
      providers: [SystemJsNgModuleLoader],
      imports: [BrowserModule]
    })
    class AppModule {
      ngDoBootstrap() {}
    }
    
    const modulePath = './src/test#TestModule';
    const moduleSelector = '#testId';
    
    platformBrowserDynamic()
    .bootstrapModule(AppModule)
    .then(appModule => {
      const ngModuleLoader = appModule.injector.get(SystemJsNgModuleLoader);
      return ngModuleLoader.loadAndCompile(modulePath)
      .then(moduleFactory => ({moduleFactory, appModule}));
    })
    .then(({moduleFactory, appModule}) => {
      let injector = appModule.injector;
      const ngModule = moduleFactory.create(injector);
      const app = ngModule.injector.get(ApplicationRef);
    
      ngModule.bootstrapFactories.forEach(comp => {
        comp.selector = moduleSelector;
        app.bootstrap(comp);
      });
    });
    

    Here's a plnkr with the example working (NgModule imported in the root module)
    Here's a plnkr with the example failing because a missing provider (NgModule imported in the dynamically bootstrapped modules)
    Here's a plnkr working correctly without lazy-load with custom selector

    Do you have any ideas on what might be missing for the injector to recognize the services?

  14. tbosch commented on Sep 6, 2016

    @tbosch
    ContributorAuthor

    Could you create a separate issue for this? This is in general just related to module loading, and not to bootstrap of a component with a custom selector.

    Your problem is that a service in a root module can not inject a service that is declared in a lazy loaded module, only the other way around. And this makes sense, as loading of modules is intended for code loading, i.e. your root module cannot refer to the service of the lazy loaded module as that code has not been loaded on bootstrap.

  15. diestrin commented on Sep 6, 2016

    @diestrin
    Contributor

    Moving, sorry...

  16. playground commented on Sep 19, 2016

    @playground

    Hi @tbosch ,

    Incorporating the following code snippet as you suggested with Angular 2.0.0, the components are getting bootstrapped and lazy loaded, however, they are not getting rendered as if change detection didn't kick in probably due to race condition. If we explicitly fire changeDetectorRef.detectChanges() in the console, then the components show up. Is the nice api for this available yet?

    public bootstrapWithCustomSelector(moduleFactory: NgModuleFactory,
    selector: string,
    ngClassName: string
    ): void {
    // Get the parent injector and create the module
    const parentInjector = ReflectiveInjector.resolveAndCreate([], this.appModule.injector);
    const ngModule = moduleFactory.create(parentInjector);

    // Some dependencies from this module
    const appRef = ngModule.injector.get(ApplicationRef);
    const inj = ngModule.injector.get(Injector);
    const lazyLoad = ngModule.injector.get(WuLazyLoadConfig, {component: null});

    if (!lazyLoad.component) {
    throw(${ngClassName} is not using the WuLazyLoadModule. This is neccesary for bootstrap the component. Check the docs.);
    }

    // Get the component factory and create it
    const compFactory = ngModule.componentFactoryResolver
    .resolveComponentFactory(lazyLoad.component);
    const compRef = compFactory.create(inj, [], selector);

    // Register the change detector to the app and trigger the first detection
    appRef.registerChangeDetector(compRef.changeDetectorRef);
    compRef.changeDetectorRef.detectChanges();
    }

  17. angular-automatic-lock-bot commented on Sep 9, 2019

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  18. locked and limited conversation to collaborators on Sep 9, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    effort3: weeksfeatureLabel used to distinguish feature request from other issues

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions