Получение ошибки ExpressionChangedAfterItHasBeenCheckedError Я обновляю свойство компонента из другого компонента - PullRequest
0 голосов
/ 09 сентября 2018

Демо доступно здесь - https://stackblitz.com/edit/angular-a9wcee

Пожалуйста, откройте окно консоли, чтобы увидеть ошибку.

Описание У меня есть Bootstrap компонент ComponentA, который должен запускаться двумя различными способами в зависимости от процесса запуска приложения. Скажем, если приложение запускается с помощью URL home.com, тогда ComponentA не должно отображать всплывающее диалоговое окно при запуске, но если приложение запускается с использованием home.com;signup, приложение должно отображать всплывающее окно.

Я прочитал, что Input не работает для компонентов начальной загрузки, поэтому я передаю атрибут ComponentA из моего index.html в качестве "контекста запуска".

<comp-a someAttr="someValue"></comp-a> <!--depending on whether someAttr is empty ("") or not, the pop should not be shown or shown respectively -->

и ComponentA используют DialogComponent в своем шаблоне следующим образом

<comp-dialog [message]=""></comp-dialog> <!-- I want the input to ComponentB to be empty to begin with -->

ComponentB является диалоговым окном Bootstrap css и принимает сообщение Input, которое отображается, когда диалоговое окно становится видимым. Сложность в том, что ComponentB находится в шаблоне ComponentA и, таким образом, Angular инициализирует его как часть запуска ComponentA, но до того, как запуск ComponentA завершен, ComponentA пытается изменить ComponentB (свойство message), если оно определяет необходимость отображения диалогового окна (ComponentB) (путем проверки атрибута). Я думаю, что это создает проблемы с Change Detection, и я Angular выдает ExpressionChangedAfterItHasBeenCheckedError ошибку. Как я могу изменить дизайн взаимодействия компонентов

Фрагменты кода ComponentA

  • Проверьте, как меня начали.

     ngAfterViewChecked(){
        this.signup = this.el.nativeElement.getAttribute('signup'); //get the attribute
        this.isSignupProcess();//check if ComponentB needs to be shown and update its message property
      }
    
      isSignupProcess(){
        console.log("sign up is "+this.signup)
        if(this.signup!==""){ //show ComponentB
          if(this.signup === "success") {
            this.showDialog("Signup was successful",new DialogContext("","")) //set message property of ComponentB
          }else if(this.signup === "error") {
            this.showDialog("Error: Signup wasn't successful",new DialogContext("",""))
          } else {
            this.showDialog("Unrecognised message: "+this.signup,new DialogContext("",""))
          }
          this.signup = ""; //no need to show ComponentB
    
        } else {
    
        }
    

    }

логика для обновления message свойства ComponentB и показа

showDialog(message:string,context:DialogContext) {

    this.dialogComponent.dialogShow(message,context);
  }

ComponentB просто вызывает Bootstrap модальную функцию

dialogShow(message:string, context:DialogContext){
    this.dialogContext = context;
    this.dialogMessage = message;
    console.log("dialog got context ",this.dialogContext);
    $(this.dialogRef.nativeElement).modal('show');

  }

html из ComponentB является

<div #modal class="modal fade" tabindex="-1" role="dialog" id={{dialogID}}>
  <div class="modal-dialog modal-dialog-centered" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">CodingJedi</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="dialogHide()">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <p>{{dialogMessage}}</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal" (click)="dialogHide()">Close</button>
      </div>
    </div>
  </div>
</div>

1 Ответ

0 голосов
/ 12 сентября 2018

В статье хорошо объясняется, что вызывает ошибку - https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4

Цитирование по ссылке, Обнаружение изменений в Angular проходит следующие шаги 1) обновить привязанные свойства для всех дочерних компонентов / директив, т.е. значений интерполяции {{}} 2) вызвать хуки жизненного цикла ngOnInit, OnChanges и ngDoCheck для всех дочерних компонентов / директив 3) обновить DOM для текущего компонента 4) запустить обнаружение изменений для дочернего компонента 5) вызвать хук жизненного цикла ngAfterViewInit для всех дочерних компонентов / директив

После каждой операции Angular запоминает, какие значения он использовал для выполнения операции. Они хранятся в свойстве oldValues ​​представления компонента.

После того, как проверки выполнены для всех компонентов, Angular сравнивает текущие значения с теми, которые он запоминает из предыдущего цикла дайджеста: 1) проверьте, что значения, передаваемые дочерним компонентам, совпадают со значениями, которые теперь будут использоваться для обновления свойств этих компонентов 2) убедитесь, что значения, используемые для обновления элементов DOM, совпадают со значениями, которые будут использоваться для обновления этих элементов сейчас 3) выполнить одинаковые проверки для всех дочерних компонентов

После этого Angular запускает цикл проверки, чтобы проверить, что значения, используемые для создания дочерних компонентов и в DOM, остаются неизменными, в противном случае обнаружение изменений не стабилизируется после одного цикла и может завершиться бесконечным циклом. Если Angular обнаружит, что значение, использованное для создания дочернего компонента или использованное в DOM, изменилось до завершения текущего цикла обнаружения изменений, оно выдаст ExpressionChangedAfterItHasBeenCheckedError

В моем коде DialogComponent создается с начальными значениями dialogMessage и dialogContext. Теперь, в зависимости от того, как приложение запущено, я хочу обновить сообщение и показать диалоговое окно. Если я просто обновлю dialogMessage, Angular выдаст ошибку ExpressionChangedAfterItHasBeenCheckedError, поскольку значение dialogMessage изменилось до завершения текущего цикла обнаружения изменений.

Существует два способа решения проблемы. Используйте setTimeout, чтобы создать следующую задачу, которая будет выполнена после завершения текущей задачи обнаружения изменений ИЛИ после изменения dialogMessage из DialogBoxComponent, запустите обнаружение изменений снова, используя detectChanges()

ngAfterViewChecked(){
    setTimeout(()=>this.isSignupProcess());

    }

    OR
ngAfterViewChecked(){
    this.isSignupProcess(); 
    this.cd.detectChanges();
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...