简体   繁体   English

Angular 5-ngFor切片数组上的子索引

[英]Angular 5 - sub index of a ngFor over sliced array

I have a list lets call it answers of numbers and am taking slices of that array and displaying there value. 我有一个列表,可以称其为数字答案,并且正在对该数组进行切片并显示值。 What I'd like to do is also note the position of what place I want in the array... 我想做的是还要注意我要在数组中放置什么位置...

<div *ngFor="let item of answers | slice: 3:6" class="float-left square">
    {{ item }}
</div>

I have tried: 我努力了:

<div *ngFor="let item of answers | slice: 3:6; index as i" class="float-left square">
    {{ item }} {{ i }}
</div>

But i results in 0,1,2 instead of the desired 3,4,5 respectively. 但是i得到0,1,2,而不是期望的3,4,5

Thoughts? 思考? The idea using the index likely is bogus as I say this while searching before asking. 正如我在询问之前进行搜索时所说的那样,使用索引的想法可能是虚假的。

My Solution 我的解决方案

So lots of folks had some great ideas; 因此,许多人都有一些很棒的主意。 but, not really a fit. 但是,这并不适合。

<div *ngFor="let item of answers | slice: 60:63; index as i"
                (click)="pickSquare(60 +i)" id="{{60 + i}}"
                class="float-left square">{{item}}</div>

What I did was manually enter the start value to the pick the square, and created an ID so I could find the unique Div (still seems butt backwards). 我所做的是手动输入起始值以选择正方形,并创建了一个ID,以便我可以找到唯一的Div(似乎仍然向后倾斜)。

In my .ts file I created a remember variable and created a pickSquare added a class to highlight that the square was picked. 在我的.ts文件中,我创建了一个Remember变量并创建了pickSquare添加了一个类来突出显示正方形已被选中。 Then a generic find any "red" lets call it, to clear the board and place a new "red" picked square after the fact. 然后,泛型找到任何“红色”来调用它,以清理木板并在事实之后放置一个新的“红色”拾取正方形。

Being "new", I wish I could accept all answers as you were all a great help. 作为“新手”,我希望我能接受所有答案,因为你们都对我有很大帮助。

You could simply pad the index with the offset (3) 您可以简单地用偏移量(3)填充索引

Something like this: 像这样:

<div *ngFor="let item of answers | slice: 3:6; index as i" class="float-left square">
    {{ item }} {{ i+3 }}
</div>

StackBlitz Example StackBlitz示例

With slice you are looking at a new array of slice so the index will be reset. 使用slice时,您正在查看一个新的slice数组,因此将重置索引。 In console type [1,2,3,4,5,6,7].slice(3, 6) and see what happens. 在控制台中,键入[1,2,3,4,5,6,7] .slice(3,6)并查看会发生什么。 If that 3 is a variable you can do something like: 如果3是变量,则可以执行以下操作:

<div *ngFor="let item of answers | slice: offset:6; index as i" class="float-left square">{{item}} {{i + offset}}</div>

There are 2 methods for doing this. 有两种方法可以做到这一点。

  1. You can add it to the index during the interpolation time like this. 您可以像这样在插值期间将其添加到索引中。

    <div *ngFor="let item of answers | slice: 3:6; index as i" class="float-left square"> {{ item }} {{ i }} </div>

  2. You can create a child component and pass the starting point value of the slice, the value to be printed and the index of the element. 您可以创建一个子组件,并传递切片的起点值,要打印的值和元素的索引。

Here is the stackblitz for the second point. 这是第二点的堆叠闪电战

Hope this helps !! 希望这可以帮助 !!

Build your own loop based on the ngFor to return the original index from the array and set start, end slice value directly in the loop. 基于ngFor构建自己的循环,以从数组返回原始索引,并直接在循环中设置start,end slice值。

Create file for-with-slice.directive.ts and set this code. 创建for-with-slice.directive.ts文件并设置此代码。 This is original ngFor with add slice options and realIndex variable. 这是原始的ngFor,带有添加切片选项和realIndex变量。

import { ChangeDetectorRef, Directive, DoCheck, EmbeddedViewRef, Input, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDiffers, NgIterable, OnChanges, SimpleChanges, TemplateRef, TrackByFunction, ViewContainerRef, forwardRef, isDevMode } from '@angular/core';

/**
 * @stable
 */
export class ngForWithSliceOfContext<T> {
  constructor(
    public $implicit: T,
    public ngForWithSliceOf: NgIterable<T>,
    public index: number,
    public realIndex: number,
    public sliceStart: number,
    public sliceEnd: number,
    public count: number) { }

  get first(): boolean { return this.index === 0; }

  get last(): boolean { return this.index === this.count - 1; }

  get even(): boolean { return this.index % 2 === 0; }

  get odd(): boolean { return !this.even; }
}

@Directive({ selector: '[ngForWithSlice][ngForWithSliceOf]' })
export class NgForWithSliceOf<T> implements DoCheck, OnChanges {

