반응형

간단하게 ngIf를 이용하여 alert를 이용할 수 있습니다.

 

하지만 3nd-party 라이브러리를 만드는 경우, 그리고 in-code라이브러리를 사용하는 경우에 필요한 기법입니다.

순수하게 프로그래밍으로만 컴포넌트를 만드는 것이죠.

 

방법은 다음과 같습니다.

1. 생성할 Component의 Factory만들기.

2. view container 레퍼런스 (placeholder Directive를 사용하는 거죠.)

3. Angular의 도움을 받아 생성한 Component를 랜더링 합니다.

4. app.module.ts에 entryComponents를 추가합니다.

 

1. Factory생성 및 unsubscribe();

// auth.component.ts
private showErrorAlert(message: string) {
    // const alertCmp = new AlertComponent();
    const alertCmpFactory = this.componentFactoryResolver.resolveComponentFactory(
      AlertComponent
    );
    const hostViewContainerRef = this.alertHost.viewContainerRef;
    hostViewContainerRef.clear();

    const componentRef = hostViewContainerRef.createComponent(alertCmpFactory);

    componentRef.instance.message = message; // alert.component.ts의 @Input() message: string;
    this.closeSub = componentRef.instance.close.subscribe(() => {
      this.closeSub.unsubscribe();
      hostViewContainerRef.clear();
    });
  }

 

2. view container 사용법 <ng-template>를 이용합니다.

<!-- auth.component.html -->
<ng-template appPlaceholder></ng-template>
<div class="row">
  <div class="col-xs-12 col-md-6 col-md-offset-3">
    <!-- <div class="alert alert-danger" *ngIf="error">
      <p>{{ error }}</p>
    </div> -->
    <!-- <app-alert
      [message]="error"
      *ngIf="error"
      (close)="onHandleError()"
    ></app-alert> -->
    <div *ngIf="isLoading" style="text-align: center;">
      <app-loading-spinner></app-loading-spinner>
    </div>
// placeholder.directive.ts
import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appPlaceholder]'
})
export class PlaceholderDirective {
  constructor(public viewContainerRef: ViewContainerRef) {}
}

3. 랜더링할 컴포넌트 입니다.

// alert.component.ts

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-alert',
  template: `
  <div class="backdrop" (click)="onClose()"></div>
  <div class="alert-box">
    <p>{{ message }}</p>
    <div class="alert-box-actions">
      <button class="btn btn-primary" (click)="onClose()">Close</button>
    </div>
  </div>`,
  styles: [`
  .backdrop {position: fixed;top: 0;left: 0;width: 100vw;height: 100vh;background: rgba(0, 0, 0, 0.75);z-index: 50;}
  .alert-box {position: fixed;top: 30vh;left: 20vw;width: 60vw;padding: 16px;z-index: 100;background: white;box-shadow: 0 2px 8px rbga(0, 0, 0, 0.26);}
  .alert-box-actions {text-align: right;}
  `]
})
export class AlertComponent {
  @Input() message: string;
  @Output() close = new EventEmitter<void>();

  onClose() {
    this.close.emit();
  }
}

4. entryComponents를 선언합니다.

//app.module.ts
...
bootstrap: [AppComponent],
  entryComponents: [
    AlertComponent
  ]
})
export class AppModule {}

 

*ngIf를 이용하는것이 쉬운 방법이며, Angular의 강력한 도구이기도 합니다.

ngIf가 false인 경우, DOM을 랜더링하지 않습니다.

필요한 경우에만 다이나믹 컴포넌트를 사용하는것이 좋겠죠?

반응형

+ Recent posts