Angular2 Service可以创建,显示和管理其内部组件?如何实现js alert()? [英] Angular2 Service which create, show and manage it's inner Component? How to implement js alert()?
问题描述
我试图找到一种在服务中拥有和管理angular2组件的方法,但没有成功:
I tried to find a way for having and manage an angular2 Component in a Service but with no success:
-
我需要创建:
I need to create:
AlertService{
alertConfirm(msg): Promise;
}
alertConfirm将显示一个带有2个按钮(确定,取消)的确认"窗口,并返回用户的选择作为承诺.
alertConfirm will prompt an Confirmation window with 2 buttons (Ok, Cancel) and will return users' choise as a Promise.
- 通常,此想法是实现著名的JavaScript alert()方法 但具有设计好的UI窗口和取消按钮.
- In General, the idea is to implement the famous JavaScript alert() method but with a designed UI window and with also a cancel button.
该方法将返回Promise并带有用户选择的响应:确定"或取消".
The method will return a Promise with a response of user's choice: "OK" or "Cancel".
-
我试图找到一种在AlertService中保存匿名"组件AlertComponent的方法:
I tried to find a way for holding an "anonymous" component, AlertComponent, in AlertService:
AlertComponent{
showMsgConfirm(msg): Promise;
}
当用户关闭提示窗口或单击确定"或取消"时,Promise将设置为带有响应.
The Promise will be set with a response when user close prompt window or click "OK" or "Cancel".
- 问题:
如何使"AlertService"具有内部的"AlertComponent",可以通过其"alertOK"方法进行管理?
How to make "AlertService" to have an inner "AlertComponent" which can be managed by it's "alertOK" method?
我的意思是,我没有找到让"alertConfirm"调用"showMsgConfirm"方法并返回其Promise作为响应的方法.
I mean, I didn't find a way for "alertConfirm" to call "showMsgConfirm" method and to return it's Promise as a response.
例如,从主要应用组件调用:
for example, calling from main app component:
this.alertService.alertConfirm("Save changes?").then(res => {
if(res.ok){console.log("Can be saved");
}, err=> { });
对此有什么想法吗?
谢谢
更新:2种不同的解决方案,但没有成功管理AlertComponent的方法:
Update:2 different ideas for solution, but with no sucess to manage the AlertComponent:
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;
}
}
推荐答案
答案是...:
-
服务:
- _counter 用于每个模态具有唯一的名称.
- comp.instance.close 是用于订阅EventEmitter的内部组件的属性.
- _counter is used for each modal to have a unique name.
- comp.instance.close is a property of inner component for subscribing for 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;
}
}
- 内部组件:
- 使用 Bootstrap 处理UI中 Modal 的显示:modal('show')\ modal('hide').
- Using Bootstrap for handling display of Modal in UI: 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();
}
}
-
应用声明:
- 不幸的是,我们必须在main-app模块中声明匿名组件.
- 我们必须添加
entryComponents
的声明:[CtmAlertComponent],
- unfortunately, we must declare the anonymus component in our main-app module.
- We must add a declaration of
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();
-
模式用户界面:
- 此html模板基于引导程序的UI:
.
<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>
.
-
用法::
- 例如:
.
this.alertCtmService.alertOK("Save changes???").subscribe(function (resp) {
console.log("alertCtmService.alertOK.subscribe: resp=" + resp.ok);
this.saveData();
}.bind(this) );
**
- 我构建的示例: https://plnkr.co/qc1ZM6
**
来源:
-
这篇关于Angular2 Service可以创建,显示和管理其内部组件?如何实现js alert()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!