Hi,
my component has this function:
async showToasts() {
const toast = await this.toastController.create({
message: "A",
duration: 3000
});
toast.present();
const toast2 = await this.toastController.create({
message: "B",
duration: 3000
});
toast2.present();
const toast3 = await this.toastController.create({
message: "C",
duration: 3000
});
toast3.present();
}
I expect to see those toasts stacked one after another. But all toasts are shown at the same position overlying each other, so that they can`t be read by the user.
Is this expected? Is it possible to show the toasts stacked below each other?
Thank you!
Hi. Thx for this. With the issue you kind-of dismissed the idea for not being md spec
Has this changed and/or how can the community act to get this feature implemented?
I think if were to implement this it would be in the form of a queue where only one toast is displayed at a time. Each additional toast would be displayed once the previous toast is dismissed.
In terms of displaying multiple toasts at once, that decision has not changed. The Material Design spec considers stacking toasts/snackbars to be an anti-pattern: Material Design
edit: The link does not go to the exact section, but if you look for âConsecutive snackbarsâ you should find the section I am referring to.
2 Likes
I created a queue controller for my app to display toasts one after another.
import { ToastButton } from '@ionic/core'
import { toastController as IonicToastController } from '@ionic/vue'
export enum ToastType {
Info,
Success,
Warning,
Error
}
export class ToastItem {
message = ''
type = ToastType.Info
buttonText?: string | undefined
duration = 3000
buttonHandler?: (() => void) | undefined
}
export class ToastController {
private toasts = Array<ToastItem>()
private isProcessing = false
public createWithJustMessage(message: string, type: ToastType): void {
const item = new ToastItem()
item.message = message
item.type = type
this.create(item)
}
public create(toast: ToastItem): void {
this.toasts.push(toast)
if (!this.isProcessing) {
this.isProcessing = true
this.process()
}
}
private async process(): Promise<void> {
const toast = this.toasts.shift()
if (toast === undefined) {
this.isProcessing = false
return
}
const buttons = Array<ToastButton>()
if (toast.buttonText) {
buttons.push({
text: toast.buttonText,
handler: toast.buttonHandler,
})
}
const toastController = await IonicToastController.create({
message: toast.message,
color: this.getColorFromType(toast.type),
buttons: buttons,
position: 'bottom',
duration: toast.duration,
cssClass: 'toasts-bottom',
})
toastController.onDidDismiss().then(() => {
this.process()
})
await toastController.present()
}
private getColorFromType(type: ToastType): string {
switch (type) {
case ToastType.Success:
return 'success'
case ToastType.Warning:
return 'warning'
case ToastType.Error:
return 'danger'
case ToastType.Info:
default:
return 'primary'
}
}
}
To use:
// instances.ts
// Create a single instance somewhere to be used throughout the app
// Not sure if this is the best way to do this but it works for me
import { ToastController } from '@/utils/toast-controller'
export const toastControllerInstance = new ToastController()
// Use throughout the app
import { toastControllerInstance } from '@/instances'
toastControllerInstance.createWithJustMessage(
'There was an issue loading your goals.',
ToastType.Warning
)
So toasts donât display on top of tabs, I added the toasts-bottom
class.
/* Fix so toasts don't overlay the tabs */
.md .toasts-bottom {
transform: translateY(-56px) !important;
}
.ios .toasts-bottom {
transform: translateY(-50px) !important;
}
1 Like
Thank you all for than clarification and code example. My solution now is, to put the string together and show it in one toast. I wanted to show the user multiple toasts like âThe item âabcâ could not be add because of reasonâ. I now combine the string to "The Items âabcâ, âdefâ, âghiâ could not be add because of reasonâ. Not perfect, but ok for me in that case.