Angular2 @Eingabe einer Eigenschaft mit get / set

178

Ich habe eine Angular2-Komponente in dieser Komponente. Derzeit sind eine Reihe von Feldern mit @Input () versehen, um die Bindung an diese Eigenschaft zu ermöglichen, d. H.

@Input() allowDay: boolean;

Was ich tun möchte, ist tatsächlich mit get / set an eine Eigenschaft zu binden, damit ich im Setter eine andere Logik ausführen kann, etwa die folgende

_allowDay: boolean;
get allowDay(): boolean {
    return this._allowDay;
}
set allowDay(value: boolean) {
     this._allowDay = value;
     this.updatePeriodTypes();
}

Wie würde ich das in Angular2 machen?

Basierend auf dem Vorschlag von Thierry Templier habe ich es geändert, aber das löst den Fehler aus. Kann nicht an 'allowDay' gebunden werden, da es keine bekannte native Eigenschaft ist:

//@Input() allowDay: boolean;
_allowDay: boolean;
get allowDay(): boolean {
    return this._allowDay;
}
@Input('allowDay') set allowDay(value: boolean) {
    this._allowDay = value;
    this.updatePeriodTypes();
}
Paul Cavacas
quelle
Wie und wo binden Sie an [allowDay]="....". If the field (setter) name and the property name you want to use for binding are the same, you can omit the parameter for @Input (...) `.
Günter Zöchbauer
Ich wäre gespannt, wie Sie Ihren Unit-Test einrichten, wenn Sie den in der akzeptierten Antwort angegebenen Weg zur Verwendung von get set eingeschlagen haben.
Winnemucca
1
Was auch immer Sie am Ende tun, stellen Sie sicher, dass Sie einen Haltepunkt, eine Debug-Anweisung oder einen Zähler in Ihren Setter einfügen, um sicherzustellen, dass er wie erwartet nur einmal ausgelöst wird. Ich habe gerade festgestellt, dass meine für jeden Änderungserkennungslauf aktualisiert wurde, was zu schrecklicher Leistung und eigenartigem Verhalten führte.
Simon_Weaver

Antworten:

271

Sie können den @Input direkt am Setter einstellen, wie unten beschrieben:

_allowDay: boolean;
get allowDay(): boolean {
    return this._allowDay;
}

@Input('allowDay')
set allowDay(value: boolean) {
    this._allowDay = value;
    this.updatePeriodTypes();
}

Siehe dieses Plunkr: https://plnkr.co/edit/6miSutgTe9sfEMCb8N4p?p=preview .

Thierry Templier
quelle
1
Ich erhalte die folgende Fehlermeldung. Kann nicht an 'allowDay' gebunden werden, da es sich nicht um eine bekannte native Eigenschaft handelt. Siehe aktualisierte Frage für genau, was ich den Code geändert habe
Paul Cavacas
Bist du sicher? Für mich geht das. Ich habe einen Plunkr hinzugefügt. Vielleicht haben Sie vergessen, die Direktive in das directivesAttribut der Komponente einzufügen, in der Sie sie verwenden möchten ... Ich habe meine Antwort aktualisiert.
Thierry Templier
2
Dies ist eine schlechte Idee, da ngOnChanges bei Verwendung des Setters nicht ausgelöst wird.
user2867288
11
WARNUNG : Die setterwird NICHT durch Mutationen zu Werten ausgelöst, die als Referenz übergeben werden (z. B. Pushing auf ein Array, Mutieren eines Objekts usw.). Sie müssten den gesamten Wert ersetzen , wird als übergeben Inputfür die setterwieder auszulösen.
Nickofthyme
61

Wenn Sie hauptsächlich daran interessiert sind, Logik nur für den Setter zu implementieren :

import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';

// [...]

export class MyClass implements OnChanges {
  @Input() allowDay: boolean;

  ngOnChanges(changes: SimpleChanges): void {
    if(changes['allowDay']) {
      this.updatePeriodTypes();
    }
  }
}

Der Import von SimpleChangesist nicht erforderlich, wenn es keine Rolle spielt, welche Eingabeeigenschaft geändert wurde, oder wenn Sie nur eine Eingabeeigenschaft haben.

Angular Doc: OnChanges

Andernfalls:

private _allowDay: boolean;

@Input() set allowDay(value: boolean) {
  this._allowDay = value;
  this.updatePeriodTypes();
}
get allowDay(): boolean {
  // other logic
  return this._allowDay;
}
Martin Schneider
quelle
Nur neugierig, gibt es einen Vorteil für die Verwendung von ngOnChanges gegenüber der Nichtverwendung der set-Eigenschaft, wenn Sie nur an einer Setter-Logik interessiert sind?
Mese
4
Es gibt keinen Unterschied zwischen "Verwenden von ngOnChanges und Nichtverwenden von set" ...;) Scherz beiseite: Ein Vorteil ist, wenn Ihre Komponente mehrere @InputEigenschaften hat und Sie eine Routine aufrufen möchten, wenn sich eine davon geändert hat. Es wird also weniger Code benötigt.
Martin Schneider
Ups, hatte einen Tippfehler hehe. Aber ok, dachte, es könnte relevanter sein. Danke für die Antwort tho :)
Mese
1
@ MA-Maddin Ich nehme an, Sie könnten auch ein entprelltes Observable festlegen, wenn Sie mehrere Änderungen gleichzeitig erwarten würden, die jeweils dazu führen würden, dass eine Routine ausgeführt werden muss.
Simon_Weaver
ngOnChanges Ansatz ist großartig !! Gute Antwort. Wenn der festgelegte Wert nicht privat sein kann, z. B. als Bindung in der Vorlage verwendet wird, wird die Konvention _propertyName setter / private naming inkonsistent. ngOnChanges umgeht dies perfekt
Drenai
8

@ Paul Cavacas, ich hatte das gleiche Problem und löste es, indem ich den Input()Dekorateur über den Getter stellte.

  @Input('allowDays')
  get in(): any {
    return this._allowDays;
  }

  //@Input('allowDays')
  // not working
  set in(val) {
    console.log('allowDays = '+val);
    this._allowDays = val;
  }

Siehe diesen Plunker: https://plnkr.co/edit/6miSutgTe9sfEMCb8N4p?p=preview

Maxi-Code
quelle
6
Dieser Fehler hat mich verrückt gemacht, ich fand schließlich heraus, dass Sie zuerst die Eingabe () definieren sollten (Getter oder Setter, aber der Eingabe-Dekorator muss zuerst gehen)
Maxi-Code
1
Hier ist eine weitere Referenz, die https://github.com/angular/angular/issues/5477
Maxi-Code