Angular2 @ Вход в свойство с помощью get / set

178

У меня есть компонент Angular2 в этом компоненте, в настоящее время он имеет кучу полей, перед которыми применяется @Input (), чтобы разрешить привязку к этому свойству, т.е.

@Input() allowDay: boolean;

То, что я хотел бы сделать, это на самом деле связать со свойством get / set, чтобы я мог сделать некоторую другую логику в установщике, что-то вроде следующего

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

Как бы я сделал это в Angular2?

Основываясь на предложении Тьерри Темплиера, я изменил его на, но это выдает ошибку. Невозможно связать с «allowDay», так как это не известное нативное свойство:

//@Input() allowDay: boolean;
_allowDay: boolean;
get allowDay(): boolean {
    return this._allowDay;
}
@Input('allowDay') set allowDay(value: boolean) {
    this._allowDay = value;
    this.updatePeriodTypes();
}
Пол Кавакас
источник
Как и где вы должны связываться с [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 (...) `.
Гюнтер Цохбауэр
Мне было бы интересно посмотреть, как вы настроите свой юнит-тест, если вы пошли по пути использования get set, как показано в принятом ответе.
Winnemucca
1
Что бы вы в итоге ни делали, убедитесь, что поставили точку останова, или оператор отладки, или счетчик внутри вашего установщика, чтобы убедиться, что он срабатывает только один раз, как и ожидалось. Я только что обнаружил, что мой обновлялся для каждого запуска обнаружения изменений, вызывая ужасную производительность и странное поведение.
Simon_Weaver

Ответы:

271

Вы можете установить @Input на сеттер напрямую, как описано ниже:

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

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

Смотрите этот план: https://plnkr.co/edit/6miSutgTe9sfEMCb8N4p?p=preview .

Тьерри Темплиер
источник
1
Я получаю следующую ошибку: «Невозможно связать с« allowDay », поскольку это не известное нативное свойство». Смотрите обновленный вопрос, для чего именно я изменил код
Пол Кавакас
Ты уверен? Меня устраивает. Я добавил plunkr. Возможно, вы забыли добавить директиву в directivesатрибут компонента, где вы хотите его использовать ... Я обновил свой ответ.
Тьерри Темплиер
2
Это плохая идея, потому что если вы используете сеттер, ngOnChanges не срабатывает.
user2867288
11
ПРЕДУПРЕЖДЕНИЕ : setterбудет НЕ быть вызваны мутациями в значения , которые передаются по ссылке (т.е. толкающие на массив, изменяющий объект и т.д.). Вам нужно будет заменить все передаваемое значение как Inputдля setterповторного запуска.
Nickofthyme
61

Если вы в основном заинтересованы в реализации логики только для сеттера :

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

Импорт SimpleChangesне требуется, если не имеет значения, какое свойство ввода было изменено или если у вас есть только одно свойство ввода.

Angular Doc: OnChanges

в противном случае:

private _allowDay: boolean;

@Input() set allowDay(value: boolean) {
  this._allowDay = value;
  this.updatePeriodTypes();
}
get allowDay(): boolean {
  // other logic
  return this._allowDay;
}
Мартин Шнайдер
источник
Просто любопытно, есть ли польза от использования ngOnChanges по сравнению с неиспользованием свойства set, если вас интересует только логика сеттера?
Месе
4
Нет никакой разницы в «использовании ngOnChanges по сравнению с не использованием set» ...;) Шутки в сторону: одно преимущество, если ваш компонент имеет несколько @Inputсвойств и вы хотите вызывать подпрограмму, когда любое из них изменилось. Поэтому требуется меньше кода.
Мартин Шнайдер
Упс, была опечатка хе-хе. Но хорошо, подумал, что это может иметь большее значение. Спасибо за ответ, но :)
Месе
1
@ MA-Maddin Полагаю, вы могли бы также установить дебасируемую наблюдаемую ситуацию, если ожидаете нескольких изменений одновременно, каждый из которых приведет к выполнению процедуры.
Simon_Weaver
Подход ngOnChanges великолепен !! Хороший ответ. Если устанавливаемое значение не может быть закрытым, например, оно используется в качестве привязки в шаблоне, соглашение об установщике _propertyName / закрытое именование становится несовместимым. ngOnChanges отлично
справляется с
8

@Paul Cavacas, у меня была та же проблема, и я решил, установив Input()декоратор над геттером.

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

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

Смотрите этот плункер: https://plnkr.co/edit/6miSutgTe9sfEMCb8N4p?p=preview

макси-код
источник
6
Эта ошибка привела меня в бешенство, я наконец-то обнаружил, что вы должны сначала определить Input () (получатель или установщик, но входной декоратор должен идти первым)
макси-код
1
Вот еще одна ссылка, которая может помочь https://github.com/angular/angular/issues/5477
макси-код