Angular2 @Input a una propiedad con get / set

178

Tengo un componente Angular2 en ese componente, actualmente tiene un montón de campos que tienen @Input () aplicado antes de ellos para permitir el enlace a esa propiedad, es decir

@Input() allowDay: boolean;

Lo que me gustaría hacer es vincularme a una propiedad con get / set, de modo que pueda hacer otra lógica en el setter, algo como lo siguiente

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

¿Cómo haría esto en Angular2?

Según la sugerencia de Thierry Templier, lo cambié a, pero eso arroja el error No se puede vincular a 'allowDay' ya que no es una propiedad nativa conocida:

//@Input() allowDay: boolean;
_allowDay: boolean;
get allowDay(): boolean {
    return this._allowDay;
}
@Input('allowDay') set allowDay(value: boolean) {
    this._allowDay = value;
    this.updatePeriodTypes();
}
Paul Cavacas
fuente
Cómo y dónde vincularse a [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
Sería curioso ver cómo configuró su unidad de prueba si siguió la ruta de uso de get set como se muestra en la respuesta aceptada.
Winnemucca
1
Independientemente de lo que termine haciendo, asegúrese de poner un punto de interrupción, una declaración de depuración o un contador dentro de su setter para asegurarse de que solo se active una vez como se esperaba. Acabo de encontrar que el mío se estaba actualizando para cada ejecución de detección de cambios que causa un rendimiento horrible y un comportamiento peculiar.
Simon_Weaver

Respuestas:

271

Puede configurar el @Input en el setter directamente, como se describe a continuación:

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

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

Vea este plunkr: https://plnkr.co/edit/6miSutgTe9sfEMCb8N4p?p=preview .

Thierry Templier
fuente
1
Me sale el siguiente error No puedo enlazar a 'allowDay' ya que no es una propiedad nativa conocida. Vea la pregunta actualizada para saber exactamente a qué cambié el código
Paul Cavacas
¿Estás seguro? Esto funciona para mi. Agregué un plunkr. Quizás olvidó agregar la directiva al directivesatributo del componente donde desea usarla ... Actualicé mi respuesta.
Thierry Templier
2
Esta es una mala idea porque si usa el setter, ngOnChanges no se dispara.
usuario2867288
11
ADVERTENCIA : La setterhabrá NO ser provocados por mutaciones a valores que son pasados por referencia (es decir, que empujan a una matriz, mutando un objeto, etc.). Debería reemplazar todo el valor que se pasa como Inputpara setterque se active nuevamente.
Nickofthyme
61

Si está interesado principalmente en implementar la lógica solo en el 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();
    }
  }
}

La importación de SimpleChangesno es necesaria si no importa qué propiedad de entrada se modificó o si solo tiene una propiedad de entrada.

Doc Angular: OnChanges

de otra manera:

private _allowDay: boolean;

@Input() set allowDay(value: boolean) {
  this._allowDay = value;
  this.updatePeriodTypes();
}
get allowDay(): boolean {
  // other logic
  return this._allowDay;
}
Martin Schneider
fuente
Solo por curiosidad, ¿hay algún beneficio por usar ngOnChanges vs no usar la propiedad set si solo estás interesado en una lógica setter?
Mese
44
No hay diferencia en "usar ngOnChanges frente a no usar set" ...;) Bromas aparte: un beneficio es, si su componente tiene múltiples @Inputpropiedades y desea llamar a una rutina cuando alguna de ellas ha cambiado. Por lo tanto, se necesita menos código.
Martin Schneider
Ups, tenía un error tipográfico jeje. Pero bueno, pensé que podría tener más relevancia. Gracias por la respuesta aunque :)
Mese
1
@ MA-Maddin Supongo que también podría establecer un observable sin rebote si esperaba múltiples cambios, todo al mismo tiempo, lo que resultaría en una rutina que debe ejecutarse.
Simon_Weaver
El enfoque de ngOnChanges es genial !! Buena respuesta. Si el valor que se establece no puede ser privado, por ejemplo, se usa como enlace en la plantilla, la convención de nombres privados / establecedor de nombre de propiedad se vuelve inconsistente. ngOnChanges soluciona esto perfectamente
Drenai
8

@Paul Cavacas, tuve el mismo problema y lo resolví configurando el Input()decorador sobre el captador.

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

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

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

código maxi
fuente
66
Este error me volvió loco, finalmente descubrí que primero debes definir Input () (getter o setter pero el decorador de entrada debe ir primero)
maxi-code
1
Aquí hay otra referencia que puede ayudar https://github.com/angular/angular/issues/5477
maxi-code