【问题标题】:Angular (v5+) - Snackbar "openFromComponent", component communicationAngular (v5+) - Snackbar “openFromComponent”,组件通信
【发布时间】:2018-10-29 03:58:59
【问题描述】:

Angular (v5.2.10) Snackbar

--|简介 |--
我有一个 Angular 组件(我们称之为“父级”)初始化一个名为 snackBar 的 Angular 材质 Snackbar。传入的是 SnackbarMessage ,这是另一个带有包含小吃栏标记的模板的组件。在这种情况下使用snackBar.openFromComponent(SnackBarMessage) 是必要的,因为我需要在小吃栏中使用的不仅仅是纯文本[如标记、点击事件等],而snackBar.open(message, action) 是不够的。

--|代码 |--

“父”组件:

@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 应用程序的当前封装来做到这一点?

【问题讨论】:

    标签: angular typescript angular-components snackbar


    【解决方案1】:

    您实际上不需要调用父组件的“dismissSnackbar()”方法来关闭snackbar。您可以简单地将“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();
        }
    }
    

    【讨论】:

    • 这不是太复杂+1
    • 如果您需要使用 MatSnackBarRef 中的方法,例如dismissWithAction(),你也可以注入它。 private matSnackBar: MatSnackBarRef&lt;MatSnackBar&gt;.
    【解决方案2】:

    yatharth 的解决方案会奏效。

    但是,如果您想让您的组件经得起未来的考验,您应该使用服务。借助服务,您可以从应用程序中的任何位置关闭您的小吃店——而不仅仅是像他的方法中的小吃店消息组件。

    创建一个可观察的流,并在您的快餐栏组件中订阅它。它只会传递一个布尔值(true 或 false),每次在流中发出新值时,您都可以使用该值切换您的快餐栏组件。

    简单示例:

    @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);
    

    或者这样关闭snackbar:

    snackbarService.status.next(false);
    

    如果您想获得更多的案例,而不仅仅是打开/关闭,您可以使用具有不同值的枚举:

    export enum SnackbarStatus {
        Open,
        Closed,
        SomethingElse
    }
    

    在您的可观察流中传递一个枚举,而不是布尔值:

    @Injectable()
    export class SnackbarService {
        status: BehaviorSubject<SnackbarStatus> = new BehaviorSubject(SnackbarStatus.Closed);
        status$: Observable<SnackbarStatus> = this.status.asObservable();
    }
    

    【讨论】:

    • 很好的解释,这个解决方案可以很好地满足我的需要。谢谢你好先生
    【解决方案3】:

    我今天使用MatSnackBar.openFromTemplate 而不是MatSnackBar.openFromComponent 解决了与您类似的问题。使用这种方法,子组件的所有功能都可以直接从父组件访问。

    “父组件”充当MatSnackBarSnackBarMessageComponent 之间的“中介”类。现在,SnackBarMessageComponent 与 MatSnackBar 解耦,成为一个普通组件,可以重命名为 MessageComponent。您可以使用普通的@Input@Output 在父组件和子组件之间发送和接收数据。您可以根据需要添加任意数量的@Inputs 或@Outputs。

    代码超过 1000 个单词:

    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>
    

    (以上代码未经测试)

    【讨论】:

      【解决方案4】:

      使用 ComponentRef 来调用你的方法。

      MyCustomSnackBarComponent 使用您的自定义方法

      public miMethod(): void { 
          console.log('call from parent');
      }
      

      您在其中创建了 MyCustomSnackBarComponent 实例的组件:

      const snackBarRef = this.snackbar.openFromComponent(MyCustomSnackBarComponent);
      snackBarRef.instance.miMethod();
      

      如果您的方法有参数,此解决方案仍然适用

      【讨论】:

        猜你喜欢
        • 2018-02-05
        • 2017-11-28
        • 2022-01-15
        • 1970-01-01
        • 2019-01-03
        • 2016-08-07
        • 2021-03-02
        • 2016-06-23
        相关资源
        最近更新 更多