У меня есть компонент 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>
Да, мы можем использовать свойство 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>
Если вы знаете, что в вашем коде будет несколько случаев, подобных этому, вы можете создать общий объект диалога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.
И вот! Вы можете вызвать этот компонент, указав тот, который хотите отобразить в параметре данных.