Как вы справляетесь с «Выражением изменилось после того, как оно было проверено» в загруженном Dynami c контенте? - PullRequest
0 голосов
/ 13 января 2020

Я использую вкладки материалов, чтобы показать кучу форм в моем приложении. У меня есть основная форма, которая делится некоторыми своими данными со вторичными формами, каждая из которых находится на отдельной вкладке, которые добавляются и удаляются динамически. Чтобы поделиться данными основной формы, я использую сервис, который содержит тему поведения, на которую подписываются другие формы. Вот мой сервис:

import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs";

@Injectable()
export class DataService {
    private MessageSource = new BehaviorSubject<any>({});

    getMessage = this.MessageSource.asObservable();

    constructor() {}

    setMessage(message: any) {
        this.MessageSource.next(message);
    }
}

В других моих формах я получаю данные и обновляю форму новыми значениями следующим образом:

        this.dataFromMain.getMessage.subscribe(message => {

            if (message.user) {
                this.form.patchValue({
                    user_name: message.user.name,
                    user_address: message.user.address,
                    user_city: message.user.city
                });
            }
            if (message.placeOfDecl) {
                this.form.patchValue({
                    placeOfDecl: message.placeOfDecl
                });
            }
            if (message.dateOfDecl) {
                this.form.patchValue({
                    dateOfDecl: message.dateOfDecl
                });
            }
            if (message.items) {
                this.form.patchValue({
                    item_id: message.items.id,
                    item_code: message.items.code,
                    item_desc: message.items.desc,

                });
            }
        });

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

Когда я помещаю вышеуказанный код в функцию ngAfterViewInit, только что созданная форма обновляется, но я также получаю ошибку "Expression has changed after it was checked".

Чтобы решить эту проблему, я использовал один и тот же код на ngOnInit и ngAfterViewInit.

Я подозреваю, что я делаю что-то не так или что-то упускаю. Повторение одного и того же кода в двух местах кажется неправильным. Не так ли?

Вот блиц ... https://stackblitz.com/edit/my-dynamic-tabs

Ответы [ 3 ]

1 голос
/ 15 января 2020

Проблема здесь двоякая. Во-первых, MessageSource - это BehaviorSubject - и специфика c c из BehaviorSubject заключается в том, что оно предоставляет значение сразу после вызова Subscribe.

Вторая проблема что вы вызываете Subscribe в OnInit и / или AfterViewInit, где это должно быть вызвано в конструкторе вашего компонента.

Что это за ошибка? Эта указанная ошибка c возникает, когда свойство компонента обновляется во время цикла обнаружения изменений (см. Angular Захваты жизненного цикла ). Если свойство компонента обновляется как побочный эффект обнаружения изменений, то, скорее всего, DOM и свойство больше не будут синхронизированы c - следовательно, выдается ошибка. Это говорит о том, что вы написали неверный код.

Причина, по которой вы получаете эту ошибку, заключается в том, что, хотя при вызове Subscribe указывается лямбда, тот факт, что вы вызываете Subscribe на BehaviorSubject означает, что лямбда вызывается немедленно, перед следующей строкой кода после Subscribe. Это так же, как если бы у вас не было звонка, чтобы подписаться в первую очередь, и просто пропустили прямо к MessageSource.value.

Эффект заключается в обновлении компонента во время цикла обнаружения изменений . Причина, по которой это работает, когда вы pipe функция delay, заключается в том, что delay ставит в очередь подписку для выполнения после завершения жизненного цикла. Это на самом деле не решает вашу проблему с дизайном, просто бумаги над ней.

Некоторые вопросы, которые вы должны рассмотреть:

  1. Зачем вам нужно BehaviorSubject в служба? Как правило, это не очень хорошая практика проектирования.

    a. Если вы хотите получить свойство CurrentMessage, вы можете отправить его вместе с темой.

  2. Почему вы не подписываетесь на услугу в одном из следующих мест / времен: (а) когда требуется вызов данных (б) конструктор компонента (c) set свойства службы (если он предоставляется позже, а не как зависимость)?

0 голосов
/ 15 января 2020

Я нашел решение, опубликованное где-то на github ... Я вставил задержку перед подпиской на наблюдаемое, как это:

 this.dataFromMain.getMessage
              .pipe(delay(0))
              .subscribe(message => {

       //rest of code

Теперь это вызывается только внутри функции ngAfterViewInit и ошибка ушел Но я думаю, что это всего лишь обходной путь ...

0 голосов
/ 13 января 2020

Подскажите, пожалуйста, когда ваш BehaviorSubject уволен?

Почему бы вам не использовать EventEmitter в вашем сервисе

 private messageSource EventEmitter<any> = new EventEmitter();

getMessage() {
    return this.messageSource;
  }

setMessage(message: any) {
    this.messageSource.emit(message);
  }

, а затем в вашем компоненте

ngOnInit() {
    this.subscription = this.dataService.getMessage()
      .subscribe(message => //initialize your form here);
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...