Угловое интерполированное значение не обновляется при подписке

  • Угловой 6.0.1
  • нгРкс 6.0.1

У меня есть интерполированное значение, установленное в моем представлении:

{{firstName}}

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

Вот соответствующий код:

Подписка от моего компонента:

private subscribeToCurrentPerson(): void {
    this.tState$ = this.store
      .pipe(select(selectors.getCurrentPerson), takeWhile(() => this.componentActive))
      .subscribe((cp: Person) => {
        if (cp) {
          const name: string = cp.primaryName.value.parsedValue.givenNames[0];
          this.firstName = name;
          console.log('name: ' + name);  // <-- this shows correct new value
        }
  });
}

subscribeToCurrentPerson вызывается из компонента ngOnInit. До этого свойство firstName не было определено.

Селектор selectors.getCurrentPerson выглядит так:

export const getCurrentPerson: MemoizedSelector<{}, Person> = 
    createSelector(getTState, (tState: ITState) => {
      console.log('selector: ', tState); // <-- this logs the correct new value
      return tState ? tState.currentPerson : null;
    });  

Значение currentPerson, возвращаемое селектором, является вновь созданным объектом. Это происходит при первом запуске приложения, поэтому до этого tState не определено.

Если я введу ChangeDetectorRef в свой конструктор и вызову cdr.detectChanges() внутри подписки, пользовательский интерфейс обновится. Но мне кажется, что обычно мне не нужно использовать ChangeDetectorRef таким образом, что он должен «просто работать».

Я думаю, проблема в моем глубоко вложенном свойстве (cp.primaryName.value.parsedValue.givenNames). Я унаследовал эти объекты от проекта, отличного от ngRx, но я думаю, что мой следующий шаг — попытаться сгладить эту структуру, чтобы посмотреть, сделает ли это ngRx и детектор изменений Angular более счастливыми.

Есть ли что-то еще, что мне не хватает?

Спасибо,

ТТЭ

ОБНОВЛЕНИЕ

Я убрал глубоко вложенное свойство из картины, просто обновив локальное свойство моего компонента внутри подписки. Итак, функция subscribeToCurrentPerson теперь выглядит так:

private subscribeToCurrentPerson(): void {
        this.tState$ = this.store
          .pipe(select(selectors.getCurrentPerson), takeWhile(() => this.componentActive))
          .subscribe((cp: Person) => {
            this.myProp = 'goodbye';
            this['newProp'] = 'world';
      });
    }

myProp — это существующее свойство моего компонента, которое я добавил для тестирования. newProp не существует до тех пор, пока он не будет добавлен с помощью скобок внутри подписки. Вот результаты:

  • myProp не обновляется — показывает значение, которое я присвоил ему при объявлении. Однако, если я не назначу значение при объявлении свойства, то значение, назначенное в подписке, правильно отображается в пользовательском интерфейсе.
  • newProp отображается в пользовательском интерфейсе правильно

Я теперь совершенно сбит с толку. Похоже, что если у свойства есть значение, оно никогда не обновляется в пользовательском интерфейсе, даже если само значение изменяется (о чем я могу узнать, выполнив вход в консоль после обновления значения).

Я не устанавливаю явно ChangeDetectionStrategy для компонента, так что это Default.

Все работает, если я позвоню detectChanges, но я не думаю, что это необходимо.


person TimTheEnchanter    schedule 05.08.2018    source источник
comment
Поскольку вы комментируете свой предыдущий вопрос и показываете в stackblitz, что представление должно обновляться автоматически... Я столкнулся с той же проблемой как вы в моем собственном коде.   -  person ConnorsFan    schedule 05.08.2018
comment
какова ваша стратегия обнаружения изменений? По умолчанию или onPush?   -  person René Winkler    schedule 05.08.2018
comment
Я пробовал каждый, но в настоящее время по умолчанию.   -  person TimTheEnchanter    schedule 05.08.2018
comment
Похоже, вы правы, что касается глубоко вложенных свойств. Нет ничего особенного в том, что код находится вне зоны, кроме переназначений/вложенных свойств внутри конструктора. В конце концов, JS, естественно, не согласен с сильно вложенными объектами и переназначениями. Извините, я не мог быть более полезным, может быть, кто-то еще увидит что-то, чего не вижу я!   -  person Z. Bagley    schedule 05.08.2018
comment
НП, спасибо @Z.Bagley. Я убрал глубоко вложенные свойства из картины и теперь совершенно сбит с толку тем, что происходит (см. Мое обновление выше). Что-то мешает обновлению пользовательского интерфейса, когда свойство имеет значение, но я понятия не имею, что.   -  person TimTheEnchanter    schedule 05.08.2018
comment
Проверьте родительские компоненты на наличие OnPush обнаружения изменений.   -  person Meme Composer    schedule 05.08.2018
comment
И у нас есть победитель! @Dummy, у тебя неправильное название! Если вы вставите это в качестве ответа, я приму это. Спасибо!   -  person TimTheEnchanter    schedule 05.08.2018


Ответы (2)


Когда родительский компонент имеет свою стратегию обнаружения изменений, установленную на OnPush, тогда дерево компонентов этого родителя не будет проверяться механизмом обнаружения изменений angular, хотя этот родительский и его дочерний метод ngOnChanges по-прежнему вызываются каждый раз при изменении любых свойств @Input. Чтобы сообщить angular, что какой-то компонент в этом дереве нуждается в обновлении, введите ChangeDetectorRef в этот компонент и используйте его API для уведомления angular об обновлении, например, detectChanges или markForCheck

person Meme Composer    schedule 05.08.2018

Во многих случаях обновления данных из компонента не будут отражать шаблон HTML. В таком случае вы можете использовать интерполяцию с тернарными операторами.

 {{firstName ? firstName : ''}}

Меня устраивает. Надеюсь, это сработает

person Aashish Bhagwat    schedule 07.03.2019