Angular2 Service that creates, displays and manages its internal Component? How to implement js alert ()?

I tried to find a way to use and manage the angular2 component in the service, but without success:

  • I need to create:

    AlertService{ alertConfirm(msg): Promise; } 

alertConfirm will offer a confirmation window with 2 buttons ("OK", "Cancel") and return the selection as a promise to users.

  1. In general, the idea is to implement the well-known JavaScript alert () method but with a developed user interface and cancel button.

The method returns Promise with a response to the user's choice: "OK" or "Cancel".

  1. I tried to find a way to host the anonymous AlertComponent component in AlertService:

     AlertComponent{ showMsgConfirm(msg): Promise; } 

The promise will be set with a response when the user closes the request window or click OK or Cancel.

  1. Question:

How to make "AlertService" have an internal "AlertComponent" that this alertOK method can control?

I mean, I did not find a way to "alertConfirm" call the showMsgConfirm method and return it as an answer.

for example, a call from the main component of the application:

 this.alertService.alertConfirm("Save changes?").then(res => { if(res.ok){console.log("Can be saved"); }, err=> { }); 

Any ideas for this?

Thanks,

Update: 2 different solutions for the solution, but without AlertComponent support:

 import { Injectable, ViewContainerRef, ReflectiveInjector, ComponentFactoryResolver, ComponentRef } from '@angular/core'; import { AlertComponent } from './../components/modales/AlertComponent/AlertComponent.component'; @Injectable() export class AlertService { constructor(private componentFactoryResolver: ComponentFactoryResolver) { } public createAlertComp(vCref: ViewContainerRef): ComponentRef<any> { let factory = this.componentFactoryResolver.resolveComponentFactory(AlertComponent); /* //Option 1: // vCref is needed cause of that injector.. let injector = ReflectiveInjector.fromResolvedProviders([], vCref.parentInjector); // create component without adding it directly to the DOM let comp = factory.create(injector); // add inputs first !! otherwise component/template crashes .. comp.instance.model = modelInput; // all inputs set? add it to the DOM .. vCref.insert(comp.hostView); return comp; */ //Option 2: var componentRef: ComponentRef<AlertComponent> = vCref.createComponent(factory); return null; } } 
+2
source share
1 answer

And the answer ...:

  • Service :

    • _counter is used for each modal name with a unique name.
    • comp.instance.close is a property of the internal component to subscribe to EventEmitter.

.

 import { Injectable, ViewContainerRef, ReflectiveInjector, ComponentFactoryResolver, ComponentRef, EventEmitter } from '@angular/core'; import { CtmAlertComponent } from './ctmAlert/ctmAlert.component'; @Injectable() export class AlertCtmService { private _vcr: ViewContainerRef; private _counter: number = 0; constructor(private componentFactoryResolver: ComponentFactoryResolver, public viewRef: ViewContainerRef) { console.log("AlertCtmService.constructor:"); //TODO: Consider appending to this.viewRef: "#alertCtmServiceContainer" as a Dom elemnt perent container which will hold all AlertModals: // Maybe by: // this.viewRef.element.nativeElement.insertAdjacentHTML('beforeend', '<div class="alertCtmServiceContainer"></div>'); this._vcr = this.viewRef; } public alertOK(alertMsg: string): EventEmitter<any> { return this.createEventEmitterComponent("CtmAlertComponent", alertMsg, false); } public alertConfirm(alertMsg: string): EventEmitter<any> { return this.createEventEmitterComponent("CtmAlertComponent", alertMsg, true); } private createEventEmitterComponent(componentName: string, alertMsg: string, isConfirm: boolean): EventEmitter<any> { console.log("AlertCtmService.createEventEmitterComponent:"); switch (componentName) { case "CtmAlertComponent": default: var _component = CtmAlertComponent; break; } let factory = this.componentFactoryResolver.resolveComponentFactory(_component); // vCref is needed cause of that injector.. let injector = ReflectiveInjector.fromResolvedProviders([], this._vcr.parentInjector); // create component without adding it directly to the DOM let comp = factory.create(injector); // add inputs first !! otherwise component/template crashes .. comp.instance.close.subscribe(resp => { console.log("AlertCtmService.createEventEmitterComponent: comp.instance.close.subscribe: resp=" + resp.ok); comp.destroy(); }) comp.instance.alertBodyMsg = alertMsg; comp.instance.isConfirm = isConfirm; comp.instance.nameId = "Modal" +(++this._counter).toString(); // all inputs set? add it to the DOM .. this._vcr.insert(comp.hostView); //return null; return comp.instance.close; } public init(vCref: ViewContainerRef): ViewContainerRef { this._vcr = vCref; return this._vcr; } } 
  • Internal component:
    • Using Bootstrap to Handle a Modal Display in an Interface: Modal ('show') \ modal ('hide').

.

 import { Component, AfterViewInit, Input, ViewChild, ElementRef, Renderer, NgZone, EventEmitter} from '@angular/core'; @Component({ selector: 'ctm-alert', styles: [``], templateUrl: '/app/shared/alertCtm/ctmAlert/CtmAlert.component.html', styleUrls: ['./app/shared/alertCtm/ctmAlert/CtmAlert.component.css'], providers: [] }) export class CtmAlertComponent implements AfterViewInit { public ModalIsVisible: boolean; //private static subscriptions: Object = {}; //enums = Enums; close = new EventEmitter(); public nameId = ""; private isOk = false; alertBodyMsg: string = ""; isConfirm = false; constructor() { console.log("CtmAlertComponent.constructor:"); } ngAfterViewInit() { this.showModal(); var attrId = this.getIdAttr(); $('#' + attrId).on('hidden.bs.modal', function () { debugger; console.log('CtmAlertComponent: #licenseModal_XXX.on(hidden.bs.modal)'); this.submitStatus(); }.bind(this) ); } showModal() { this.ModalIsVisible = true; var attrId = '#' +this.getIdAttr(); $(attrId).modal('show'); } hideModal() { this.ModalIsVisible = false; var attrId = '#' + this.getIdAttr(); $(attrId).modal('hide'); } getIdAttr(): string { return "ctmAlertModal_" + this.nameId; } submitStatus() { var resp = { ok: (this.isOk == true) }; this.close.emit(resp); } submitOk() { this.isOk = true; this.hideModal(); } submitCancel() { this.isOk = false; this.hideModal(); } } 
  • Application Declaration :

    • Unfortunately, we have to declare an anonymous component in our main application.
    • We must add an entryComponents : [CtmAlertComponent],

.

 import { CtmAlertComponent } from './shared/alertCtm/ctmAlert/ctmAlert.component'; @NgModule({ imports: [ BrowserModule, HttpModule, AppRoutingModule, ... ], declarations: [ CtmAlertComponent, AppComponent, ... ], entryComponents: [CtmAlertComponent], providers: [ ... ], bootstrap: [AppComponent], }) export class AppModule { } enableProdMode(); 
  • Modal interface :

    • This html template is based on the bootstrap user interface:

.

 <div class="ctmAlertModal modal fade in" [id]="getIdAttr()" role="dialog"> <div class="modal-dialog modal-lg" [ngClass]="{'modal-lg-6': true }"> <!-- Modal content--> <div class="modal-content"> <div class="modal-header" style=""> <div class="pull-right" style="position: relative;"> <a href="#" data-dismiss="modal" (click)="hideModal()"><span class="fa fa-times-circle" aria-hidden="true" style="color: #949494"></span></a> </div> </div> <div class="modal-body"> <div class="modal-body-msg"> {{alertBodyMsg}} </div> <div class="modal-body-buttons"> <div style="margin: 0 auto;" [style.width]="(isConfirm)? '165px' : '70px' "> <button type="button" *ngIf="isConfirm" class="btn-submit pull-left btn-cancel" [ngClass]="{'disabled': false }" [disabled]="false" (click)="submitCancel()"> <!--<img alt="End-Training" class="centering-me2" src="../../../contents/training_state_stop_white.svg">--> Cancel </button> <button type="button" class="btn-submit pull-right" [ngClass]="{'disabled': false }" [disabled]="false" (click)="submitOk()"> <!--<img alt="Resume-Training" src="../../../contents/training_state_play_white.svg">--> OK </button> </div> </div> </div> </div> </div> </div> 

.

  • Application:

    • eg:

.

  this.alertCtmService.alertOK("Save changes???").subscribe(function (resp) { console.log("alertCtmService.alertOK.subscribe: resp=" + resp.ok); this.saveData(); }.bind(this) ); 

**

**

Sources:

0
source

All Articles