Оповещения об уровне приложения 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, который вы связали, конкретно объясняется, что их сценарий использования - создание нового компонента динамически, когда они даже не знают фактический класс компонента. Я надеюсь, что мой пример выше поможет вам понять, как организовать эти оповещения в вашем проекте.