Реализация кнопки закрытия компонента в диалоговом окне

У меня есть компонент A, который обычно должен отображаться без кнопки закрытия. Однако, когда я открываю компонент A в диалоговом окне, я хочу добавить кнопку «Закрыть», чтобы закрыть диалоговое окно.

Как я могу реализовать это поведение в Angular? Есть ли элегантный способ определить, открыт ли компонент в диалоговом окне, чтобы я мог соответственно добавить кнопку закрытия?

Заранее спасибо за вашу помощь!

Вот мой код: https://stackblitz.com/edit/stackblitz-starters-p4pfnr?file=src%2Fapp%2Fb%2Fb.comComponent.ts

ПОЛНЫЙ КОД:

всплывающее окно HTML

<form [formGroup] = "form" class = "">
  <h1>App A</h1>

  <mat-form-field>
    <mat-label>Email</mat-label>
    <input
      matInput
      type = "email"
      formControlName = "email"
      placeholder = "Ex. [email protected] "
    />
  </mat-form-field>

  <button mat-button type = "button" color = "primary">Save</button>
</form>

всплывающее окно ТС

import { Component } from '@angular/core';
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
import { FormControl, FormGroup } from '@angular/forms';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';

@Component({
  selector: 'app-a',
  standalone: true,
  imports: [
    FormsModule,
    ReactiveFormsModule,
    MatFormFieldModule,
    MatInputModule,
    MatButtonModule,
  ],
  templateUrl: './a.component.html',
  styleUrl: './a.component.css',
})
export class AComponent {
  form: FormGroup;

  constructor() {
    this.form = new FormGroup({
      email: new FormControl(''),
    });
  }
}

звоню ТС

import { Component } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { AComponent } from '../a/a.component';

@Component({
  selector: 'app-b',
  standalone: true,
  imports: [],
  templateUrl: './b.component.html',
  styleUrl: './b.component.css',
})
export class BComponent {
  constructor(public dialog: MatDialog) {}

  public openDialog() {
    this.dialog
      .open(AComponent, {})
      .afterClosed()
      .subscribe((res) => {
        console.info(res);
      });
  }
}

вызов HTML

<button (click) = "openDialog()" mat-raised-button color = "primary" type = "button">
  Open Dialog
</button>
Тестирование функциональных 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
1
0
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Да, мы можем использовать свойство data второго аргумента метода open. мы устанавливаем свойство fromPopup как истинное, а затем читаем его на нашем компоненте!

Я использую декоратор angular @Optional, поэтому, даже если мы используем этот компонент вне всплывающего окна, мы все равно не получим ошибку внедрения зависимостей при попытке получить MAT_DIALOG_DATA

б тс

import { Component } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { AComponent } from '../a/a.component';

@Component({
  selector: 'app-b',
  standalone: true,
  imports: [AComponent],
  templateUrl: './b.component.html',
  styleUrl: './b.component.css',
})
export class BComponent {
  constructor(public dialog: MatDialog) {}

  public openDialog() {
    this.dialog
      .open(AComponent, {
        data: { fromPopup: true },
      })
      .afterClosed()
      .subscribe((res) => {
        console.info(res);
      });
  }
}

б HTML

<button (click) = "openDialog()" mat-raised-button color = "primary" type = "button">
  Open Dialog
</button>

<app-a />

ТС

import { Component, Inject, Optional } from '@angular/core';
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
import { FormControl, FormGroup } from '@angular/forms';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-a',
  standalone: true,
  imports: [
    FormsModule,
    ReactiveFormsModule,
    MatFormFieldModule,
    MatInputModule,
    MatButtonModule,
    CommonModule,
    MatDialogModule,
  ],
  templateUrl: './a.component.html',
  styleUrl: './a.component.css',
})
export class AComponent {
  form!: FormGroup;
  fromPopup = false;

  constructor(
    @Optional() @Inject(MAT_DIALOG_DATA) public data: { fromPopup: boolean }
  ) {
    this.fromPopup = !!data?.fromPopup;
    this.form = new FormGroup({
      email: new FormControl(''),
    });
  }
}

HTML

<form [formGroup] = "form" class = "">
  <h1>App A</h1>

  <mat-form-field>
    <mat-label>Email</mat-label>
    <input
      matInput
      type = "email"
      formControlName = "email"
      placeholder = "Ex. [email protected] "
    />
  </mat-form-field>

  <button mat-button type = "button" color = "primary">Save</button>
</form>
<button *ngIf = "fromPopup" mat-button [mat-dialog-close] = "true">
  shows only for popup!
</button>

Демо-версия Stackblitz

Если вы знаете, что в вашем коде будет несколько случаев, подобных этому, вы можете создать общий объект диалогаHandler и вызывать его всякий раз, когда захотите отобразить компонент в диалоговом окне. Назовем его modalHandlerComponent:

modalHandler.comComponent.ts

import { CommonModule } from '@angular/common';
import { Component, Inject, Type } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';

@Component({
  selector: 'app-dialogHandler',
  standalone: true,
  imports: [MatDialogModule, CommonModule],
  templateUrl: './dialogHandler.component.html',
  styleUrl: './dialogHandler.component.css',
})
export class DialogHandlerComponent {
  constructor(@Inject(MAT_DIALOG_DATA) public data: { component: Type<any> }) {}
}

Он получит компонент, который вы хотите внедрить, благодаря MAT_DIALOG_DATA, с помощью которого вы передаете данные в диалоговое окно пользовательского интерфейса материала.

модалХандлер.компонент.html

<h2 mat-dialog-title>A dialog with component injection. You can inject a title via data if you want.</h2>
<mat-dialog-content>
  <ng-container *ngComponentOutlet = "data.component"></ng-container>
</mat-dialog-content>
<mat-dialog-actions>
  <button mat-button mat-dialog-close>Close button</button>
</mat-dialog-actions>

Затем компонент отобразит компонент благодаря ng-контейнеру.

б.компонент.тс

import { Component } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { AComponent } from '../a/a.component';
import { DialogHandlerComponent } from '../dialogHandler/dialogHandler.component';

@Component({
  selector: 'app-b',
  standalone: true,
  imports: [],
  templateUrl: './b.component.html',
  styleUrl: './b.component.css',
})
export class BComponent {
  constructor(public dialog: MatDialog) {}

  public openDialog() {
    this.dialog
      .open(DialogHandlerComponent, {
        data: {
          component: AComponent,
        },
      })
      .afterClosed()
      .subscribe((res) => {
        console.info(res);
      });
  }
}

Здесь мы внедряем компонент, который хотим отображать в диалоговом окне, в компонент диалогаHandler через MAT_DIALOG_DATA.

И вот! Вы можете вызвать этот компонент, указав тот, который хотите отобразить в параметре данных.

Демо-версия Stackblitz

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