Angular2服务,它创建,显示和管理它的内部组件?如何实现js alert()?

时间:2017-08-02 09:40:50

标签: angular2-template angular2-services

我试图找到一种在服务中拥有和管理angular2组件的方法,但没有成功:

  1. 我需要创建:

    AlertService{
    
        alertConfirm(msg): Promise;
    }
    
  2. alertConfirm将提示一个带有2个按钮的确认窗口(确定,取消)并返回用户'选择作为承诺。

    1. 一般来说,我们的想法是实现着名的JavaScript alert()方法 但是有一个设计的UI窗口和一个取消按钮。
    2. 该方法将返回一个Promise,其中包含用户选择的响应:" OK"或"取消"。

      1. 我试图找到一种方法来举办一个匿名的"组件,AlertComponent,在AlertService中:

        AlertComponent{
        
            showMsgConfirm(msg): Promise;
        }
        
      2. 当用户关闭提示窗口或点击"确定&#34>时,Promise将设置响应。或"取消"。

        1. 问题:
        2. 如何制作" AlertService"有一个内部" AlertComponent"这可以由它管理" alertOK"方法

          我的意思是,我没有为" alertConfirm"找到方法。打电话给#34; showMsgConfirm"方法并将其作为回应返回。

          例如,从主应用程序组件调用:

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

          对此有何想法?

          谢谢,

          更新:2个不同的解决方案,但没有成功管理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;
              }
          
          
          }
          

1 个答案:

答案 0 :(得分:0)

答案是......:

  • 服务

    1. _counter 用于每个模式以具有唯一名称。
    2. comp.instance.close 是订阅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;
    }

}
  • 内部组件:
    1. 使用 Bootstrap 处理UI中模态的显示:模式(&#39;显示&#39;)\ modal(&#39;隐藏&#39;)

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();
    }


}
  • 应用宣言

    1. 不幸的是,我们必须在main-app模块中声明anonymus组件。
    2. 我们必须添加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();
  • 模态用户界面

    1. 此html模板基于bootstrap的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>

  • <强>用法:

    1. 例如:

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

**

**

来源:

  1. building-angular-2-components-on-the-fly-a-dialog-box-example

  2. angular2-ngmodule