How to create a Dialog service in Angular2

2020-07-17 05:04发布

问题:

In Angular 2 it seems any and all DOM manipulations are performed by components or directives. I'm used to Angular 1 however in which it was reasonably common to have certain services that created and managed their own DOM elements; most notably dialogs.

In the past it was possible to for instance create an Angular 1 service ConfirmationService with a function Confirm() that returned a Promise<bool> that showed the user a dialog to press either yes or no on, which resolved the promise.

These dialog services (for instance UI Bootstrap Modal or the NgDialog) generally work by injecting the $document, $compile and $parse services and create and inject DOM elements on the fly.

I'm having difficulties finding out what the recommended Angular 2 approach is to creating such a service. If at all possible I'd like to prevent having to create a ConfirmationComponent that has to be added to any component that needs to ask for confirmation (partly because it can also be another service that needs the confirmation and that confirmation is but one example where this is useful)

Anyway, some help/pointers would be greatly appreciated. Thanks in advance.

回答1:

If you're ok taking a dependency on sweetalert2, a dialog service becomes pretty simple:

import { Injectable } from '@angular/core';
import { default as swal } from 'sweetalert2';

@Injectable()
export class DialogService {
    confirm(title: string, message: string) {
        return swal({
            title: title,
            text: message,
            type: 'warning',
            showCancelButton: true
        });
    };
}


回答2:

I just ran across this link. While I haven't tried it yet, it looks like the solution is to create a Component as usual, and a service that uses that component like so:

@Injectable()
export class DialogService {  
  constructor(private modalService: NgbModal) {}

  public confirm() {
    const modalRef = this.modalService.open(DialogComponent);
    modalRef.componentInstance.name = "Discard Changes?";
    modalRef.componentInstance.message = "Are you sure you want to discard your changes?";
    modalRef.componentInstance.changeRef.markForCheck();
    return modalRef.result;
  }
}

The trick is to make sure to reference the DialogComponent from your main @NgModule:

@NgModule({
  imports: [...], 
  declarations: [ DialogComponent ],
  bootstrap:    [ AppComponent ],
  providers: [ DialogService],
  entryComponents: [DialogComponent]
})


回答3:

Angular Material has a dialog box that works in an 'angular' type of way and supports multiple open dialogs (not really sure why but it does).

https://material.angular.io/components/dialog/overview



回答4:

import { Observable } from 'rxjs/Rx';
import { DialogsFormComponent } from  './dialogs-form.component';
import { MatDialogRef, MatDialog, MatDialogConfig } from '@angular/material';
import { Injectable } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';

@Injectable() 
exprt class DialogsFormService {
constructor(private dialog: MatDialog, private fb: FormBuilder) { }
public config(title: string, fields: any, formGroup: any): Observable<boolean> {
let dialogRef: MatDialogRef<DialogsFormComponent>;
dialogRef = this.dialog.open(DialogsFormComponent, { width: '600px
'});
if (formGroup instanceof FormGroup) {
dialogRef.componentInstance.modalForm = formGroup;
} else {
dialogRef.componentInstance.modalForm = this.fb.group(formGroup);
}
dialogRef.componentInstance.title = title;
dialogRef.componentInstance.fields = fields;
return dialogRef.afterClosed();
}
}

component.ts

import { Validators } from '@angular/forms';

export class YourComponent {
constructor (private dialogsFormService: DialogFormService) {}
openDialog() {
const title =  'Your Title';
const type = 'your type you can control on dialog html';
const fields = dialogFieldOptions;
const formGroup = {
prority:['', Validators.required ],
type: ['', Validators.required ],
message: ['', Validators.required]
};
this.dialogsFormService.confirm(title, fields, formGroup)
.subscribe((res) => {
if (response != undefined) {
// do some things
}
});
}
}
const dialogFieldOptions = [
{
'label': 'you lable',
'type': 'radio',
'name': 'your name',
'option': ['option1', 'option2'],
'required': true;
}
];

dialog-form.component.ts

import { component, Inject } from '@angular/core';
import { MatDialogRef } from '@angular/material';
import { FormGroup } from '@angular/forms';
@Component({ templateUrl:'./dialogs-form.component.html'})
export class DialogsFormComponent {
public title: string;
public fields: any;
public modalForm: any;
private markFormAsTouched (formGroup: FormGroup) {
(<any>Object).values(formGroup.constrols).forEach(control => {
control.markAsTouched();
if (control.controls) {
this.markFormAsTouched(control);
}
});
}
constructor(public dialogRef: MatDialogRef<DialogsFormComponent>) { }
onSubmit(mForm, dialog) {
if (mForm.valid) {
dialog.close(mForm.value);
} else {
this.markFormAsTouched(mForm);
}
}
}

dialog-form.component.html

<form (ngSubmit) = "onSubmit(modelForm, dialogRef)" [formGroup]= "modalForm">
<mat-dialog-content>
<selection *ngIf = "field.type ==== 'radio'">
<label> field.label</label>
<mat-radio-group formControlName="field.name" required = "field.required">
<mat-radio-button *ngFor="let option of field.options" [value]= "option">
{{option}}</mat-radio-button>
</mat-radio-group>
</selection>
</mat-dialog-content>
<mat-dialog-actions>
<button type="button" mat-raised-button (click)="dialogRef.close()"> Cancle</button>
<button type="submit" mat-raised-button> Submit</button>
</mat-dialog-actions>
</form>