Может ли объект быть уведомлен, когда объект компонента изменяется в Angular 2/4?

В Angular компонент может получить как @Input() переменная или объект. Всякий раз, когда переменная изменяется, Angular уведомляет компонент. Очень круто...

Я пытаюсь создать приложение, которое показывает ng2-tree вид слева и вид редактирования справа. Когда пользователь нажимает на узел в дереве, подробности этого элемента отображаются справа, и пользователь может изменять свойства этого элемента. Что мне нужно, чтобы эти изменения распространились обратно к дереву.

Отдельные узлы в дереве являются ItemTreeNode:

export class ItemTreeNode implements TreeModel {
  value: string;
  id: string;
  children: Array<ItemTreeNode>;
  icon: string;
  settings: TreeModelSettings;
  loadChildren;

  constructor(
    private itemService: ItemService,
    private parent_id: string,
    public item: Item
  ){ ... }
}

Дерево визуализирует узел, используя .value для имени. Это устанавливается во время конструктора, вызывая this.item.nodeName(), После установки оно не меняется. Проблема в том, что он должен меняться всякий раз, когда меняется элемент.

То, что я ищу, - это способ уведомления этого объекта об изменении элемента, чтобы value свойство может быть обновлено.

Есть ли способ для ItemTreeNode "наблюдать" за элементом и получать обратный вызов, если он когда-либо изменится, как часть цикла обнаружения изменений Angular?

Или есть лучший способ реализовать желаемое поведение?

1 ответ

Это можно сделать с помощью RxJs. Давайте прервём настройку имени Предмета через сеттер и запустим Observable .next(),

import {BehaviorSubject} from 'rxjs/BehaviorSubject'

class Item {
  private _name: string;
  private nameSource = new BehaviorSubject<string>('');
  name$ = this.nameSource.asObservable();

  set name(name: string) {
    this._name = name;
    this.nameSource.next(name);
  } 

  get name() { return this._name; } 

  getNodeName() { return this._name + ' !!!'; }

  constructor(name: string){
    this._name = name;
  }
}

Видите ли, я нажимаю название оригинального предмета на this.nameSource.next(name), В моем примере я предполагаю, что имя элемента и имя узла являются разными. наблюдаемый $name Публично, это для внешних подписок. Затем мне нужно подписаться на изменение имени элемента, и лучшее место для этого - конструктор ItemTreeNode, который получает экземпляр элемента в качестве параметра:

class Node {
  value: string;

  constructor(item: Item) {
    item.name$.subscribe(result => this.value = item.getNodeName());
  }
}

Здесь result это новое имя предмета, но так как оно не совпадает с именем узла предмета, я делаю дополнительный вызов .getNodeName(), Поэтому единственное, что вам нужно сделать, это передать экземпляр Item конструктору Node, и тогда RxJs выполнит магию привязывания за вас.

this.item = new Item('My Name');
const node = new Node(this.item);

Вот и все, я создал Plunker, чтобы продемонстрировать этот подход.

Другие вопросы по тегам