【问题标题】:How to replace targeted element by a component in *ngFor using custom directive?如何使用自定义指令将目标元素替换为 *ngFor 中的组件?
【发布时间】:2019-03-17 17:05:36
【问题描述】:

我正在构建一个指令,该指令应替换组件(加载器)包含的元素,并在达到延迟时发送错误消息。

遇到的问题:列表中的所有元素都被加载器替换,而不是我点击的那个。

我找不到只选择被点击的元素的方法。

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>

【问题讨论】:

  • 你能为此创建一个堆栈闪电战吗?
  • @dince12 它应该可以工作stackblitz.com/edit/…
  • isLoading 布尔值与每个项目共享,因此当您更改一个的值时,每个项目都会更改。

标签: angular angular2-directives


【解决方案1】:

你可以这样做:

<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循环的项目添加了一个状态

EDIT : 你可以在这里测试它 => https://stackblitz.com/edit/angular-hfnhg7

【讨论】:

  • 我可以定位 id ! :) 谢谢,我太投入了,以至于我错过了布尔值一直被共享的事实??
  • :) 如果您满意,请考虑批准答案;)
  • 当然!在批准您的答案之前,我只需要在我的项目中对其进行测试;)
猜你喜欢
  • 1970-01-01
  • 2021-12-17
  • 2017-11-30
  • 2014-04-25
  • 1970-01-01
  • 2018-11-05
  • 2016-08-24
  • 1970-01-01
  • 2020-03-21
相关资源
最近更新 更多