Подтвердить что ты не робот

Как вызвать функцию каждый раз, когда модель изменяется в angular 2?

У меня есть настраиваемый компонент выбора, который устанавливает модель при нажатии на элемент li, но поскольку я вручную вызываю this.modelChange.next(this.model) каждый раз, когда я меняю модель, это довольно грязно и повторяемо, чего я хочу избежать.

Итак, мой вопрос: если что-то похожее на $scope.$watch, где я могу посмотреть, меняется ли значение, а затем вызывает this.modelChange.next(this.model) каждый раз, когда это происходит.

Я читал о Observables, но я не могу понять, как это предполагается использовать только для простого значения, поскольку все примеры, которые я вижу, связаны с асинхронными запросами к внешним api: s.

Неужели должен быть более простой способ достичь этого?

(Не то, что я не могу использовать ngModelChanges, так как на самом деле я не использую для этого ввод).

import {Component, Input, Output, EventEmitter, OnInit, OnChanges} from 'angular2/core';

@Component({
  selector: 'form-select',
  templateUrl: './app/assets/scripts/modules/form-controls/form-select/form-select.component.html',
  styleUrls: ['./app/assets/scripts/modules/form-controls/form-select/form-select.component.css'],
  inputs: [
    'options',
    'callback',
    'model',
    'label'
  ]
})

export class FormSelectComponent implements OnInit, OnChanges {
  @Input() model: any;
  @Output() modelChange: EventEmitter = new EventEmitter();

  public isOpen: boolean = false;

  ngOnInit() {

    if (!this.model) {
      this.model = {};
    }

    for (var option of this.options) {

      if (option.model == (this.model.model || this.model)) {
        this.model = option;

      }
    }
  }

  ngOnChanges(changes: {[model: any]: SimpleChange}) {
    console.log(changes);
    this.modelChange.next(changes['model'].currentValue);
  }

  toggle() {
    this.isOpen = !this.isOpen;
  }

  close() {
    this.isOpen = false;
  }

  select(option, callback) {
    this.model = option;
    this.close();

    callback ? callback() : false;
  }

  isSelected(option) {
    return option.model === this.model.model;
  }
}

Изменить: Я попытался использовать ngOnChanges (см. обновленный код выше), но он запускается только один раз при инициализации, тогда он не обнаруживает изменений. Что-то не так?

4b9b3361

Ответ 1

  Поэтому мой вопрос: есть ли что-то похожее на $ scope. $ Watch, где я могу посмотреть, если значение свойства input model изменится

Если model является примитивным типом JavaScript (Number, String, Boolean), то вы можете реализовать ngOnChanges(), чтобы получать уведомления об изменениях. См. пример поваренной книги и документацию по жизненному циклу, раздел OnChanges.
Другой вариант - использовать установщик и получатель. См. пример поваренной книги.

Если model является ссылочным типом JavaScript (массив, объект, дата и т.д.), То как вы обнаружите изменения, зависит от того, как меняется модель:

  • Если ссылка на модель изменится (например, вы назначите новый массив или новый объект и т.д.), Вы можете реализовать ngOnChanges(), чтобы получать уведомления об изменениях, как для примитивных типов.
  • Однако, если ссылка на модель не изменяется, но изменяется некоторое свойство модели (например, изменяется значение элемента массива, либо добавляется или удаляется элемент массива, или если изменяется значение свойства объекта), вы можете реализовать ngDoCheck() для реализации собственной логики обнаружения изменений.
    См. документацию по жизненному циклу, раздел DoCheck.

Ответ 2

Если вы выберете пользовательский компонент для внутреннего использования форм ввода, я бы использовал событие ngModelChange для него/них:

<select [ngModel]="..." (ngModelChange)="triggerUpdate($event)">…</select>

или valueChanges наблюдаемых соответствующих элементов управления, если таковые имеются. В шаблоне:

<select [ngFormControl]="myForm.controls.selectCtrl">…</select>

В компоненте:

myForm.controls.selectCtrl.valueChanges.subscribe(newValue => {
  (...)
});

Ответ 3

ngAfterViewChecked - лучший метод жизненного цикла, так как он вызывается после рендеринга DOM и любые манипуляции могут быть сделаны здесь.

fooobar.com/questions/203026/...

Ответ 4

Вы можете сделать model getter/setter или реализовать OnChanges, добавив метод ngOnChanges(changes) {}, который вызывается каждый раз после изменения значения @Input().

Пример ngOnChanges() из документов (связанных выше):

@Component({
  selector: 'my-cmp',
  template: `<p>myProp = {{myProp}}</p>`
})
class MyComponent implements OnChanges {
  @Input() myProp: any;
  ngOnChanges(changes: {[propName: string]: SimpleChange}) {
    console.log('ngOnChanges - myProp = ' + changes['myProp'].currentValue);
  }
}
@Component({
  selector: 'app',
  template: `
    <button (click)="value = value + 1">Change MyComponent</button>
    <my-cmp [my-prop]="value"></my-cmp>`,
  directives: [MyComponent]
})
export class App {
  value = 0;
}
bootstrap(App).catch(err => console.error(err));

Обновление

Если внутреннее состояние model изменяется, но не сам model (другой экземпляр model), то изменение обнаружения не распознает его. Вам нужно реализовать свой собственный механизм, чтобы уведомить заинтересованный код, например, используя Observable в model, который испускает событие с изменениями, на которое может подписаться ваш компонент.

Также ngOnChanges() вызывается только тогда, когда model изменяется привязкой данных (когда someFieldInParent изменился в <my-comp [model]="someFieldInParent"> и Angular) передает новое значение model в MyComponent.

return option.model === this.model.model; не вызывает вызов ngOnChanges(). Для этого лучше использовать подход геттера/сеттера.