Angular 6 View не обновляется после изменения переменной в подписке - PullRequest
0 голосов
/ 25 мая 2018

Почему представление не обновляется, когда переменная изменяется в подписке?

У меня есть этот код:

example.component.ts

testVariable: string;

ngOnInit() {
    this.testVariable = 'foo';

    this.someService.someObservable.subscribe(
        () => console.log('success'),
        (error) => console.log('error', error),
        () => {
            this.testVariable += '-bar';

            console.log('completed', this.testVariable);
            // prints: foo-Hello-bar
        }
    );

    this.testVariable += '-Hello';
}

example.component.html

{{testVariable}}

Но в окне отображается: foo-Hello .

Почему неон отображает: foo-Hello-bar ?

Если я позвоню ChangeDetectorRef.detectChanges() в рамках подписки, он отобразит правильное значение, но зачем мне это делать?

Я не должен вызывать этот метод из каждой подписки или вообще (угловая должна обрабатывать это).Есть ли правильный путь?

Я что-то упустил в обновлении от Angular / rxjs 5 до 6?

Прямо сейчас у меня Angular версии 6.0.2 и rxjs 6.0.0.Тот же код работает нормально в Angular 5.2 и rxjs 5.5.10 без необходимости вызова detectChanges.

1 Ответ

0 голосов
/ 04 июля 2018

Насколько я знаю, Angular обновляет только вид, если вы меняете данные в «Angular zone».Асинхронный вызов в вашем примере не подходит для этого.Но если вы хотите, вы можете поместить его в угловую зону или использовать rxjs или извлечь часть кода в новый компонент для решения этой проблемы.Я объясню все:

1 Угловая зона

Наиболее распространенным использованием этого сервиса является оптимизация производительности при запуске работы, состоящей из одного или нескольких асинхронныхзадачи, которые не требуют обновлений пользовательского интерфейса или обработки ошибок для обработки Angular.Такие задачи могут быть запущены с помощью runOutsideAngular, и при необходимости эти задачи могут повторно войти в угловую зону с помощью run .https://angular.io/api/core/NgZone

Ключевая часть - это функция запуска.Вы можете внедрить NgZone и поместить свое обновление значения в обратный вызов run объекта NgZone:

constructor(private ngZone: NgZone ) { }
testVariable: string;

ngOnInit() {
   this.testVariable = 'foo';

   this.someService.someObservable.subscribe(
      () => console.log('success'),
      (error) => console.log('error', error),
      () => {
      this.ngZone.run( () => {
         this.testVariable += '-bar';
      });
      }
   );
}

Согласно этому ответу, это приведет к тому, что все приложение обнаружит изменения, тогда как вашПодход ChangeDetectorRef.detectChanges обнаружил бы изменения только в вашем компоненте и его потомках.

2 RxJS

Другим способом было бы использовать rxjs для обновления представления.Когда вы впервые подписываетесь на ReplaySubject , это даст вам последнее значение.A BehaviorSubject в основном то же самое, но позволяет вам определить значение по умолчанию (имеет смысл в вашем примере, но не обязательно всегда будет правильным выбором).После этого начального излучения это обычный субъект воспроизведения:

this.testVariable = 'foo';
testEmitter$ = new BehaviorSubject<string>(this.testVariable);


ngOnInit() {

   this.someService.someObservable.subscribe(
      () => console.log('success'),
      (error) => console.log('error', error),
      () => {
         this.testVariable += '-bar';
         this.testEmitter.next(this.testVariable);
      }
   );
}

По вашему мнению, вы можете подписаться на тему, используя async pipe:

{{testEmitter$ | async}}

3 Извлечение кода в новый компонент

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

Таким образом, новый компонент имеет следующий код:

@Input() testVariable = '';

И переменная testVariable назначается в HTML, как и раньше, с фигурными скобками.

В родительском представлении HTML вы можете затем передать переменную элемента parentelement дочернему элементу:

<app-child [testVariable]="testVariable"></app-child>

Таким образом, вы находитесь в угловой зоне.

4 Личные предпочтения

Мое личное предпочтение - использовать rxjs или компонентный способ.Использование Detechanges или NGZone кажется мне более хакерским.

...