3

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.

Robba
  • 7,684
  • 12
  • 48
  • 76
  • [ng2-bootstrap modal](https://github.com/valor-software/ng2-bootstrap/blob/development/components/modal/modal.component.ts) Maybe take a look at this modal implementation will help you. – merlin Sep 22 '16 at 09:05
  • Unfortunately their solution is to create a directive and thus requires you to add the html for the modal to the component that uses it which would mean alot of duplication in the case of a standard dialog like a confirmation dialog. – Robba Sep 22 '16 at 09:09
  • [ionic 2 alert](http://ionicframework.com/docs/v2/components/#alert-prompt) How about this? It's implementation kind of meets your needs. – merlin Sep 22 '16 at 09:22
  • I took a look, but ionic is a huge framework. I've tried to figure out what's what, but for a relatively new Angular 2 developer it's pretty hard to figure out what's going on... Thanks anyway though – Robba Sep 22 '16 at 10:15
  • Really good question. I've been wondering the same thing!! And I've been working in Angular 2 since the early alphas... – Vern Jensen May 19 '17 at 20:20

4 Answers4

4

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
        });
    };
}
Stuart
  • 1,572
  • 4
  • 21
  • 39
3

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]
})
Vern Jensen
  • 3,449
  • 6
  • 42
  • 59
0

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

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
0
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>
  • Actually, I had used a reactive form of Angular to display the dialog. (Component. ts) this is nothing but it is your view of where DialogsFormService is going to call. – Machhindra Neupane Apr 22 '18 at 11:48