javascript Angular 2/4 - Material Design Snackbars 按顺序显示多个消息

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47409869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 07:21:26  来源:igfitidea点击:

Angular 2/4 - Material Design Snackbars multiple message in sequence

javascriptangularangular-material

提问by ar099968

I have implemented a "snackbar service" that display a snackbar:

我已经实现了一个显示小吃店的“小吃店服务” :

snackbar.service.ts

小吃店.service.ts

import { Subscription } from 'rxjs/Subscription';
import { Subject } from 'rxjs/Subject';
import { Inject, Injectable, OnDestroy } from '@angular/core';
import { MatSnackBar, MdSnackBarConfig } from '@angular/material/snack-bar';
import { MdSnackBarRef, SimpleSnackBar } from '@angular/material/snack-bar';

export class SnackBarMessage  {
  message: string;
  action: string = null;
  config: MdSnackBarConfig = null;
}

@Injectable()
export class SnackBarService implements OnDestroy
{
    private messageQueue: Subject<SnackBarMessage> = new Subject<SnackBarMessage>();
    private subscription: Subscription;
    private snackBarRef:  MdSnackBarRef<SimpleSnackBar>;


    constructor(public snackBar: MatSnackBar){
        this.subscription = this.messageQueue.subscribe(message => { 
            this.snackBarRef = this.snackBar.open(message.message, message.action, message.config);
        });
    }

    ngOnDestroy() {
        this.subscription.unsubscribe();
    }

    /**
     * Add a message
     * @param message The message to show in the snackbar.
     * @param action The label for the snackbar action.
     * @param config Additional configuration options for the snackbar.
     */
    add(message: string, action?: string, config?: MdSnackBarConfig): void{

        if ( !config ){
            config = new MdSnackBarConfig();
            config.duration = 10000;
        }

        let sbMessage = new SnackBarMessage();
        sbMessage.message = message;
        sbMessage.action = action;
        sbMessage.config = config;

        this.messageQueue.next(sbMessage);
    }
}

I want display multiple snackbars in sequence:

我想按顺序显示多个小吃店:

test.component.ts

test.component.ts

import { Component } from '@angular/core';
import { SnackBarService } from 'app/core/services/snackbar.service';

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss']
})
export class TestComponent {

   constructor(public snackBarService: SnackBarService) {
     this.snackBarService.add('A');
     this.snackBarService.add('B');
     this.snackBarService.add('C');
   }
}

But all message are displayed at same time (overlapping).

但所有消息同时显示(重叠)。

How can I wait for a snackBar afterDismissedfor display a new message into messageQueue?

我怎样才能等待snackBar afterDismissed以将新消息显示到messageQueue 中?

采纳答案by Ankit

As @Aamir Khan pointed out - using afterDismissed, I have tweaked your code a bit.

正如@Aamir Khan 指出的那样-使用afterDismissed,我对您的代码进行了一些调整。

  showNext() {
  if (this.msgQueue === 0) {
    return;
  }

  let message = this.msgQueue.shift();
  this.isInstanceVisible = true;
  this.snackBarRef = this.snackBar.open(message.message, message.action, {duration: 2000});
  this.snackBarRef.afterDismissed().subscribe(() => {
    this.isInstanceVisible = false;
    this.showNext();
  });
}

And inside add()added this -

并在里面add()添加了这个 -

this.msgQueue.push(sbMessage);
if (!this.isInstanceVisible) {
     this.showNext(); 
}

Plunker

普朗克

Caution- Its kind of a dirty and non standard way, not an ideal user experience (IMO), above code might have some memory leaks and race conditions, due to usage of flags.

注意-这是一种肮脏和非标准的方式,不是理想的用户体验 (IMO),由于使用了标志,上面的代码可能存在一些内存泄漏和竞争条件。

回答by MaylorTaylor

Here is @Ankit's Plunker broken out here.

这是@Ankit 的 Plunker 在这里分解。

