Angular (v5+) - Snackbar "openFromComponent", 组件通信
Angular (v5+) - Snackbar "openFromComponent", component communication
Angular (v5.2.10) Snackbar
--|介绍 |--
我有一个 Angular 组件(我们称之为 "Parent")初始化一个名为 snackBar
的 Angular material Snackbar。传入的是 SnackbarMessage
,这是另一个具有包含 snackbar 标记的模板的组件。在这种情况下使用 snackBar.openFromComponent(SnackBarMessage)
是必要的,因为我需要在小吃栏中使用的不仅仅是纯文本 [如标记、点击事件等],而 snackBar.open(message, action)
是不够的。
--|代码|--
"Parent"分量:
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html'
})
export class Parent implements AfterViewInit {
public constructor(public snackBar: MatSnackBar) { }
public ngAfterViewInit(): void {
this.snackBar.openFromComponent(SnackbarMessage);
}
public dismissSnackbar(): void {
this.snackBar.dismiss();
}
}
"SnackbarMessage"分量:
@Component({
selector: 'app-snackbar-message',
templateUrl: './snackbar-message.html'
})
export class SnackbarMessage { }
"snackbar-message.html" 标记:
<p>(Snackbar message)</p>
<button type="button" (click)="dismissSnackbar();">Dismiss</button>
--|问题 |--
在导入的SnackbarMessage
模板(snackbar-message.html)中,我需要调用Parent组件的dismissSnackbar();
,我们如何使用这个Angular应用程序的当前封装来做到这一点?
您实际上不需要调用父组件的 "dismissSnackbar()" 方法来关闭快餐栏。您可以简单地将 "MatSnackBar" 注入到 "SnackbarMessage" 组件中,然后在注入的 "MatSnackBar" 实例上调用 "dismiss()" 方法。如 docs 中所写,这将隐藏当前可见的 Snackbar,即在您的示例中使用 "SnackbarMessage" 组件打开的 Snackbar。以下是您更新后的 "SnackbarMessage" 组件:-
"SnackbarMessage"分量:
@Component({
selector: 'app-snackbar-message',
templateUrl: './snackbar-message.html'
})
export class SnackbarMessage {
constructor(public snackBar: MatSnackBar) {}
public dismissSnackbar(): void {
this.snackBar.dismiss();
}
}
yatharth 的解决方案将起作用。
但是,如果您想让您的组件面向未来,您应该使用服务。通过服务,您可以从应用程序的任何位置关闭您的小吃店——而不仅仅是像他的方法那样的小吃店消息组件。
创建一个可观察流,并在您的 snackbar 组件中订阅它。它只会传递一个布尔值(true 或 false),每次在流中发出新值时,您都可以使用该值切换您的 snackbar 组件。
简单示例:
@Injectable()
export class SnackbarService {
status: BehaviorSubject<boolean> = new BehaviorSubject(false);
status$: Observable<boolean> = this.status.asObservable();
}
@Component({
selector: 'app-snackbar-message',
templateUrl: './snackbar-message.html'
})
export class SnackbarMessage {
open: boolean = false;
constructor(public snackbarService: SnackbarService) {
snackbarService.status$.subscribe((open: boolean) => this.open = open);
}
}
现在,在您应用的任何位置,您只需打开快餐栏:
snackbarService.status.next(true);
或者关闭快餐栏:
snackbarService.status.next(false);
如果您想要获得的案例不只是 open/closed,您可以使用具有不同值的枚举:
export enum SnackbarStatus {
Open,
Closed,
SomethingElse
}
在您的可观察流中传递枚举,而不是布尔值:
@Injectable()
export class SnackbarService {
status: BehaviorSubject<SnackbarStatus> = new BehaviorSubject(SnackbarStatus.Closed);
status$: Observable<SnackbarStatus> = this.status.asObservable();
}
我今天使用 MatSnackBar.openFromTemplate
而不是 MatSnackBar.openFromComponent
解决了一个与您类似的问题。使用这种方法,子组件的所有功能都可以直接从父组件访问。
'Parent Component' 充当 MatSnackBar
和 SnackBarMessageComponent
之间的 'Mediator' class。现在,SnackBarMessageComponent
与 MatSnackBar 分离,成为一个普通组件,可以重命名为 MessageComponent
。您可以使用 @Input
和 @Output
在父组件和子组件之间发送和接收数据。您可以根据需要添加任意数量的 @Input
或 @Output
。
代码超过 1.000 个字:
parent.component.html
<h1>parent component</h1>
<ng-template #snackBarTemplate>
<app-message [msg]="message" (onDismissClick)="dismissSnackbar"></app-message>
</ng-template>
parent.component.ts
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html'
})
export class Parent implements AfterViewInit {
@ViewChild('snackBarTemplate')
snackBarTemplate: TemplateRef<any>;
public message: string;
public constructor(public snackBar: MatSnackBar) { }
public ngAfterViewInit(): void {
this.message = '(Snackbar message)';
this.snackBar.openFromTemplate(snackBarTemplate);
}
public dismissSnackbar(): void {
this.snackBar.dismiss();
}
}
message.component.ts
@Component({
selector: 'app-message',
templateUrl: './message.html'
})
export class MessageComponent {
@Input()
msg: string;
@Output()
onDismissClick= new EventEmitter<any>();
dismissClicked() {
this.onDismissClick.emit(null);
}
}
message.component.html
<p>{{msg}}</p>
<button type="button" (click)="dismissClicked()">Dismiss</button>
(以上代码未经测试)
使用 ComponentRef 调用您的方法。
MyCustomSnackBarComponent 使用您的自定义方法
public miMethod(): void {
console.log('call from parent');
}
您在其中创建 MyCustomSnackBarComponent 实例的组件:
const snackBarRef = this.snackbar.openFromComponent(MyCustomSnackBarComponent);
snackBarRef.instance.miMethod();
如果您的方法有参数,此解决方案仍然适用
Angular (v5.2.10) Snackbar
--|介绍 |--
我有一个 Angular 组件(我们称之为 "Parent")初始化一个名为 snackBar
的 Angular material Snackbar。传入的是 SnackbarMessage
,这是另一个具有包含 snackbar 标记的模板的组件。在这种情况下使用 snackBar.openFromComponent(SnackBarMessage)
是必要的,因为我需要在小吃栏中使用的不仅仅是纯文本 [如标记、点击事件等],而 snackBar.open(message, action)
是不够的。
--|代码|--
"Parent"分量:
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html'
})
export class Parent implements AfterViewInit {
public constructor(public snackBar: MatSnackBar) { }
public ngAfterViewInit(): void {
this.snackBar.openFromComponent(SnackbarMessage);
}
public dismissSnackbar(): void {
this.snackBar.dismiss();
}
}
"SnackbarMessage"分量:
@Component({
selector: 'app-snackbar-message',
templateUrl: './snackbar-message.html'
})
export class SnackbarMessage { }
"snackbar-message.html" 标记:
<p>(Snackbar message)</p>
<button type="button" (click)="dismissSnackbar();">Dismiss</button>
--|问题 |--
在导入的SnackbarMessage
模板(snackbar-message.html)中,我需要调用Parent组件的dismissSnackbar();
,我们如何使用这个Angular应用程序的当前封装来做到这一点?
您实际上不需要调用父组件的 "dismissSnackbar()" 方法来关闭快餐栏。您可以简单地将 "MatSnackBar" 注入到 "SnackbarMessage" 组件中,然后在注入的 "MatSnackBar" 实例上调用 "dismiss()" 方法。如 docs 中所写,这将隐藏当前可见的 Snackbar,即在您的示例中使用 "SnackbarMessage" 组件打开的 Snackbar。以下是您更新后的 "SnackbarMessage" 组件:-
"SnackbarMessage"分量:
@Component({
selector: 'app-snackbar-message',
templateUrl: './snackbar-message.html'
})
export class SnackbarMessage {
constructor(public snackBar: MatSnackBar) {}
public dismissSnackbar(): void {
this.snackBar.dismiss();
}
}
yatharth 的解决方案将起作用。
但是,如果您想让您的组件面向未来,您应该使用服务。通过服务,您可以从应用程序的任何位置关闭您的小吃店——而不仅仅是像他的方法那样的小吃店消息组件。
创建一个可观察流,并在您的 snackbar 组件中订阅它。它只会传递一个布尔值(true 或 false),每次在流中发出新值时,您都可以使用该值切换您的 snackbar 组件。
简单示例:
@Injectable()
export class SnackbarService {
status: BehaviorSubject<boolean> = new BehaviorSubject(false);
status$: Observable<boolean> = this.status.asObservable();
}
@Component({
selector: 'app-snackbar-message',
templateUrl: './snackbar-message.html'
})
export class SnackbarMessage {
open: boolean = false;
constructor(public snackbarService: SnackbarService) {
snackbarService.status$.subscribe((open: boolean) => this.open = open);
}
}
现在,在您应用的任何位置,您只需打开快餐栏:
snackbarService.status.next(true);
或者关闭快餐栏:
snackbarService.status.next(false);
如果您想要获得的案例不只是 open/closed,您可以使用具有不同值的枚举:
export enum SnackbarStatus {
Open,
Closed,
SomethingElse
}
在您的可观察流中传递枚举,而不是布尔值:
@Injectable()
export class SnackbarService {
status: BehaviorSubject<SnackbarStatus> = new BehaviorSubject(SnackbarStatus.Closed);
status$: Observable<SnackbarStatus> = this.status.asObservable();
}
我今天使用 MatSnackBar.openFromTemplate
而不是 MatSnackBar.openFromComponent
解决了一个与您类似的问题。使用这种方法,子组件的所有功能都可以直接从父组件访问。
'Parent Component' 充当 MatSnackBar
和 SnackBarMessageComponent
之间的 'Mediator' class。现在,SnackBarMessageComponent
与 MatSnackBar 分离,成为一个普通组件,可以重命名为 MessageComponent
。您可以使用 @Input
和 @Output
在父组件和子组件之间发送和接收数据。您可以根据需要添加任意数量的 @Input
或 @Output
。
代码超过 1.000 个字:
parent.component.html
<h1>parent component</h1>
<ng-template #snackBarTemplate>
<app-message [msg]="message" (onDismissClick)="dismissSnackbar"></app-message>
</ng-template>
parent.component.ts
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html'
})
export class Parent implements AfterViewInit {
@ViewChild('snackBarTemplate')
snackBarTemplate: TemplateRef<any>;
public message: string;
public constructor(public snackBar: MatSnackBar) { }
public ngAfterViewInit(): void {
this.message = '(Snackbar message)';
this.snackBar.openFromTemplate(snackBarTemplate);
}
public dismissSnackbar(): void {
this.snackBar.dismiss();
}
}
message.component.ts
@Component({
selector: 'app-message',
templateUrl: './message.html'
})
export class MessageComponent {
@Input()
msg: string;
@Output()
onDismissClick= new EventEmitter<any>();
dismissClicked() {
this.onDismissClick.emit(null);
}
}
message.component.html
<p>{{msg}}</p>
<button type="button" (click)="dismissClicked()">Dismiss</button>
(以上代码未经测试)
使用 ComponentRef 调用您的方法。
MyCustomSnackBarComponent 使用您的自定义方法
public miMethod(): void {
console.log('call from parent');
}
您在其中创建 MyCustomSnackBarComponent 实例的组件:
const snackBarRef = this.snackbar.openFromComponent(MyCustomSnackBarComponent);
snackBarRef.instance.miMethod();
如果您的方法有参数,此解决方案仍然适用