如何使用自定义指令在* ngFor中用组件替换目标元素?

时间:2019-03-17 17:05:36

标签: angular angular2-directives

我正在建立一条指令,该指令应替换组件(装入程序)中包含该元素的元素,并在到达延迟时发送错误消息。

遇到的问题:列表中的所有元素均由加载程序代替,而不是我单击的加载程序。

我找不到只选择已单击元素的方法。

Stackblitz: https://stackblitz.com/edit/angular-wmybgc?file=src%2Fapp%2Floader-and-error-handler.directive.ts

指令:


    import { StoreService } from '@services/store/store.service';
    import { Directive, Input, ViewContainerRef, TemplateRef, ComponentFactoryResolver, Type } from '@angular/core';
    import { LoaderComponent } from '@components-ui/loader/loader.component';

    export class LoaderAndErrorContext {
      $implicit: boolean;
      message: string;
    }

    @Directive({
      selector: '[loaderAndErrorHandler]'
    })
    export class LoaderAndErrorHandlerDirective {

      private isLoading: boolean;

      @Input('loaderAndErrorHandlerWait') private delay: number;
      @Input('loaderAndErrorHandlerBeforeDisplaying') private message: string;
      @Input() set loaderAndErrorHandler(isLoading: boolean) {

        this.isLoading = isLoading;

        this.viewControllerRef.clear();

        if (this.isLoading) {

          this.displayComponent(LoaderComponent);

          setTimeout(() => {
            this.store.sendNotification(this.message);
          }, this.delay);
        }
        else {
          this.viewControllerRef.clear();
          this.viewControllerRef.createEmbeddedView(this.templateRef);
        }
      }

      constructor(
        private viewControllerRef: ViewContainerRef,
        private templateRef: TemplateRef<any>,
        private componentFactoryResolver: ComponentFactoryResolver,
        private store: StoreService
      ) {
        this.displayComponent = this.displayComponent.bind(this);
      }

      displayComponent = (component: Type<LoaderComponent>, message?: string): void => {
        const componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
        message
          ? this.viewControllerRef.createComponent(componentFactory).instance['message'] = message
          : this.viewControllerRef.createComponent(componentFactory);
      }
    }

实施:

<h2>Mes documents</h2>
<ul [@fadeInOutStagger]="documents.length">
  <ng-container *loaderAndErrorHandler="isLoading; wait 2000 beforeDisplaying errorMessage;">
  <li *ngFor="let document of documents | sortBy:'label'">
      <article (click)="getDocument(document.id)" class="document-label">
        <input type="image" src="assets/images/icon/icone_document.svg">
        <label>
          <strong>{{document.label}}</strong>
        </label>
      </article>
      <article class="document-date">
        <p>{{document.date | dateTo:'JJ Mois'}}</p>
      </article>
  </li>
  </ng-container>
</ul>

1 个答案:

答案 0 :(得分:0)

您可以这样操作:

<h2>Mes documents</h2>
<ul>
  <ng-container *ngFor="let document of documents; let i = index" >
  <li *loaderAndErrorHandler="document.isLoading; wait 2000 beforeDisplaying errorMessage;">
      <article (click)="getDocument(document.id, i)" class="document-label">
        <img src="https://image.noelshack.com/fichiers/2019/11/7/1552854323-iconfinder-note3-254240.png" height="20px" width="20px">
        <label>
          <strong>{{document.label}}</strong>
        </label>
      </article>
      <article class="document-date">
        <p>{{document.date}}</p>
      </article>
  </li>
  </ng-container>
</ul>

getDocument方法将循环索引作为额外的参数,以检索要更新的良好参数。对于该示例,您必须选择其他值以确保文档存在于数据中。

import { Component, Input, ViewRef } from '@angular/core';
import { StoreService } from './services/store/store.service';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {

  documents = [
    {
      id: '123',
      label: 'Certificat of something great',
      date: '15 jun.',
      isLoading: false
    },
    {
      id: '123',
      label: 'Certificat of something not so great',
      date: '15 jun.',
      isLoading: false
    },
    {
      id: '123',
      label: 'Certificat of something ok',
      date: '15 jun.',
      isLoading: false
    },
  ];

  public errorMessage = 'Erreur: Une erreur s\'est produite durant la récupération de votre document.\nVeuillez renouveler votre requête ultérieurement.'

  constructor(private store: StoreService) {
    this.store.notificationPublisher.subscribe(notification => {
      console.log('Notification:', notification)
    })
  }

  public getDocument = (documentId: string, documentIndex: number): void => {
    this.documents[documentIndex].isLoading = true;
    setTimeout(() => {
      this.documents[documentIndex].isLoading = false;
    }, 1000)
  }
}

我只为每个文档和您用*ngFor循环的项目添加了状态。

编辑:您可以在此处进行测试=> https://stackblitz.com/edit/angular-hfnhg7