Components: Unclear documentation about snackbar usage on documentation website

Created on 9 Feb 2017  路  16Comments  路  Source: angular/components

Bug, feature request, or proposal:

Documentation: Snackbar component is unclear, and its Plunker code example is not running

Details:

  1. It seems the Snackbar component documentation on website does not describe fully about how to open snackbar from component and what to do with MdSnackBarRef in API Reference tab while they are mentioned in Overview tab

  2. Plunker example in Examples tab of Snackbar component is not working.
    Reproduce steps:

    Notes:

    • Developer need to add PizzaPartyComponent in declarations and entryComponents of ngModule in main.ts file, plus create new template snack-bar-component-example-snack.html and component stylesheet snack-bar-component-example-snack.css for PizzaPartyComponent.
    • Plunker example: https://plnkr.co/edit/IVRsaVTFRiaHIHGXnhAw?p=preview
  3. The documentation does not describe how to execute the action of a component itself if that component is opened in snackbar.
    In the project source code, I've found that to execute the dismiss snackbar action when open snack bar from open method you guys did this:

  4. Create a self-reference with MdSnackBarRef of the content component: In class SimpleSnackBar, there is snackBarRef: MdSnackBarRef<SimpleSnackBar> property. To be able to dismiss snackbar, SimpleSnackBar component has to call dismiss() method, which in turn calls the _action() method of snackBarRef.
  5. In open method of MdSnackBar:
open(message: string, action = '', config: MdSnackBarConfig = {}): MdSnackBarRef<SimpleSnackBar> {
    config.announcementMessage = message;
    let simpleSnackBarRef = this.openFromComponent(SimpleSnackBar, config);
    simpleSnackBarRef.instance.snackBarRef = simpleSnackBarRef;
    simpleSnackBarRef.instance.message = message;
    simpleSnackBarRef.instance.action = action;
    return simpleSnackBarRef;
}

At line 4, the snackBarRef of instance SimpleSnackBar of simpleSnackBarRef was assigned to simpleSnackBarRef itself. Therefore, the snackbar component was able to close.

If I want to create a snackbar from a component with a dismiss/arbitrary button, then I have to do the same with my code. However, there is no instruction to do that with openFromComponent method. I think this should be documented clearer so developer can do that from looking at the documentation, not have to dig into the source code.
Plunker example: https://plnkr.co/edit/rOql4ebj2d5ynQpzutUW?p=preview

Which versions of Angular, Material, OS, browsers are affected?

Material: 2.0.0-beta1

docs help wanted

Most helpful comment

This is a good suggestion. I had to go through the sources of openFromComponent to find out information that should have been in the documentation or in the examples.

All 16 comments

This is a good suggestion. I had to go through the sources of openFromComponent to find out information that should have been in the documentation or in the examples.

Thanks @thanhpd for putting this together, really helpful. I guess the last missing piece is how we can send different messages from a custom component that is opened by the SnackBar. If I have a SnackBar with 2 buttons (i.e. cookie-law component). Could you share the API for that?

@tobi-or-not-tobi The buttons in your custom component can call its component methods as usual. Then you can close the snackbar by using MdSnackBarRef method within that custom component.
Here's an example: https://plnkr.co/edit/vU74mzYGrXiaiy1992Hz?p=preview

@thanhpd the example is broken :/

@M-a-c I think this is because Angular has updated it npm package to version 4, and Material2 is not ready beyond version 2. Updated the example to use fixed version of Angular2, should be working again.

Is there a way to set the background colour of a snack bar?

@xuanshenbo You can use extraClasses properties of MdSnackBarConfig to style built-in snackbar (source) or use your custom component, which should give you control over pretty much everything.
This kind of question should be asked in Gitter room so you can have faster responses. This issue is dedicated to documentation problem only.

@thanhpd Do you want to commit that code as an example? Do you mind if I base a commit explaining how this works? (my commit earlier does not address the main issue in this thread, though it is supposed to fix some docs stuff)

@M-a-c Please do that, it'll help a lot of people. I'm pretty busy these days so not sure how the documentation contribution works.

@thanhpd checkout the pr, let me know if you find something out of place :)

Docs don't seem to indicate how to distinguish between action and dismiss using openFromComponent. The only way seems to be to directly invoke the private method _action since both will trigger dismiss.

Might be worth adding to the example code in the docs that the custom component (in this case SimpleSnackBar) should contain onAction and onDismiss methods for invoking this.snackBarRef._action() and this.snackBarRef.dismiss(); to trigger the associated Observable responses.

Seems wrong to use the private method _action, but there isn't any other available method.

@Component({
  selector: 'app-simple-snackbar',
  templateUrl: './simple-snackbar.component.html',
  styleUrls: ['./simple-snackbar.component.scss']
})
export class SimpleSnackBarComponent {
  public snackBarRef: MdSnackBarRef<SimpleSnackBarComponent>;
  public message: string;
  public action: string;

  public onAction() { this.snackBarRef._action(); }
  public onDismiss() { this.snackBarRef.dismiss(); }
}
<div>
  <p>
    {{ message }}
  </p>

  <button md-button
          color="accent"
          (click)="onAction()">{{ action }}</button>

  <button md-button
          color="accent"
          (click)="onDismiss()">{{ dismiss }}</button>

</div>

Now, subscriptions are propagated through the reference:

const snackBarRef = this.open(...).onAction().subscribe(() => { 
  console.log('action was explicitly clicked');
});
const snackBarRef = this.open(...).afterDismissed().subscribe(() => {  
  console.log('regardless of how the snackbar has been dismissed');
});

This would be over documentation if written into the docs, but would be a good addition to the example code where action or dismiss responses could be bound to template to display a boolean indicating which occurred like other examples in the docs provide.

Added an issue for a public method for indicating an action has been performed in a custom snackbar - https://github.com/angular/material2/issues/5657

.snackbar { min-width: 250px; margin-left: -125px; background-color: #333; color: #fff; text-align: center; border-radius: 2px; padding: 16px; position: fixed; z-index: 1; left: 50%; bottom: 30px; }

<div class="snackbar" [@snack-visibility]="snackVisibility"> {{message}} </div>

`import { Component, OnInit } from '@angular/core';
import { trigger, state, style, transition, animate} from "@angular/animations"

import {NotificationService} from '../notification.service'
import {Observable} from 'rxjs/Observable'
import 'rxjs/add/observable/timer'
import 'rxjs/add/operator/do'
import 'rxjs/add/operator/switchMap'

@Component({
selector: 'mt-snackbar',
templateUrl: './snackbar.component.html',
styleUrls: ['./snackbar.component.css'],
animations: [
trigger('snack-visibility', [
state('hidden', style({
opacity: 0,
bottom: '0px'
})),
state('visible', style({
opacity: 1,
bottom: '30px'
})),
transition('hidden => visible', animate('500ms 0s ease-in')),
transition('visible => hidden', animate('500ms 0s ease-out'))
])
]
})
export class SnackbarComponent implements OnInit {

message: string

snackVisibility: string = 'hidden'

constructor(private notificationService: NotificationService) { }

ngOnInit() {
this.notificationService.notifier
.do(message=>{
this.message = message
this.snackVisibility = 'visible'
}).switchMap(message => Observable.timer(3000))
.subscribe(timer=> this.snackVisibility = 'hidden')
}

}
`

`import { NgModule } from '@angular/core';

//IMPORT DOS COMPONENTES DO MATERIAL
import { SharedModule } from '@app/shared';

import { SnackbarComponent } from './snackbar.component';

@NgModule({
imports: [SharedModule],
declarations: [SnackbarComponent]
})
export class SnackbarModule {}
`

`import {EventEmitter} from '@angular/core'

export class NotificationService {
notifier = new EventEmitter()

notify(message: string){
this.notifier.emit(message)
}

}
`

It also seems that the default value of aria-live="polite" is not set in the main example and shows assertive but documentation doesn't show any use of the config to make it assertive.
image

import {Component} from '@angular/core';
import {MatSnackBar} from '@angular/material';

/**
 * @title Basic snack-bar
 */
@Component({
  selector: 'snack-bar-overview-example',
  templateUrl: 'snack-bar-overview-example.html',
  styleUrls: ['snack-bar-overview-example.css'],
})
export class SnackBarOverviewExample {
  constructor(public snackBar: MatSnackBar) {}

  openSnackBar(message: string, action: string) {
    this.snackBar.open(message, action, {
      duration: 2000,
    });
  }
}

AFAICT this issue is obsolete; the docs for snackbar are up to date and the code examples all work.

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings