Ionic 从页面中的另一个组件打开 Popover
Ionic open a Popover from another component within a page
我知道这里已经存在这个问题:
但我没有得到解决方案。
我有一个页面,其中包含一个带有按钮的工具栏组件。此按钮应触发页面内的功能。当我从页面内部触发该功能时,它会起作用。我还可以看到 popoverController 的 onInit 已填充,但稍后执行该函数时它是未定义的。
ERROR TypeError: Cannot read property 'create' of undefined
at HeaderComponent.push.6176.LocationSelectionPage.openAddLocation (location-selection.page.ts:92)
at HeaderComponent_ion_buttons_7_Template_ion_buttons_click_0_listener (template.html:14)
at executeListenerWithErrorHandling (core.js:15285)
at wrapListenerIn_markDirtyAndPreventDefault (core.js:15323)
at HTMLElement.<anonymous> (platform-browser.js:560)
at ZoneDelegate.invokeTask (zone.js:406)
at Object.onInvokeTask (core.js:28664)
at ZoneDelegate.invokeTask (zone.js:405)
at Zone.runTask (zone.js:178)
at ZoneTask.invokeTask [as invoke] (zone.js:487)
函数如下所示:
openAddLocation() {
this.popover
.create({
component: LocationAddPage,
cssClass: '',
showBackdrop: true,
})
.then((popoverElement) => {
popoverElement.present();
});
}
我有另一个弹出窗口可以正常工作,但它是在同一页面中触发的。
header.component.ts
import { Component, Input, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
})
export class HeaderComponent implements OnInit {
@Input() title: string;
@Input() openAddLocation: Function;
showBackBtn: boolean = false;
showMenuBtn: boolean = true;
path: string;
constructor(private router: Router) {}
ngOnInit() {
this.path = this.router.url;
if (/labsite-selection|retailers|location-selection/.test(this.path)) {
this.showBackBtn = true;
this.showMenuBtn = false;
} else {
this.showBackBtn = false;
this.showMenuBtn = true;
}
}
}
components.module.ts
import { NgModule } from '@angular/core';
import { IonicModule } from '@ionic/angular';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HeaderComponent } from './header/header.component';
import { SearchComponent } from './search/search.component';
@NgModule({
imports: [IonicModule, CommonModule, FormsModule],
declarations: [HeaderComponent, SearchComponent],
exports: [HeaderComponent, SearchComponent],
providers: [],
})
export class ComponentsModule {}
header.component.html
<ion-header mode="md">
<ion-toolbar color="primary">
<ion-title>{{ title }}</ion-title>
<ion-buttons slot="start">
<ion-menu-button *ngIf="showMenuBtn" autoHide="false"></ion-menu-button>
<ion-back-button
*ngIf="showBackBtn"
defaultHref="start"
></ion-back-button>
</ion-buttons>
<ion-buttons
*ngIf="path.includes('location-selection')"
slot="end"
(click)="openAddLocation()"
>
<ion-button>
<ion-icon slot="icon-only" name="add-outline"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
首先,解决方案。您以这种方式使用 app-header
组件:
<app-header [openAddLocation]="openAddLocation"></app-header>
并且您的页面中有以下代码:
openAddLocation() {
this.popover.create({
component: LocationAddPage,
cssClass: '',
showBackdrop: true,
}).then((popoverElement) => {
popoverElement.present();
});
}
你应该改成这样:
openAddLocation = () => {
this.popover.create({
component: LocationAddPage,
cssClass: '',
showBackdrop: true,
}).then((popoverElement) => {
popoverElement.present();
});
}
解释:
在第一种情况下,你传递了一个Function
。此方法不会将 this
上下文传递给组件。当组件尝试调用 @Input
函数时,它会调用组件的 this
而不是页面的 this
。
在第二种情况下,你传递了一个闭包。此处将在两次调用中使用页面的 this
。
另一种解决方案
我认为第一个解决方案对您来说很容易实现,但我认为这不是一个好方法。我认为使用 @Output
参数而不是 @Input
来调用函数会更好。
在你的 header.component.ts
:
- import { Component, Input, OnInit } from '@angular/core';
+ import { Component, EventEmitter, Input, Output, OnInit } from '@angular/core';
- @Input() openAddLocation: Function;
+ @Output() openAddLocation: EventEmitter<void> = new EventEmitter();
header.component.html
:
- (click)="openAddLocation()"
+ (click)="openAddLocation.emit()"
然后你就可以这样在你的页面上使用了:
<app-header (openAddLocation)="openAddLocation()"></app-header>
文档中关于 @Input
和 @Output
参数的更多信息:https://angular.io/guide/inputs-outputs
我知道这里已经存在这个问题:
我有一个页面,其中包含一个带有按钮的工具栏组件。此按钮应触发页面内的功能。当我从页面内部触发该功能时,它会起作用。我还可以看到 popoverController 的 onInit 已填充,但稍后执行该函数时它是未定义的。
ERROR TypeError: Cannot read property 'create' of undefined
at HeaderComponent.push.6176.LocationSelectionPage.openAddLocation (location-selection.page.ts:92)
at HeaderComponent_ion_buttons_7_Template_ion_buttons_click_0_listener (template.html:14)
at executeListenerWithErrorHandling (core.js:15285)
at wrapListenerIn_markDirtyAndPreventDefault (core.js:15323)
at HTMLElement.<anonymous> (platform-browser.js:560)
at ZoneDelegate.invokeTask (zone.js:406)
at Object.onInvokeTask (core.js:28664)
at ZoneDelegate.invokeTask (zone.js:405)
at Zone.runTask (zone.js:178)
at ZoneTask.invokeTask [as invoke] (zone.js:487)
函数如下所示:
openAddLocation() {
this.popover
.create({
component: LocationAddPage,
cssClass: '',
showBackdrop: true,
})
.then((popoverElement) => {
popoverElement.present();
});
}
我有另一个弹出窗口可以正常工作,但它是在同一页面中触发的。
header.component.ts
import { Component, Input, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
})
export class HeaderComponent implements OnInit {
@Input() title: string;
@Input() openAddLocation: Function;
showBackBtn: boolean = false;
showMenuBtn: boolean = true;
path: string;
constructor(private router: Router) {}
ngOnInit() {
this.path = this.router.url;
if (/labsite-selection|retailers|location-selection/.test(this.path)) {
this.showBackBtn = true;
this.showMenuBtn = false;
} else {
this.showBackBtn = false;
this.showMenuBtn = true;
}
}
}
components.module.ts
import { NgModule } from '@angular/core';
import { IonicModule } from '@ionic/angular';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HeaderComponent } from './header/header.component';
import { SearchComponent } from './search/search.component';
@NgModule({
imports: [IonicModule, CommonModule, FormsModule],
declarations: [HeaderComponent, SearchComponent],
exports: [HeaderComponent, SearchComponent],
providers: [],
})
export class ComponentsModule {}
header.component.html
<ion-header mode="md">
<ion-toolbar color="primary">
<ion-title>{{ title }}</ion-title>
<ion-buttons slot="start">
<ion-menu-button *ngIf="showMenuBtn" autoHide="false"></ion-menu-button>
<ion-back-button
*ngIf="showBackBtn"
defaultHref="start"
></ion-back-button>
</ion-buttons>
<ion-buttons
*ngIf="path.includes('location-selection')"
slot="end"
(click)="openAddLocation()"
>
<ion-button>
<ion-icon slot="icon-only" name="add-outline"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
首先,解决方案。您以这种方式使用 app-header
组件:
<app-header [openAddLocation]="openAddLocation"></app-header>
并且您的页面中有以下代码:
openAddLocation() {
this.popover.create({
component: LocationAddPage,
cssClass: '',
showBackdrop: true,
}).then((popoverElement) => {
popoverElement.present();
});
}
你应该改成这样:
openAddLocation = () => {
this.popover.create({
component: LocationAddPage,
cssClass: '',
showBackdrop: true,
}).then((popoverElement) => {
popoverElement.present();
});
}
解释:
在第一种情况下,你传递了一个Function
。此方法不会将 this
上下文传递给组件。当组件尝试调用 @Input
函数时,它会调用组件的 this
而不是页面的 this
。
在第二种情况下,你传递了一个闭包。此处将在两次调用中使用页面的 this
。
另一种解决方案
我认为第一个解决方案对您来说很容易实现,但我认为这不是一个好方法。我认为使用 @Output
参数而不是 @Input
来调用函数会更好。
在你的 header.component.ts
:
- import { Component, Input, OnInit } from '@angular/core';
+ import { Component, EventEmitter, Input, Output, OnInit } from '@angular/core';
- @Input() openAddLocation: Function;
+ @Output() openAddLocation: EventEmitter<void> = new EventEmitter();
header.component.html
:
- (click)="openAddLocation()"
+ (click)="openAddLocation.emit()"
然后你就可以这样在你的页面上使用了:
<app-header (openAddLocation)="openAddLocation()"></app-header>
文档中关于 @Input
和 @Output
参数的更多信息:https://angular.io/guide/inputs-outputs