Диалог материала Angular медленный, с нарушенным воспроизведением и привязкой

У меня есть приложение Angular 17, использующее Angular Material и редактор Angular Monaco v2 . Полную репродукцию можно найти на Stackblitz.

В приложении воспроизведения есть редактор Monaco, привязанный к клавишам CTRL+P. Когда вы нажимаете эту горячую клавишу, должно появиться диалоговое окно, оборачивающее HelloComponent в тот же проект. Это фиктивный компонент с одним текстовым полем, в котором вы можете ввести имя.

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

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

Описание проекта репродукции

Чтобы компонент ввода имени можно было использовать как в качестве «обычного» компонента, так и в качестве компонента, завернутого в диалог материала, он получает дополнительные инъекции в свой конструктор для MatDialogRef (чтобы он мог закрыть диалог, передавая данные обратно) и данные, опционально полученные путем внедрения. через токен MAT_DIALOG_DATA.

Данные имеют тип HelloData, который содержит только строковое свойство name. Во всплывающем окне должно отображаться полученное имя, если таковое имеется, и вы можете его редактировать. Когда вы нажмете на нее, он вернет новое имя.

На стороне компонента контейнера диалоговое окно открывается при нажатии клавиши CTRL+P на базовом экземпляре Monaco путем вызова insertText. Это получает текущий выбранный текст из Монако и открывает диалоговое окно, в котором этот текст передается в качестве редактируемого имени.

После закрытия диалогового окна с помощью кнопки «ОК» компонент контейнера позаботится о замене выделения новым именем, если таковое имеется.

Это полный шаблон компонента:

<div>
  <form [formGroup] = "form" (submit) = "save()">
    <mat-form-field>
      <input
        type = "text"
        matInput
        [formControl] = "inputName"
        placeholder = "name"
      />
    </mat-form-field>
    <p>Hello, {{ inputName.value }}!</p>
    <button mat-flat-button type = "submit">OK</button>
  </form>
</div>

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

export interface HelloData {
  name?: string;
}

@Component({
  selector: 'app-hello',
  standalone: true,
  imports: [
    CommonModule,
    FormsModule,
    ReactiveFormsModule,
    MatButtonModule,
    MatFormFieldModule,
    MatDialogModule,
    MatInputModule,
  ],
  templateUrl: './hello.component.html',
  styleUrl: './hello.component.css',
})
export class HelloComponent {
  public inputName: FormControl<string | null>;
  public form: FormGroup;

  constructor(
    formBuilder: FormBuilder,
    @Optional()
    public dialogRef?: MatDialogRef<HelloComponent>,
    @Optional()
    @Inject(MAT_DIALOG_DATA)
    public data?: HelloData
  ) {
    this.inputName = formBuilder.control(data?.name || null);
    this.form = formBuilder.group({
      name: this.inputName,
    });
  }

  public save(): void {
    this.dialogRef?.close(this.inputName.value);
  }
}

Наконец, вот как открывается и закрывается диалог:

private async promptName(name?: string): Promise<string | undefined> {
  this._cd.detach();
  const dialogRef = this._dialog.open(HelloComponent, {
    data: {
      name,
    },
  });
  const result: HelloData | undefined = await firstValueFrom(
    dialogRef.afterClosed()
  );
  this._cd.reattach();
  this._cd.detectChanges();
  return result?.name;
}
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
0
98
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, что команды, выполняемые monaco, обрабатываются за пределами NgZone, поэтому обнаружение изменений вообще не инициируется. А поскольку он находится за пределами зоны, ручная проверка изменений на ChangeDetectorRef тоже не даст никаких результатов. Это приводит к тому, что чистый HTML передается в DOM без других вещей, которые активируются при обнаружении изменений.

Вам следует обернуть дескриптор команды ngZone.run. Введите зону:

constructor(private _dialog: MatDialog, private ngZone: NgZone) {}

А затем оберните обработчик ngZone.run:

this._editor.addCommand(
  monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyP,
  async () => {
    this.ngZone.run(async () => await this.insertText());
  }
);

Вот рабочая вилка вашего stackblitz.

В целом, я бы предположил, что если вы используете оболочку Angular для Монако, она должна обрабатывать подобные вещи, поэтому вам, вероятно, следует создать проблему в соответствующем репозитории git.

Спасибо! Stackblitz теперь работает, хотя я не смог протестировать его на своем реальном приложении, потому что оно все еще страдает от проблемы компиляции, возникшей в самых последних версиях Angular+Monaco. Я тоже попробую там, как только с этим разберутся.

Naftis 11.04.2024 22:28

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