2017-02-06 4 views
3

Ich habe eine Klasse, die bei der Initialisierung Daten von einem Dienst abruft und eine seiner Eigenschaften auffüllt, die ein Array ist. Diese selbe Klasse hat eine Funktion, die dieses Array sortiert, filtert und zurückgibt. Wenn ich ein Objekt dieser Klasse instanziiere und diese Funktion aufruft, merke ich, dass es aufgerufen wird, bevor seine Konstruktor- und ngOnInit() - Funktionen ausgeführt werden (wahrscheinlich, weil ich asynchronen Inhalt von den Observablen verwende, die der Dienst zurückgibt). Wie kann ich garantieren, dass Konstruktor und Init vollständig ausgeführt wurden, bevor irgendeine Funktion meiner Klasse extern aufgerufen wird?Wie kann sichergestellt werden, dass Konstruktor/ngOnInit ausgeführt wird, bevor Funktionen aus einer Klasse aufgerufen werden?

export class BaseChoice implements PickAppraiser, OnInit { 
weight = 0; 
options = new Array<PickQuality>(); 

constructor(private championService: ChampionService) {} 

ngOnInit() { 
    // Iterates through the list of champions adding them to the current object 
    this.championService.getChampions() 
     .subscribe(champions => { 
      // Iterates through the list of champions adding them to the current object 
      Object.keys(champions).map(key => this.options.push(new PickQuality(champions[key], 0))) 
     }) 
} 

choose(n?: number): PickQuality[] { 
    var sorted = this.options.sort((a, b) => a.score - b.score); 
    return sorted; 
} 

}

Ich habe auch versucht, so etwas wie

choose(n?: number): PickQuality[] { 
    // Iterates through the list of champions adding them to the current object 
    this.championService.getChampions() 
     .subscribe(champions => { 
      // Iterates through the list of champions adding them to the current object 
      Object.keys(champions).map(key => this.options.push(new PickQuality(champions[key], 0))) 
      this.reevaluate(this.options); 

      var sorted = this.options.sort((a, b) => a.score - b.score); 
      var chosen; 
      if(n) chosen = sorted.slice(1, n); 
      else chosen = sorted.slice(1, 2); 
      return chosen; 
     }); 
} 

zu tun, wo ich von der Asynchron-Anfrage innerhalb der Auswahl() -Methode laufen selbst, aber es wird mich nicht so tun lassen, Ich nehme an, weil die Rückgabevariable nicht garantiert ist zu existieren.

+0

Dies hängt davon ab, wie der Inhalt extern aufgerufen wird. Wird es von einer übergeordneten Komponente, einer Direktive, einem Service usw. aufgerufen? Gibt es einen Grund, warum Sie die Liste nach der Kartenfunktion nicht sortieren können? – joh04667

+0

Werfen Sie einen Blick auf [Ist es eine schlechte Übung, eine Konstruktorfunktion eine Versprechung zurückgeben zu lassen?] (Http://stackoverflow.com/q/24398699/1048572). Tue nichts Asynchrones bei der Initialisierung einer Instanz (über den Konstruktor direkt oder eckige Hooks), tue es vor dem Erstellen der Instanz. – Bergi

+0

Wie kann ich vor der Instanzerstellung in einer Klasse etwas tun? Ist der Konstruktor nicht das erste, was in einer Klasse läuft? –

Antwort

0

Da Sie die options -Eigenschaft auf ein leeres Array options = new Array<PickQuality>(); initialisieren, warum nicht einen Haken in der Choose-Methode?

choose(n?: number): PickQuality[] { 
    if (this.options && this.options.length !== 0) { 
     var sorted = this.options.sort((a, b) => a.score - b.score); 
     return sorted; 
    } else { 
     /* do something else if options is empty */ 
    } 
} 

--- --- Bearbeiten

Hier ist eine aufgeraut out-Version von dem, was ich in den Kommentaren erwähnt:

export class BaseChoice implements PickAppraiser, OnInit { 
weight = 0; 
options = new Subject<PickQuality[]>(); 

constructor(private championService: ChampionService) {} 

ngOnInit() { 
    this.championService.getChampions() 
     .subscribe(champions => { 
      Let arr = []; 
      Object.keys(champions).map(key => arr.push(new PickQuality(champions[key], 0))); 
      this.options.next(arr); 
     }) 
} 

choose(n?: number): PickQuality[] { 
    return this.options.take(1).sort((a, b) => a.score - b.score); 
} 
} 
+0

Was würde ich auf else-Anweisung tun? Ich kann den Funktionsaufruf choose() nicht einfach abbrechen, nur weil der asynchrone Inhalt noch nicht ausgeführt wurde. Ich kann auch nicht auf beschäftigt warten (wie während (1)), denn dann stoppt meine ganze App. –

+0

Das hängt davon ab, was die Choose-Methode auslöst und was sie tut (Sie geben 'n' ein, werden aber nicht verwendet). In meinen Apps würde ich eigentlich ein RXJS Subject erstellen. options = new Betreff (); Dann wähle in choice die Sortierung und gebe das Observable zurück, so dass der Empfänger der Antwort der choose-Methode auf das Array warten würde (asynchron). – JRulle

+0

Ich verwende es tatsächlich, um mein Array wie options.split (0, n) zu teilen. Ich werde dieses Thema Sache überprüfen, danke. –

0

Wenn Sie anrufen (n) aus einer Vorlage Sie könnten dem Tag in der Vorlage ein * ngIf = "Optionen" hinzufügen. Sie müssen ändern, wie Sie "Optionen" deklarieren, so dass es nicht definiert ist, bis die Daten geladen sind. Etwas wie folgt aus:

options: PickQuality[]; 

Wenn Sie anrufen (n) von einem Dienst, würde ich es ändern, um eine beobachtbare zurückzukehren, oder stattdessen Versprechen.

1

Ich denke, Sie sollten sehen, wie Sie Ihre Komponente im Grunde legen. Sie können Observablen so nutzen, wie sie in Ihrer Vorlage mit der asynchronen Pipe verwendet werden.

Ich bin von den Details Ihrer Komponente nicht sicher, aber ich würde so etwas tun:

export class BaseChoice implements PickAppraiser, OnInit { 
    weight = 0; 
    options$: Observable<PickQuality>; 
    champions$ : Observable<Champion>; 

    constructor(private championService: ChampionService) {} 

    ngOnInit() { 
     this.champions$ = this 
      .championService.getChampions(); 

     this.options$ = this.champions$.map((champion, index) => { 
      return new PickQuality(champion, 0))) 
     }) 
    } 
} 

in Ihrer Vorlage Wenn Sie *ngFor="let option in options$ | async) tun wird es automatisch, dass Strom laufen und geben Sie die Ergebnis, dann in Ihrer choose() Funktion, die ich nehme, ist eine Aktion, die ein Benutzer auf einen Klick nimmt, können Sie einfach direkt die Option übergeben, etwas damit zu tun.

Wenn es komplizierter ist, können Sie dies einem Stream von Klicks wie championClicked$ zuordnen und diese Klicks einfach der richtigen Option aus dem Optionen-Stream zuordnen.

Die Sache zu beachten ist, dass Sie diese Observablen mit einer Pipeline von Aktionen einrichten, und dass diese Pipeline einmal pro Observer (Abonnent) läuft, was bedeutet, jedes Mal, wenn Sie die | async Pipe verwenden, die es abonniert und läuft das ganze Ding.

Etwas Zeit mit dem Lernen von RxJS zu verbringen, wird sich in Ihrer Angular 2-Entwicklung enorm auszahlen.

Verwandte Themen