Angular2 @Input à une propriété avec get / set

178

J'ai un composant Angular2 dans ce composant, il a actuellement un tas de champs qui ont @Input () appliqué avant eux pour permettre la liaison à cette propriété, c'est-à-dire

@Input() allowDay: boolean;

Ce que je voudrais faire est en fait de me lier à une propriété avec get / set, afin que je puisse faire une autre logique dans le setter, quelque chose comme ce qui suit

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

comment pourrais-je faire cela dans Angular2?

Sur la base de la suggestion de Thierry Templier, je l'ai changé en, mais cela génère l'erreur Can't bind to 'allowDay' car ce n'est pas une propriété native connue:

//@Input() allowDay: boolean;
_allowDay: boolean;
get allowDay(): boolean {
    return this._allowDay;
}
@Input('allowDay') set allowDay(value: boolean) {
    this._allowDay = value;
    this.updatePeriodTypes();
}
Paul Cavacas
la source
Comment et où vous liez-vous à [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
Je serais curieux de voir comment vous configurez votre test unitaire si vous avez choisi d'utiliser get set comme indiqué dans la réponse acceptée.
Winnemucca
1
Quoi que vous finissiez par faire, assurez-vous de mettre un point d'arrêt, une instruction de débogage ou un compteur dans votre setter pour vous assurer qu'il ne se déclenche qu'une seule fois comme prévu. Je viens de découvrir que le mien était mis à jour pour chaque exécution de détection de changement, provoquant des performances horribles et un comportement décalé.
Simon_Weaver

Réponses:

271

Vous pouvez définir @Input directement sur le setter, comme décrit ci-dessous:

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

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

Voir ce plunkr: https://plnkr.co/edit/6miSutgTe9sfEMCb8N4p?p=preview .

Thierry Templier
la source
1
J'obtiens l'erreur suivante Je ne peux pas me lier à «allowDay» car ce n'est pas une propriété native connue. Voir la question mise à jour pour savoir exactement à quoi j'ai changé le code
Paul Cavacas
Êtes-vous sûr? Ça marche pour moi. J'ai ajouté un plunkr. Peut-être avez-vous oublié d'ajouter la directive dans l' directivesattribut du composant où vous souhaitez l'utiliser ... J'ai mis à jour ma réponse.
Thierry Templier
2
C'est une mauvaise idée car si vous utilisez le setter, ngOnChanges ne se déclenche pas.
user2867288
4
Sur les pages
Angular
11
AVERTISSEMENT : Le setterne sera PAS déclenché par des mutations vers des valeurs qui sont passées par référence (ex: pousser vers un tableau, muter un objet, etc.). Vous devrez remplacer toute la valeur transmise Inputpour que le setterse déclenche à nouveau.
Nickofthyme
61

Si vous êtes principalement intéressé par l'implémentation de la logique sur le setter uniquement :

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

L'importation de SimpleChangesn'est pas nécessaire si la propriété d'entrée modifiée n'a pas d'importance ou si vous n'avez qu'une seule propriété d'entrée.

Doc angulaire: OnChanges

autrement:

private _allowDay: boolean;

@Input() set allowDay(value: boolean) {
  this._allowDay = value;
  this.updatePeriodTypes();
}
get allowDay(): boolean {
  // other logic
  return this._allowDay;
}
Martin Schneider
la source
Juste curieux, y a-t-il un avantage à utiliser ngOnChanges par rapport à ne pas utiliser la propriété set si vous n'êtes intéressé que par une logique de setter?
Mese
4
Il n'y a aucune différence entre "utiliser ngOnChanges et ne pas utiliser set" ...;) Blague à part: un avantage est que si votre composant a plusieurs @Inputpropriétés et que vous voulez appeler une routine quand l'une d'elles a changé. Donc, moins de code nécessaire.
Martin Schneider
Ups, avait une faute de frappe hehe. Mais ok, j'ai pensé que cela pourrait avoir plus de pertinence. Merci pour la réponse tho :)
Mese
1
@ MA-Maddin Je suppose que vous pourriez également définir un observable déboncé si vous vous attendiez à plusieurs changements en même temps qui entraîneraient chacun une routine devant être exécutée.
Simon_Weaver
L'approche ngOnChanges est géniale !! Bonne réponse. Si la valeur définie ne peut pas être privée, par exemple, elle est utilisée comme liaison dans le modèle, le setter _propertyName / convention de dénomination privée devient incohérent. ngOnChanges contourne parfaitement cela
Drenai
8

@Paul Cavacas, j'ai eu le même problème et j'ai résolu en mettant le Input()décorateur au-dessus du getter.

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

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

Voir ce plunker: https://plnkr.co/edit/6miSutgTe9sfEMCb8N4p?p=preview

maxi-code
la source
6
Ce bug m'a rendu fou, j'ai finalement trouvé que vous devriez d'abord définir Input () (getter ou setter mais le décorateur d'entrée doit commencer)
maxi-code
1
Voici une autre référence qui peut aider https://github.com/angular/angular/issues/5477
maxi-code