import {Subscription} from 'rxjs';
import {Injectable, OnDestroy} from '@angular/core';
import {MatSnackBar, MatSnackBarConfig} from '@angular/material/snack-bar';
import {MatSnackBarRef, SimpleSnackBar} from '@angular/material/snack-bar';
import {SnackBarMessage} from './snackBarMessage.model';

@Injectable()
export class NotificationService implements OnDestroy {
  private messageQueue: Array<any> = Array<any>();
  private subscription: Subscription;
  private snackBarRef: MatSnackBarRef<SimpleSnackBar>;
  private isInstanceVisible = false;

  constructor(public snackBar: MatSnackBar) {}

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
  /**
   * Add a message
   * @param message The message to show in the snackbar.
   * @param action The label for the snackbar action.
   * @param config Additional configuration options for the snackbar.
   * @param classOverride Adds a css class on the snackbar so you can add color.

   */
  show(
    message: string,
    action?: string,
    config?: MatSnackBarConfig,
    classOverride: string = 'blue-snackbar'
  ): void {
    if (!config) {
      config = new MatSnackBarConfig();
      config.duration = 3000;
      config.verticalPosition = 'bottom';
      config.horizontalPosition = 'end';
      config.panelClass = [classOverride];
    }

    const sbMessage = new SnackBarMessage();
    sbMessage.message = message;
    sbMessage.action = action;
    sbMessage.config = config;

    this.messageQueue.push(sbMessage);

    if (!this.isInstanceVisible) {
      this.showNext();
    }
  }

  private showNext() {
    if (this.messageQueue.length === 0) {
      return;
    }

    const message = this.messageQueue.shift();
    this.isInstanceVisible = true;

    this.snackBarRef = this.snackBar.open(
      message.message,
      message.action,
      message.config
    );

    this.snackBarRef.afterDismissed().subscribe(() => {
      this.isInstanceVisible = false;
      this.showNext();
    });
  }
}

回答by Vivek Doshi

You can achieve this by making these simple changes :

您可以通过进行这些简单的更改来实现这一点:

this.snackBarService.add(['A','B','C']); // pass messages as array

add(messages: Array<string>, action?: string, config?: MdSnackBarConfig): void{
    if ( !config ){
        config = new MdSnackBarConfig();
        config.duration = 10000;
    }

    let sbMessage = new SnackBarMessage();
    sbMessage.message = message;
    sbMessage.action = action;
    sbMessage.config = config;

    messages.forEach((message,index) => {
        setTimeout((message) => {
            sbMessage.message = message;
            this.messageQueue.next(sbMessage);
        },(config.duration*index);
    })
}

回答by Shailesh Ladumor

you need to use time out method. hide snackbar in specific time and open another snackbar using timeout function

您需要使用超时方法。在特定时间隐藏小吃店并使用超时功能打开另一个小吃店

constructor(public snackBarService: SnackBarService) {
          this.snackBarService.add('A')
          setTimeout(this.snackBarService.add('B'),10000);
          setTimeout(this.snackBarService.add('C'),20000);
       }

回答by Igor Simic

list of messages:

消息列表:

messages = [
  {
    text: "This is message 1",
  },
  {
    text: "This is message 2",
  }

];

];

loop through them and display one message after another

遍历它们并显示一条又一条消息

message.forEach( (message, index) => {

        setTimeout(() => {

            this.snackBar.open(message.text, action, {
                duration: this.timeOut,
                verticalPosition: 'bottom', // 'top' | 'bottom'
                horizontalPosition: 'end', //'start' | 'center' | 'end' | 'left' | 'right'
                panelClass: [className],
            });


        }, index * (this.timeOut+500)); // 500 - timeout between two messages

    });

demo:

演示:

https://www.coditty.com/code/angular-material-display-multiple-snackbars-messages-in-sequence

https://www.coditty.com/code/angular-material-display-multiple-snackbars-messages-in-sequence