Оповещения об уровне приложения Dynamic Clarity

Я использую vmware/clarity Система разработки, и я пытаюсь реализовать динамические оповещения на уровне приложений, используя динамическую загрузку компонентов, описанную в angular.io. Я следовал этому шаблону раньше, но, похоже, я не могу заставить его работать с предупреждениями, исходящими от Clarity.

app.component.ts

import { AfterViewInit, Component, ComponentFactoryResolver, OnDestroy, ViewChild } from '@angular/core';
import { ClrAlert } from '@clr/angular';

import { AlertsHostDirective } from './directives/alerts-host.directive';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit, OnDestroy {

  @ViewChild(AlertsHostDirective) alerts: AlertsHostDirective;
  private interval: NodeJS.Timer;

  constructor(private _componentFactoryResolver: ComponentFactoryResolver) { }

  ngAfterViewInit(): void {
    this.alert();
    this.getAlerts();
  }

  ngOnDestroy(): void {
    clearInterval(this.interval);
  }

  private alert() {
    const componentFactory = this._componentFactoryResolver.resolveComponentFactory(ClrAlert);

    const viewContainerRef = this.alerts.viewContainerRef;
    const componentRef = viewContainerRef.createComponent(componentFactory);

    componentRef.instance.isAppLevel = true;
    componentRef.changeDetectorRef.detectChanges();
  }

  private getAlerts() {
    this.interval = setInterval(() => {
      this.alert();
    }, 5000);
  }

}

app.component.html

<clr-main-container>
    <clr-alerts>
        <ng-template appAlertsHost></ng-template>
        <clr-alert clrAlertType="info"
                   [clrAlertAppLevel]="true">
            <div class="alert-item">
                <span class="alert-text">This is the first app level alert.    </span>
                <div class="alert-actions">
                    <button class="btn alert-action">Fix</button>
                </div>
            </div>
        </clr-alert>
        <clr-alert clrAlertType="danger"
                   [clrAlertAppLevel]="true">
            <div class="alert-item">
                <span class="alert-text">This is a second app level alert.</span>
                <div class="alert-actions">
                    <button class="btn alert-action">Fix</button>
                </div>
            </div>
        </clr-alert>
    </clr-alerts>
...

оповещает-host.directive.ts

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appAlertsHost]'
})
export class AlertsHostDirective {

  constructor(public viewContainerRef: ViewContainerRef) { }

}

Если я положу директиву на ClrAlerts компонент, он работает так, как должно быть в том, что оповещения уровня приложения добавляются после ClrAlerts в ДОМ. Но я хочу, чтобы все мои оповещения уровня приложения появлялись внутри этого компонента по мере их поступления. В свою очередь, я бы хотел, чтобы компонент пейджера также обновлялся.

Это возможно?

2 ответа

Решение

@Eudes указал, что я делал вещи слишком сложными. По сути, мне просто нужно следить за массивом уведомлений, чтобы, когда происходит что-то "тревожное", я мог просто вставить объект оповещения в массив и проследить за ним *ngFor,

Тем не менее, кажется, что проблема с ClrAlerts родительский компонент обрабатывает эти изменения правильно в определенных ситуациях. Например, если вы начинаете с предупреждений в массиве, закрываете их при взаимодействии с пользователем, а затем добавляете больше, текущее предупреждение настроено неправильно. Поэтому, это, кажется, самое чистое решение, которое я мог придумать:

шаблон

<clr-main-container>
    <clr-alerts>
        <clr-alert *ngFor="let alert of alerts"
                   [clrAlertType]="alert.type"
                   [clrAlertAppLevel]="true">
            <div class="alert-item">
                <span class="alert-text">{{alert.text}}</span>
                <div class="alert-actions"
                     *ngIf="alert.action">
                    <button class="btn alert-action">{{alert.action}}</button>
                </div>
            </div>
        </clr-alert>
    </clr-alerts>
    ...

Составная часть

import 'rxjs/add/Observable/of';

import { AfterViewInit, Component, OnDestroy, ViewChild } from '@angular/core';
import { ClrAlerts } from '@clr/angular';

export interface AppLevelAlert {
  type: 'info' | 'warning' | 'success' | 'danger';
  text: string;
  action: string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit, OnDestroy {

  @ViewChild(ClrAlerts) alertsContainer: ClrAlerts;
  private interval: NodeJS.Timer;
  alerts: AppLevelAlert[] = [];

  ngAfterViewInit(): void {
    this.alert();
    this.getAlerts();
  }

  ngOnDestroy(): void {
    clearInterval(this.interval);
  }

  private alert() {
    this.alerts.push({
      type: 'success',
      text: 'This was added later!',
      action: 'Do nothing'
    });
    if (!this.alertsContainer.currentAlert) {
      this.alertsContainer.multiAlertService.current = 0;
    }
  }

  private getAlerts() {
    this.interval = setInterval(() => {
      this.alert();
    }, 5000);
  }

}

После обсуждения в комментариях я подумал, что было бы проще, если бы я просто опубликовал то, что имел в виду, просто используя *ngFor: https://stackblitz.com/edit/clarity-light-theme-v11-vs8aig?file=app%2Fnotifications.provider.ts

Использование фабрики компонентов для создания всегда одного и того же компонента полностью излишне и является ужасной практикой. В разделе Angular docs, который вы связали, конкретно объясняется, что их сценарий использования - создание нового компонента динамически, когда они даже не знают фактический класс компонента. Я надеюсь, что мой пример выше поможет вам понять, как организовать эти оповещения в вашем проекте.

Другие вопросы по тегам