Instance Angular 2 Component Two times

后端 未结 3 1598
借酒劲吻你
借酒劲吻你 2020-12-03 14:44

I\'m trying to learn Angular 2, so I was making some hello world examples. Here is my code:

boot.ts

import {bootstrap}          


        
相关标签:
3条回答
  • 2020-12-03 15:05

    I have tested this. You can not make more than one Angular 2 Main Components with the same name. But you can make as many as you want for non-Main components.

    How can main and non-main component are differentiated?

    Main component is the one that gets bootstrapped.

    Have a look of the screen shot.

    My main component called: Which I made it twice in the HTML:

    <body>
      <my-app>Loading...</my-app>
      <my-app>Loading...</my-app>
    </body>
    

    As you can see, there is a loading at the end of the bottom of the picture.

    However, it works for non-main components. As you can see my-hero-detail components can be created as many as I can.

    <div class="center-align">
    <h1>{{title}}</h1>
    </div>
    <div class="row" style="margin-bottom: 0;">
        <div class="col s12 m6">
            <div id="my-heroes" class="card">
                <div class="card-header">
                    <span>My Heroes</span>
                </div>
                <div class="card-content">
                    <ul class="heroes">
                        <li *ngFor="#hero of heroes" 
                            (click)="onSelect(hero)"
                            [class.selected]="hero === selectedHero">
                            <span class="badge">{{hero.id}}</span> {{hero.name}}
                        </li>
                    </ul>   
                </div>
            </div>      
        </div>
        <my-hero-detail [hero]="selectedHero"></my-hero-detail>
    </div>
    <div class="row">
        <my-hero-detail [hero]="selectedHero"></my-hero-detail>
        <my-hero-detail [hero]="selectedHero"></my-hero-detail>
    </div>
    

    My Hero Detail Component:

    import {Component} from 'angular2/core';
    import {Hero} from '../hero';
    @Component({
        selector: 'my-hero-detail',
        templateUrl: 'app/hero-detail/hero-detail.html',
        inputs: ['hero'],
    })
    
    export class HeroDetailComponent {
        public hero: Hero;
    }
    
    0 讨论(0)
  • 2020-12-03 15:14

    If you come across this question and really do want two root level app instances, this can be accomplished by manually bootstrapping your root level component(s) in the NgModule ngDoBootstrap method.

    (Note that in Angular 5+ this method may no longer be required, see this Angular PR)

    We first find all root elements we want to bootstrap and give them a unique ID. Then for each instance, hack the component factory selector with the new ID and trigger the bootstrap.

    const entryComponents = [
      RootComponent,
    ];
    
    @NgModule({
      entryComponents,
      imports: [
        BrowserModule,
      ],
      declarations: [
        RootComponent,
      ],
    })
    export class MyModule {
      constructor(private resolver: ComponentFactoryResolver) {}
    
      ngDoBootstrap(appRef: ApplicationRef) {
        entryComponents.forEach((component: any) => {
          const factory = this.resolver.resolveComponentFactory(component);
          let selectorName;
          let elements;
    
          // if selector is a class
          if (factory.selector.startsWith('.')) {
            selectorName = factory.selector.replace(/^\./, '');
            elements = document.getElementsByClassName(selectorName);
    
          // else assume selector is an element
          } else {
            selectorName = factory.selector;
            elements = document.getElementsByTagName(selectorName);
          }
    
          // no elements found, early return
          if (elements.length === 0) {
            return;
          }
    
          // more than one root level componenet found, bootstrap unique instances
          if (elements.length > 1) {
            const originalSelector = factory.selector;
    
            for (let i = 0; i < elements.length; i += 1) {
              elements[i].id = selectorName + '_' + i;
              (<any>factory).factory.selector = '#' + elements[i].id;
              appRef.bootstrap(factory);
            }
    
            (<any>factory).factory.selector = originalSelector;
    
          // only a single root level component found, bootstrap as usual
          } else {
            appRef.bootstrap(factory);
          }
        });
      }
    }
    

    Now, assuming our RootComponent's selector was '.angular-micro-app' this will work as expected:

    <body>
        <div class="angular-micro-app"></div>
        ...
        <div class="angular-micro-app"></div>
    </body>
    
    0 讨论(0)
  • 2020-12-03 15:22

    Just as standard HTML page should have one <body> tag for content and one <head> tag for 'metadata', an Angular2 application should have one root tag. To make app work you have to initialize it (tell Angular that it is an app) and you do that by calling bootstrap() function.

    If it bothers you that your root tag (for example <app>) is inside the body, you can change selector from custom tag app to standard tag body. If you add different component as root, like this:

    import {bootstrap} from 'angular2/platform/browser'
    import {Component} from 'angular2/core';
    import {AppComponent} from './app.component'
    import {DataService} from './app.dataservice'
    
    @Component({
      selector: 'body',
      directives: [AppComponent],
      template: `
        <hello-world>Loading...</hello-world>
        <hello-world>Loading...</hello-world>
      `
    })
    class RootComponent {}
    
    bootstrap(RootComponent, [DataService]);
    

    ...the rest of your code should work.

    Of course, if in your HTML you need to have other stuff (non-app content, or other angular apps) you wouldn't select body as root selector for your Angular2 app.

    Hope this helps you understand things better...

    0 讨论(0)
提交回复
热议问题