Angular2 @Input em uma propriedade com get / set

178

Eu tenho um componente Angular2 nesse componente que atualmente possui um monte de campos que têm @Input () aplicado antes deles para permitir a ligação a essa propriedade, ou seja,

@Input() allowDay: boolean;

O que eu gostaria de fazer é vincular a uma propriedade com get / set, para que eu possa fazer alguma outra lógica no setter, algo como o seguinte

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

como eu faria isso no Angular2?

Com base na sugestão de Thierry Templier, eu mudei para, mas isso gera o erro Não é possível vincular a 'allowDay', pois não é uma propriedade nativa conhecida:

//@Input() allowDay: boolean;
_allowDay: boolean;
get allowDay(): boolean {
    return this._allowDay;
}
@Input('allowDay') set allowDay(value: boolean) {
    this._allowDay = value;
    this.updatePeriodTypes();
}
Paul Cavacas
fonte
Como e onde você se liga ao [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
Eu ficaria curioso para ver como você configurou seu teste de unidade se você seguisse o caminho de usar o set-set, conforme mostrado na resposta aceita.
Winnemucca
1
O que quer que você faça, certifique-se de colocar um ponto de interrupção, uma instrução de depuração ou um contador dentro do seu setter para garantir que ele seja acionado apenas uma vez conforme o esperado. Acabei de descobrir que o meu estava sendo atualizado para cada execução de detecção de alterações, causando desempenho horrível e comportamento peculiar.
Simon_Weaver

Respostas:

271

Você pode definir o @Input diretamente no configurador, conforme descrito abaixo:

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

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

Veja este artigo: https://plnkr.co/edit/6miSutgTe9sfEMCb8N4p?p=preview .

Thierry Templier
fonte
1
Recebo o seguinte erro Não é possível vincular a 'allowDay', pois não é uma propriedade nativa conhecida. Veja a pergunta actualizado para exatamente o que eu mudei o código para
Paul Cavacas
Você tem certeza? Funciona para mim. Eu adicionei um plunkr. Talvez você tenha esquecido de adicionar a diretiva ao directivesatributo do componente em que deseja usá-la ... Atualizei minha resposta.
Thierry Templier
2
É uma péssima idéia, porque se você usar o setter, o ngOnChanges não será acionado.
user2867288
11
ATENÇÃO : A setterirá NÃO ser desencadeada por mutações para valores que são passados por referência (isto é, que empurram para uma matriz, um objecto mutação, etc.). Você precisaria substituir todo o valor que está sendo passado como um Inputpara o settergatilho novamente.
Nickofthyme
61

Se você está interessado principalmente em implementar lógica apenas para o setter :

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

A importação de SimpleChangesnão é necessária se não importa qual propriedade de entrada foi alterada ou se você possui apenas uma propriedade de entrada.

Doc Angular: OnChanges

de outra forma:

private _allowDay: boolean;

@Input() set allowDay(value: boolean) {
  this._allowDay = value;
  this.updatePeriodTypes();
}
get allowDay(): boolean {
  // other logic
  return this._allowDay;
}
Martin Schneider
fonte
Apenas curioso, há algum benefício em usar ngOnChanges vs não usar a propriedade set se você estiver interessado apenas em uma lógica de setter?
Mese
4
Não há diferença em "usar ngOnChanges vs não usar set" ...;) Brincadeiras à parte: Um benefício é que, se o seu componente possui várias @Inputpropriedades e você deseja chamar uma rotina quando algum deles foi alterado. Portanto, é necessário menos código.
Martin Schneider
Ups, tive um erro de digitação hehe. Mas tudo bem, pensei que poderia ter mais relevância. Obrigado pela resposta tho :)
Mese
1
@ MA-Maddin Suponho que você também possa definir um observável debounceado se estiver esperando várias alterações ao mesmo tempo que resultem em uma rotina que precisa ser executada.
Simon_Weaver
A abordagem do ngOnChanges é ótima !! Boa resposta. Se o valor que está sendo definido não puder ser privado, por exemplo, ele será usado como ligação no modelo, a convenção _propertyName setter / private naming se tornará inconsistente. o ngOnChanges resolve isso perfeitamente #
Drenai 15/05
8

@Paul Cavacas, tive o mesmo problema e resolvi colocando o Input()decorador acima do getter.

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

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

Veja este plunker: https://plnkr.co/edit/6miSutgTe9sfEMCb8N4p?p=preview

código maxi
fonte
6
Este bug me deixa doida, eu finalmente descobri que você deve definir a entrada () primeiro (getter ou setter, mas o decorador de entrada deve ir primeiro)
maxi-código
1
Aqui está outra referência que pode ajudar https://github.com/angular/angular/issues/5477
maxi-code