【问题标题】:Dynamic Clarity App Level Alerts动态清晰度应用程序级别警报
【发布时间】:2018-02-08 19:36:46
【问题描述】:

我正在使用vmware/clarity design system,我正在尝试使用动态组件加载outlined in 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>
...

alerts-host.directive.ts

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

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

  constructor(public viewContainerRef: ViewContainerRef) { }

}

如果我将指令放在 ClrAlerts 组件上,它的工作方式应该是在 DOM 中的 ClrAlerts 之后附加应用程序级别的警报。但我希望我的所有应用程序级警报在它们进入时出现在该组件中。反过来,我希望寻呼机组件似乎也已更新。

这可能吗?

【问题讨论】:

  • 这个回答可以帮到你stackoverflow.com/questions/40922224/…
  • 您实际上总是在创建ClrAlert 组件,这是如何动态的?在您的示例中,您可以只使用一个简单的 *ngFor 就可以了。
  • @Eudes ,也许有比动态更好的词,但我借用了动态组件加载器的 angular.io 文档中的措辞。正如您所说,使用它们概述的模式,您正在加载相同的组件,强类型。我认为动态的意思是“在运行时”。换句话说,当客户端已经加载了应用程序时,可以基于用户交互或其他事件创建组件。 *ngFor 要求我在启动应用程序之前了解所有通知,这错过了我想要做的事情。
  • *ngFor 是动态的,你不需要在运行时知道所有的通知。如果您的应用程序中有一个全局提供程序来跟踪应显示的所有通知,并且用户交互和事件会更新该列表,那么 *ngFor 将非常适合您的用例。
  • 确实如此。让我试一试...

标签: angular dynamic angular2-changedetection vmware-clarity clarity


【解决方案1】:

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

}

【讨论】:

  • 我也尝试过使用动态组件,但这是关于复杂性和清晰度的最佳解决方案。我会将所有警报推送到服务,而 clr-alerts 只需订阅可观察到的警报。
  • 太棒了。 TY 分享。
【解决方案2】:

在 cmets 讨论之后,我想如果我只是简单地使用 *ngFor 发布我的意思会更容易:https://stackblitz.com/edit/clarity-light-theme-v11-vs8aig?file=app%2Fnotifications.provider.ts

使用组件工厂创建始终相同的组件完全是矫枉过正,是一种糟糕的做法。您链接的 Angular 文档部分特别解释了他们的用例是动态实例化一个新组件当他们甚至不知道组件的实际类时。我希望我上面的例子能帮助你理解如何在你的项目中组织这些警报。

【讨论】:

  • 这看起来可行。我正在去你整理的类似的东西的路上。但是,我认为我再次过于复杂化并将通知设置为 Observable&lt;MyAlertType&gt; 而不仅仅是我可以推送到的直接数组。
  • 我注意到的一件事是,如果您从通知开始,使用“x”按钮将其删除,然后添加更多,事情不会显示得很正确。您添加的第一个根本不显示,第二个似乎是为自己制作的,但渲染效果不佳。这似乎是 Clarity 的一个错误?
  • 是的,当用户单击“x”时,通知不会从主数组中删除。你可以通过收听(clrAlertClosedChange): stackblitz.com/edit/… 来连接它
  • 但是使用这种方法,在删除所有警报后,您仍然需要在添加警报后显式设置当前索引。
  • 这有点糟糕,因为我不确定如何访问MultiAlertService 来设置当前索引而不将此代码保留在AppComponent 中以获取ViewChild
猜你喜欢
  • 2021-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多