Reputation: 85
I am new to Angular, and have a question regarding services. In the past in other languages, I would create components that were self contained that could be called from anywhere in the application.
I have a need for popup dialog and error messages shown modally that can be called from either a different service or from the ts file for a component.
My ultimate goal is to not have the HTML for the dialog in multiple components, but rather in a single service or component & service.
My initial thoughts are something along the lines of a service with a template and style section (if these are available in a service) that is fully self contained or if this is not doable, then a service with the methods for the dialog and a separate component containing the markup and styles.
What I am thinking is one of 2 ideas: 1. A service that has the necessary html, styles and methods to display the dialog or error message 2. A service and component that works together to show the dialog
Am I going down the correct road with this train of thought or am I thinking about doing something that will bite me?
Upvotes: 4
Views: 7750
Reputation: 24194
Using a Service to encapsulate Angular dialog logic is a good approach. Leveraging Angular Material Dialog, you could create a service as follows.
import { ElementRef, Injectable } from '@angular/core'
import { MatDialog, MatDialogRef } from '@angular/material'
import { DialogProfileOptionsComponent } from './dialog-profile-options/dialog-profile-options.component'
import { DialogYesNoComponent } from './dialog-yes-no/dialog-yes-no.component'
@Injectable({
providedIn: 'root'
})
export class DialogService {
constructor(public dialog: MatDialog) { }
public open_info_dialog() { }
public open_profile_options_dialog(
{
position_relative_to_element,
user,
has_backdrop = false,
height = '135px',
width = '290px'
}: {
position_relative_to_element: ElementRef,
user: firebase.User,
has_backdrop?: boolean,
height?: string,
width?: string
}
): MatDialogRef<DialogProfileOptionsComponent> {
const dialog_ref: MatDialogRef<DialogProfileOptionsComponent> =
this.dialog.open(DialogProfileOptionsComponent, {
hasBackdrop: has_backdrop,
height: height,
width: width,
data: { position_relative_to_element: position_relative_to_element, user: user }
});
return dialog_ref;
}
public open_yes_no_dialog(
{
question,
title = 'Confirm',
yes_button_first = true,
has_backdrop = false,
height = '250px',
width = '350px'
}: {
question: string,
title?: string,
yes_button_first?: boolean,
has_backdrop?: boolean,
height?: string, width?: string
}
): MatDialogRef<DialogYesNoComponent> {
const dialog_ref = this.dialog.open(DialogYesNoComponent, {
autoFocus: true,
backdropClass: 'cdk-overlay-transparent-backdrop',
closeOnNavigation: true,
disableClose: false,
hasBackdrop: has_backdrop,
height: height,
width: width,
data: { question: question, title: title, yes_button_first: yes_button_first }
});
return dialog_ref;
}
open_warning_dialog() { /* TODO */ }
}
import { Component, ElementRef, Inject, OnInit } from '@angular/core'
import { MatDialogConfig, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'
@Component({
selector: 'dialog-profile-options',
templateUrl: './dialog-profile-options.component.html',
styleUrls: ['./dialog-profile-options.component.css']
})
export class DialogProfileOptionsComponent implements OnInit {
private position_relative_to_element: ElementRef
constructor(
public dialog_ref: MatDialogRef<DialogProfileOptionsComponent>,
@Inject(MAT_DIALOG_DATA) public options: {
position_relative_to_element: ElementRef,
user: firebase.User
}
) {
this.position_relative_to_element = options.position_relative_to_element
}
ngOnInit() {
const mat_dialog_config = new MatDialogConfig()
const rect: DOMRect = this.position_relative_to_element.nativeElement.getBoundingClientRect()
mat_dialog_config.position = { right: `10px`, top: `${rect.bottom + 2}px` }
this.dialog_ref.updatePosition(mat_dialog_config.position)
}
}
<div mat-dialog-content>
<div><b>{{options.user.displayName}}</b></div>
<div class="text-secondary">{{options.user.email}}</div>
</div>
<div mat-dialog-actions>
<button mat-button mat-dialog-close="view-profile" cdkFocusInitial>View profile</button>
<button mat-button mat-dialog-close="sign-out">Sign out</button>
</div>
Upvotes: 3