  @Input() ngForWithSliceOf: NgIterable<T>;
  @Input() ngForWithSliceSliceStart: number = 0;
  @Input() ngForWithSliceSliceEnd: number;
  @Input()
  set ngForTrackBy(fn: TrackByFunction<T>) {
    if (isDevMode() && fn != null && typeof fn !== 'function') {

      if (<any>console && <any>console.warn) {
        console.warn(
          `trackBy must be a function, but received ${JSON.stringify(fn)}. ` +
          `See https://angular.io/docs/ts/latest/api/common/index/NgFor-directive.html#!#change-propagation for more information.`);
      }
    }
    this._trackByFn = fn;
  }

  get ngForTrackBy(): TrackByFunction<T> { return this._trackByFn; }

  private _differ: IterableDiffer<T> | null = null;
  private _trackByFn: TrackByFunction<T>;

  constructor(
    private _viewContainer: ViewContainerRef,
    private _template: TemplateRef<ngForWithSliceOfContext<T>>,
    private _differs: IterableDiffers) { }

  @Input()
  set ngForTemplate(value: TemplateRef<ngForWithSliceOfContext<T>>) {
    if (value) {
      this._template = value;
    }
  }

  ngOnChanges(changes: SimpleChanges): void {
    if ('ngForWithSliceOf' in changes) {
      const value = changes['ngForWithSliceOf'].currentValue;
      if (!this._differ && value) {
        try {
          this._differ = this._differs.find(value).create(this.ngForTrackBy);
        } catch (e) {
          throw new Error(
            `Cannot find a differ supporting object '${value}' of type '${getTypeNameForDebugging(value)}'. NgFor only supports binding to Iterables such as Arrays.`);
        }
      }
    }
  }

  ngDoCheck(): void {
    if (this._differ) {
      const changes = this._differ.diff(this.ngForWithSliceOf);
      if (changes) this._applyChanges(changes);
    }
  }

  private _applyChanges(changes: IterableChanges<T>) {

    const insertTuples: RecordViewTuple<T>[] = [];
    changes.forEachOperation(
      (item: IterableChangeRecord<any>, adjustedPreviousIndex: number, currentIndex: number) => {
        let endOfArray = this.ngForWithSliceSliceEnd;
        if (typeof endOfArray === "undefined") {
          endOfArray = item.currentIndex + 1;
        }
        if (item.currentIndex >= this.ngForWithSliceSliceStart && item.currentIndex < endOfArray) {
          if (item.previousIndex == null) {
            const view = this._viewContainer.createEmbeddedView(
              this._template,
              new ngForWithSliceOfContext<T>(null!, this.ngForWithSliceOf, -1, -1, 0, 0, -1), currentIndex - this.ngForWithSliceSliceStart );
            const tuple = new RecordViewTuple<T>(item, view);
            insertTuples.push(tuple);
          } else if (currentIndex == null) {
            this._viewContainer.remove(adjustedPreviousIndex);
          } else {
            const view = this._viewContainer.get(adjustedPreviousIndex)!;
            this._viewContainer.move(view, currentIndex);
            const tuple = new RecordViewTuple(item, <EmbeddedViewRef<ngForWithSliceOfContext<T>>>view);
            insertTuples.push(tuple);
          }
        }
      });

    console.error(insertTuples)
    for (let i = 0; i < insertTuples.length; i++) {

      this._perViewChange(insertTuples[i].view, insertTuples[i].record);
    }

    for (let i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
      const viewRef = <EmbeddedViewRef<ngForWithSliceOfContext<T>>>this._viewContainer.get(i);
      viewRef.context.index = i;
      viewRef.context.realIndex = i + this.ngForWithSliceSliceStart;
      viewRef.context.count = ilen;
    }

    changes.forEachIdentityChange((record: any) => {
      const viewRef =
        <EmbeddedViewRef<ngForWithSliceOfContext<T>>>this._viewContainer.get(record.currentIndex);
      viewRef.context.$implicit = record.item;
    });
  }

  private _perViewChange(
    view: EmbeddedViewRef<ngForWithSliceOfContext<T>>, record: IterableChangeRecord<any>) {
    view.context.$implicit = record.item;
  }
}

class RecordViewTuple<T> {
  constructor(public record: any, public view: EmbeddedViewRef<ngForWithSliceOfContext<T>>) { }
}

export function getTypeNameForDebugging(type: any): string {
  return type['name'] || typeof type;
}

Declaration and export in module: 声明和导出模块:

import { NgForWithSliceOf } from './for-with-slice.directive'
...
@NgModule({
  imports:      [ ... ],
  declarations: [ ... NgForWithSliceOf ],
  bootstrap:    [ ... ],
  exports: [NgForWithSliceOf],
})

Use in template: 在模板中使用:

<div *ngForWithSlice="let thing of allTheThings; sliceStart: 2; sliceEnd: 7; realIndex as i; index as j">
  {{'Value: ' + thing}} {{'realIndex: ' + i}} {{' index: ' + j }}
</div>

component example array: 组件示例数组:

allTheThings = [0, 1, 2, 2,3,6,2,1];

StackBlitz Example StackBlitz示例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM