Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular (v5+) - Snackbar "openFromComponent", component communication

Angular (v5.2.10) Snackbar

--| Intro |--
I have one Angular component (let's call it "Parent") initializing an Angular material Snackbar called snackBar. Passed in is SnackbarMessage , another component with a template containing the snackbar markup. Using snackBar.openFromComponent(SnackBarMessage) is necessary in this instance because I need to use more than just plain text in the snackbar [like markup, click events, etc] where snackBar.open(message, action) is not enough.

--| Code |--

"Parent" component:

@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:

@Component({
  selector: 'app-snackbar-message',
  templateUrl: './snackbar-message.html'
})
export class SnackbarMessage { }

"snackbar-message.html" markup:

<p>(Snackbar message)</p>
<button type="button" (click)="dismissSnackbar();">Dismiss</button>


--| Issue |--
Within the imported SnackbarMessage template (snackbar-message.html) I need to call the Parent component's dismissSnackbar();, how do we do this with the current encapsulation of this Angular app?

like image 939
Cody Tolene Avatar asked Nov 27 '22 20:11

Cody Tolene


2 Answers

You don't actually need to call the parent component's "dismissSnackbar()" method to dismiss the snackbar. You can simply inject the "MatSnackBar" into the "SnackbarMessage" component and call "dismiss()" method on that injected instance of "MatSnackBar". As written in the docs, this will hide the currently visible Snackbar i.e. the Snackbar opened using "SnackbarMessage" component in your example. Below is your updated "SnackbarMessage" component:-

"SnackbarMessage" component:

@Component({
    selector: 'app-snackbar-message',
    templateUrl: './snackbar-message.html'
})
export class SnackbarMessage { 
    constructor(public snackBar: MatSnackBar) {}

    public dismissSnackbar(): void {
        this.snackBar.dismiss();
    }
}
like image 177
Yatharth Varshney Avatar answered Nov 30 '22 09:11

Yatharth Varshney


I solved today a problem similar to yours using MatSnackBar.openFromTemplate instead of MatSnackBar.openFromComponent. With this approach, all features from the child component becomes directly accessible from the parent component.

The 'Parent Component' acts as a 'Mediator' class between MatSnackBar and the SnackBarMessageComponent. Now, the SnackBarMessageComponent is decoupled of a MatSnackBar and becomes a plain component and could be renamed to MessageComponent. You can send and receive data between parent and child component using plain @Input and @Output. You can add as many @Inputs or @Outputs as you want.

The code says more than 1.000 words:

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>

(The above code has not been tested)

like image 28
Sergio Marcelo C Figueiredo Avatar answered Nov 30 '22 10:11

Sergio Marcelo C Figueiredo