web-dev-qa-db-de.com

Beispiel Angular 2 Komponente Zwei mal

Ich versuche, Angular 2 zu lernen, also machte ich einige hello world-Beispiele ... Hier ist mein Code:

boot.ts

import {bootstrap}    from 'angular2/platform/browser'
import {AppComponent} from './app.component'
import {DataService} from './app.dataservice'

bootstrap(AppComponent, [DataService]);

index.html

...
<body>
    <hello-world>Loading...</hello-world>
    <hello-world>Loading...</hello-world>
</body>
...

app.component.ts

import {Component} from 'angular2/core';
import {DataService} from './app.dataservice'

@Component({
    selector: 'hello-world',
    template: '<h1>Hello {{ item }}</h1>'
})

export class AppComponent {
    items: Array<number>;
    item: number;

    constructor(dataService: DataService) {
        this.items = dataService.getItems();
        this.item = this.items[0];
    }
}

app.dataservice.ts

export class DataService {
    items: Array<number>;

    constructor() {
        this.items = [1,2,3];
    }

    getItems() {
        return this.items;
    }
}

Der Code scheint einwandfrei zu funktionieren, da das erste hello-world-benutzerdefinierte Tag korrekt mit dem Code in der ts angezeigt wird. Der zweite hello-world tag is not transformed. Es wird nur ein benutzerdefiniertes Element angezeigt.

Kann nicht mehr als ein benutzerdefiniertes Tag sein? Wie kann ich das machen?

EDIT

Ich habe den neuen Import in app.components.ts hinzugefügt

import {ByeWorld} from './app.byeworld';

und in app.byeworld.ts

import {Component} from 'angular2/core';

@Component({
    selector: 'bye-world',
    template: '<h1>Bye World</h1>'
})

export class ByeWorld {
    constructor() {
    }
}
14
Pablo

So wie die Standard-HTML-Seite ein <body>-Tag für den Inhalt und ein <head>-Tag für 'Metadaten' haben sollte, sollte eine Angular2-Anwendung ein Stammtag haben. Damit die App funktioniert, müssen Sie sie initialisieren (sagen Sie Angular, dass es sich um eine App handelt) und tun Sie dies, indem Sie die Funktion bootstrap() aufrufen. 

Wenn es Sie stört, dass sich Ihr Root-Tag (z. B. <app>) im Rumpf befindet, können Sie den Selektor vom benutzerdefinierten Tag app zum Standard-Tag body ändern. Wenn Sie eine andere Komponente als root hinzufügen, wie folgt:

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]);

... der Rest Ihres Codes sollte funktionieren. 

Wenn Sie in Ihrem HTML-Code andere Elemente (Nicht-App-Inhalte oder andere eckige Apps) benötigen, würden Sie body natürlich nicht als Root-Selector für Ihre Angular2-App auswählen.

Hoffe, das hilft dir, die Dinge besser zu verstehen ...

4
Sasxa

Ich habe das getestet. Sie können nicht mehr als eine Angular 2 Hauptkomponenten mit demselben Namen erstellen. Sie können jedoch beliebig viele Komponenten für Nicht-Main-Komponenten erstellen.

Wie können Haupt- und Nicht-Hauptkomponente unterschieden werden?

Hauptkomponente ist diejenige, die Bootstraps erhält.

Schauen Sie sich den Screenshot an .  enter image description here

Meine Hauptkomponente heißt: Was ich im HTML zweimal gemacht habe:

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

Wie Sie sehen, befindet sich am unteren Rand des Bildes eine loading.

Funktioniert jedoch für Nicht-Hauptkomponenten. Wie Sie sehen, können my-hero-detail-Komponenten so viele erstellt werden, wie ich kann.

<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>

Meine Heldendetailkomponente:

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;
}
9
Shaohao Lin

Wenn Sie auf diese Frage stoßen und wirklich zwei Instanzen auf Root-Ebene wünschen, können Sie dies durch manuelles Bootstrapping der Root-Level-Komponenten in der NgModule-Methode ngDoBootstrap erreichen.

(Beachten Sie, dass in Angular 5+ diese Methode möglicherweise nicht mehr erforderlich ist, siehe this Angular PR )

Wir finden zuerst alle Root-Elemente, die wir bootstrapen möchten, und geben ihnen eine eindeutige ID. Hacken Sie dann für jede Instanz den Komponenten-Factory-Selector mit der neuen ID und lösen Sie den Bootstrap aus.

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);
      }
    });
  }
}

Angenommen, der RootComponent-Selektor lautete ".angular-micro-app". Dies funktioniert wie erwartet:

<body>
    <div class="angular-micro-app"></div>
    ...
    <div class="angular-micro-app"></div>
</body>
0
Josh