Как создать пользовательскую директиву с включенным «синтаксисом» в angular 5? - PullRequest
0 голосов
/ 31 августа 2018

В угловом 5 есть встроенная функция для директивы ngIf - as syntax. Вы можете найти пример здесь https://toddmotto.com/angular-ngif-async-pipe.

В приведенном ниже примере user$ является наблюдаемым.

<div *ngIf="(user$ | async) as user; else loading">
  <user-profile
    [user]="user.profile">
  </user-profile>
  <user-messages
    [user]="user.messages">
  </user-messages>
</div>

<ng-template #loading>
  Loading stuff...
</ng-template>

Я создал свою собственную директиву, которая заменяет содержимое элемента загрузкой счетчика, и я хочу включить передачу наблюдаемого в качестве входных данных, см. Код ниже.

@Directive({ selector: '[appLoadingData]' })
export class LoadingDataDirective {
  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainerRef: ViewContainerRef,
    private componentFactoryResolver: ComponentFactoryResolver
  ) { }
  @Input()
  set appLoadingData(data: any) {
    if (data != null) {
      if (data.subscribe) {
        this.addLoadingPlaceholder();
        data.subscribe(() => {
          setTimeout(() => this.addView(), 0);
        });
      } else {
        this.addView();
      }
    } else {
      this.addLoadingPlaceholder();
    }
  }

  private addView() {
    this.viewContainerRef.clear();
    this.viewContainerRef.createEmbeddedView(this.templateRef);
  }

  private addLoadingPlaceholder() {
    this.viewContainerRef.clear();
    const loadingComponentFactory = this.componentFactoryResolver.resolveComponentFactory(LoadingDataComponent);
    this.viewContainerRef.createComponent(loadingComponentFactory);
  }
}

А я хочу использовать следующим образом

    <ng-container *ngFor="let chartConfig of chartsConfigs">
      <div class="chart-wrapper"
        *appLoadingData="(chartConfig.chartGroups$ | async) as groups">
        <chart-summary [chartData]="groups"
          [chartOptionsName]="chartConfig.chartType">
        </chart-summary>
      </div>
    </ng-container>

или в идеале *appLoadingData="chartConfig.chartGroups$ as groups"

Без синтаксиса as (*appLoadingData="chartConfig.chartGroups$ | async" и [chartData]="chartConfig.chartGroups$ | async"), после того, как мой загрузчик уволен, возникает задержка, я думаю, это происходит потому, что в директиве addView() in асинхронный канал вызывается во второй раз. Я хочу реализовать as syntax как для директивы ngIf. Я пытался использовать это так: *appLoadingData="(chartConfig.chartGroups$ | async) as groups", но, к сожалению, в этом случае groups всегда undefined.

Как реализовать as syntax в пользовательской директиве?

1 Ответ

0 голосов
/ 31 августа 2018

Вы видите, что они используют переменную _context. https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts

Также см. Там @yurzui ответ. Как объявить переменную в шаблоне в Angular2

Мой окончательный результат:

export class LoadingDataDirective {
  context: any = {};
  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainerRef: ViewContainerRef,
    private componentFactoryResolver: ComponentFactoryResolver
  ) { }
  @Input()
  set appLoadingData(data: any) {
    if (data != null) {
      if (this.isObservable(data)) {
        this.addLoadingPlaceholder();
        const subscription = data.subscribe((observableResult: any) => {
          this.addView(observableResult);
          subscription.unsubscribe();
        });
      } else {
        this.addView(data);
      }
    } else {
      this.addLoadingPlaceholder();
    }
  }

  private addView(contextData: any) {
    this.context.$implicit = this.context.appLoadingData = contextData;
    this.viewContainerRef.clear();
    this.viewContainerRef.createEmbeddedView(this.templateRef, this.context);
  }

  private addLoadingPlaceholder() {
    this.viewContainerRef.clear();
    const loadingComponentFactory = this.componentFactoryResolver.resolveComponentFactory(LoadingDataComponent);
    this.viewContainerRef.createComponent(loadingComponentFactory);
  }

  private isObservable(data: any): boolean {
    return !!data.subscribe;
  }
}

chartConfig.charGroup$ - это наблюдаемое

   <ng-container *ngFor="let chartConfig of chartsConfigs">
      <div class="chart-wrapper"
        *appLoadingData="chartConfig.chartGroups$ as groups">
        <chart-summary [chartData]="groups"
          [chartOptionsName]="chartConfig.chartType">
        </chart-summary>
      </div>
    </ng-container>
...