Angular 4: Как просмотреть объект для изменений?

ETA: Я знаю, что есть различные способы посмотреть мою форму изменений. Это не то, что я пытаюсь сделать. Как говорится в названии, я спрашиваю, как следить за изменениями в объекте. Приложение, показанное ниже, предназначено только для иллюстрации. Пожалуйста, ответьте на вопрос, который я задал. Спасибо!

У меня есть это простое приложение:

import { Component, OnInit } from '@angular/core';

export class Customer {
    firstName: string;
    favoriteColor: string;
}

@Component({
    selector: 'my-app',
    template: `
        <div *ngIf="customer">
            <input type="text" [(ngModel)]="customer.firstName">
            <input type="text" [(ngModel)]="customer.favoriteColor">
        </div>
        `
})
export class AppComponent implements OnInit {

    private customer: Customer;

    ngOnInit(): void {

        this.customer = new Customer();

        // TODO: how can I register a callback that will run whenever
        // any property of this.customer has been changed?

    }

}

Обратите внимание на TODO. Мне нужно зарегистрировать обратный вызов, который будет выполняться всякий раз, когда будет изменено любое свойство this.customer.

Я не могу использовать ngChange на входах. Мне нужно подписаться непосредственно на изменения в модели. Причины относятся к моему прецеденту и не стоит здесь входить. Просто поверьте мне, что это не вариант.

Возможно ли это? Я сделал много Googling, но я придумал сухую.

Ответ 1

Angular обычно использует встроенный в конструктор класс KeyValueDiffers.

Для вашего случая это может выглядеть так:

import { KeyValueChanges, KeyValueDiffer, KeyValueDiffers } from '@angular/core';

export class Customer {
  firstName: string;
  favoriteColor: string;
}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html'
})
export class AppComponent {
  private customerDiffer: KeyValueDiffer<string, any>;
  private customer: Customer;

  constructor(private differs: KeyValueDiffers) {}

  ngOnInit(): void {
    this.customer = new Customer();
    this.customerDiffer = this.differs.find(this.customer).create();
  }

  customerChanged(changes: KeyValueChanges<string, any>) {
    console.log('changes');
    /* If you want to see details then use
      changes.forEachRemovedItem((record) => ...);
      changes.forEachAddedItem((record) => ...);
      changes.forEachChangedItem((record) => ...);
    */
  }

  ngDoCheck(): void {
      const changes = this.customerDiffer.diff(this.customer);
      if (changes) {
        this.customerChanged(changes);
      }
  }
}

Пример Stackblitz

Еще один вариант - использовать setter для свойств, которые вы хотите проверить.

Смотрите также

Ответ 2

Мне нужно подписаться непосредственно на изменения в модели.

Затем вам нужно прослушать изменения модели с помощью ngModelChange

Шаблон:

<input type="text" (ngModelChange)="doSomething($event)" [ngModel]="customer.firstName">

Класс:

doSomething(event) {
  console.log(event); // logs model value
}

DEMO

Ответ 3

Вы не можете просматривать изменения в объекте. Его не angular 1 здесь нет наблюдателей. Другое решение будет через наблюдаемые.

использовать форму

<form #f="ngForm">
  <input type="text" name="firstName" [(ngModel)]="customer.firstName">
  <input type="text" name="favoriteColor" [(ngModel)]="customer.favoriteColor">
</form>

в коде

@ViewChild('f') f;

ngAfterViewInit() {
  this.f.form.valueChanges.subscribe((change) => {
   console.log(change)
  })
}

Ответ 4

Вы можете использовать настраиваемые сеттеры для запуска обратного вызова:

class Customer {
  private _firstName: string
  get firstName(): string {
    return this._firstName
  }
  set firstName(firstName: string) {
    this.valueChanged(this._firstName, firstName)
    this._firstName = firstName
  }

  private _lastName: string
  get lastName(): string {
    return this._lastName
  }
  set lastName(lastName: string) {
    this.valueChanged(this._lastName, lastName)
    this._lastName = lastName
  }

  valueChanged: (oldVal, newVal) => void

  constructor (valueChanged?: (oldVal, newVal) => void) {
    // return an empty function if no callback was provided in case you don't need
    // one or want to assign it later
    this.valueChanged = valueChanged || (() => {})
  }
}

Затем просто назначьте обратный вызов при создании объекта:

this.customer = new Customer((oldVal, newVal) => console.log(oldVal, newVal))

// or

this.customer = new Customer()
this.customer.valueChanged = (oldVal, newVal) => console.log(oldVal, newVal)

Ответ 5

посетите https://github.com/cartant/rxjs-observe. основывается на rxjs и прокси.

import { observe } from "rxjs-observe";

const instance = { name: "Alice" };
const { observables, proxy } = observe(instance);
observables.name.subscribe(value => console.log(name));
proxy.name = "Bob";

Ответ 6

Вы можете увидеть эту статью, может быть, это поможет.

constructor(private ref: ChangeDetectorRef) {}
removeSomthing(){
    this.items.split(idx, 1);
    // run manually watcher
    this.ref.detectChanges();
}