Açısal 2 - Ng Koleksiyonlar yerine sayıları kullanma


191

...Örneğin...

<div class="month" *ngFor="#item of myCollection; #i = index">
...
</div>

Gibi bir şey yapmak mümkün ...

<div class="month" *ngFor="#item of 10; #i = index">
...
</div>

... zarif olmayan bir çözüme başvurmadan:

<div class="month" *ngFor="#item of ['dummy','dummy','dummy','dummy','dummy',
'dummy','dummy','dummy']; #i = index">
...
</div>

?


8
Aynı problemim var. Gerçekten üzgün biri açısal 2 ile bu kadar basit şeyler yapamaz.
albanx

1
Belki bu yardımcı olabilir: stackoverflow.com/questions/3895478/…
Pizzicato

Yanıtlar:


198

Bileşeninizde, aşağıda açıklandığı gibi bir sayı dizisi (ES6) tanımlayabilirsiniz:

export class SampleComponent {
  constructor() {
    this.numbers = Array(5).fill().map((x,i)=>i); // [0,1,2,3,4]
    this.numbers = Array(5).fill(4); // [4,4,4,4,4]
  }
}

Dizi oluşturmak için bu bağlantıya bakın: JavaScript'te 1..20'den bir tamsayı dizisi oluşturmanın en ters yolu .

Daha sonra bu dizi üzerinden aşağıdakileri tekrarlayabilirsiniz ngFor:

@Component({
  template: `
    <ul>
      <li *ngFor="let number of numbers">{{number}}</li>
    </ul>
  `
})
export class SampleComponent {
  (...)
}

Veya kısaca:

@Component({
  template: `
    <ul>
      <li *ngFor="let number of [0,1,2,3,4]">{{number}}</li>
    </ul>
  `
})
export class SampleComponent {
  (...)
}

5
Evet, Thierry! Bu senin hatan değil, ama yine de aynı bağlamda :( Hiç de zarif değil. Ama çok yetenekli bir A2 geliştiricisi olduğun için, daha iyi bir çözüm olmadığını varsayabilirim. Üzücü!
Marco Jr

Aslında, döngü sözdiziminde Angular2'de bunun için hiçbir şey yoktur. Diziler oluşturmak için JavaScript'in sağladığı özelliklerden yararlanmanız gerekir. Örneğin: Array(5).fill(4)yaratmak için[4,4,4,4,4]
Thierry Templier

3
Not: @View notu, açısal2 beta 10 ve üstü sürümlerde kaldırıldı.
Pardeep Jain

23
Array.fill()Açısal 2 Dizgisinde kullanmak şu hatayı üretir Supplied parameters do not match any signature of call t arget.- Array.prototype.fill belgelerini kontrol etmek, 1 argüman gerektirdiğini söylüyor ... developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Joshua Russell

5
Array(5).fill(1).map((x, i) => i + 1); /*[1,2,3,4,5]*/Bu TS
mshahbazm

90

@OP, "zarif olmayan" çözüm ile çok yakın.

Nasıl olur:

<div class="month" *ngFor="let item of [].constructor(10); let i = index"> ... </div>

İşte alıyorum Array: Boş bir diziden yapıcı [].constructor, çünkü Arrayşablon sözdizimi tanınmış sembolü değildir ve ben yapamayacak kadar tembelim Array=Arrayveya counter = Arrayonun 4 örnekte yaptığımız @ pardeep-jain gibi bileşen daktilo. Ve ben yapmadan çağırıyorum newçünkü yapıcıdan newbir dizi almak için gerekli değil Array.

Array(30)ve new Array(30)eşdeğerdir.

Dizisi boş olacak, ama sen gerçekten sadece kullanmak istediğiniz çünkü önemli değil iitibaren ;let i = indexsizin döngü içinde.


13
Bu en iyi cevap.
kagronick

Bu çözüm değişiklik algılamayı tetikler. Sanırım yeni Dizi yüzünden.
Tobias81

1
@ Tobias81, biraz ayrıntı verebilir misiniz? Uygulama değişiklik algılamayı her çalıştırdığında, dizi yeniden oluşturulduğundan * ngFor içeriğinin yeniden çizildiğini mi söylüyorsunuz? Bu kesinlikle kayda değer. Aslında referans için TS'de bir dizi alanı oluşturarak etrafta dolaşabilir, böylece değişiklik algılama her çalıştığında aynı olur. Ancak bu kesinlikle istenenden daha az zarif olacaktır. Thierry Templier'ın seçilen cevabındaki 2. örnekte aynı değişiklik algılama sorunu var mı? <li *ngFor="let number of [0,1,2,3,4]">{{number}}</li>
jcairney

Bu sorun için en iyi çözüm budur
khush

1
@ Tobias81, ngFor yönergesinin alt öğesi olarak oluşturduğum bir bileşenin yapıcısının içine bir print deyimi koyarak, değişiklik algılamanın ngFor içeriğini sürekli olarak yeniden yaratmadığından emin olmak için kontrol ettim. Bileşenleri her Değişiklik Algılama yinelemesinde yeniden oluşturulduğunu görmüyorum, bu yüzden aslında bir sorun olduğunu düşünmüyorum (en azından Açısal 8'de).
jcairney

83

Hayır Ng Ng için sayı yerine koleksiyon kullanmak için henüz bir yöntem yok, Şu anda, * ngFor sadece bir koleksiyonu parametre olarak kabul etmektedir, ancak bunu aşağıdaki yöntemleri kullanarak yapabilirsiniz:

Boru kullanma

pipe.ts

import {Pipe, PipeTransform} from 'angular2/core';

@Pipe({name: 'demoNumber'})
export class DemoNumber implements PipeTransform {
  transform(value, args:string[]) : any {
    let res = [];
    for (let i = 0; i < value; i++) {
        res.push(i);
      }
      return res;
  }
}


<ul>
  <li>Method First Using PIPE</li>
  <li *ngFor='let key of 5 | demoNumber'>
    {{key}}
  </li>
</ul>

Sayı dizisini doğrudan HTML'de kullanma (Görünüm)

<ul>
  <li>Method Second</li>
  <li *ngFor='let key of  [1,2]'>
    {{key}}
  </li>
</ul>

Bölme yöntemini kullanma

<ul>
  <li>Method Third</li>
  <li *ngFor='let loop2 of "0123".split("")'>{{loop2}}</li>
</ul>

Bileşende yeni dizi oluşturmayı kullanma

<ul>
  <li>Method Fourth</li>
  <li *ngFor='let loop3 of counter(5) ;let i= index'>{{i}}</li>
</ul>

export class AppComponent {
  demoNumber = 5 ;

  counter = Array;

  numberReturn(length){
    return new Array(length);
  }
}

Çalışma demosu


4
Thierrys yanıtında gösterilenler Array.fill()yerine dizi oluşturmak için de yöntemi kullanabilirsiniz res.push().
Günter Zöchbauer

evet yapabilirim ama yanlış bir şey var pushmı? yani her iki yöntem de doğru ama yine de herhangi bir fark. onların arasında.
Pardeep Jain

3
Hayır, yine de güzel bir çözüm +1. Sadece Array.fill()itme kullanarak döngüden daha zarif buluyorum ve muhtemelen daha verimli.
Günter Zöchbauer

1
Bu çözümü counter = Arrayçok akıllıca seviyorum ;)
Verri

11

Bileşenlerin düz tekrarı için bir dizi ayırma fikrine dayanamadım, bu yüzden yapısal bir yönerge yazdım. Dizini şablon için kullanılabilir hale getirmeyen en basit biçimde, şuna benzer:

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

@Directive({ selector: '[biRepeat]' })
export class RepeatDirective {

  constructor( private templateRef: TemplateRef<any>,
             private viewContainer: ViewContainerRef) { }

  @Input('biRepeat') set count(c:number) {
    this.viewContainer.clear();
    for(var i=0;i<c;i++) {
      this.viewContainer.createEmbeddedView(this.templateRef);
    }
  }
}

http://plnkr.co/edit/bzoNuL7w5Ub0H5MdYyFR?p=preview


Dizi yaklaşımının çirkin olduğunu kabul ediyorum, ama bu benim için erken optimizasyon gibi görünüyor.
Aluan Haddad

3
Tabii ki, aynı zamanda bir direktif yazma alıştırması. Öte yandan, ikinci aklı başında yaklaşım olacak olan borudan daha uzun değildir.
pdudits

Bu iyi bir nokta, bazılarını özel yapısal direktifler konseptiyle elde etmek için çok fazla fırsat yok.
Aluan Haddad

Nice one @pdudits - Hala en son sürümlerle çalışır: plnkr.co/edit/8wJtkpzre3cBNokHcDL7?p=preview [ plnkr'nizi güncellemekten çekinmeyin]
AT

5

Angular 5.2.6 ve TypeScript 2.6.2 kullanarak bunu çözdüm:

class Range implements Iterable<number> {
    constructor(
        public readonly low: number,
        public readonly high: number,
        public readonly step: number = 1
    ) {
    }

    *[Symbol.iterator]() {
        for (let x = this.low; x <= this.high; x += this.step) {
            yield x;
        }
    }
}

function range(low: number, high: number) {
    return new Range(low, high);
}

Aşağıdaki gibi bir Bileşende kullanılabilir:

@Component({
    template: `<div *ngFor="let i of r">{{ i }}</div>`
})
class RangeTestComponent {
    public r = range(10, 20);
}

Hata kontrolü ve kısalık amacına yönelik ihmaller (örn. Adım negatifse ne olur).


2
HTML olarak <div *ngfor="let i of 4, i++"></div>olabilir herhangi bir yolu var mı
Nithila Shanmugananthan

5

ayrıca böyle kullanabilirsiniz

export class SampleComponent {
   numbers:Array<any> = [];
   constructor() {
      this.numbers = Array.from({length:10},(v,k)=>k+1);
   }
}

HTML

<p *ngFor="let i of numbers">
   {{i}}
</p>

4

Lodash'ı kullanabilirsiniz:

@Component({
  selector: 'board',
  template: `
<div *ngFor="let i of range">
{{i}}
</div>
`,
  styleUrls: ['./board.component.css']
})
export class AppComponent implements OnInit {
  range = _.range(8);
}

Kodu test etmedim ama işe yaramalı.


HTML olarak <div *ngfor="let i of 4, i++"></div>olabilir herhangi bir yolu var mı
Nithila Shanmugananthan

iBir koda ihtiyacınız varsa veya bir dizinde dizin oluşturuyorsanız*ngFor="let i of range; let i = index"
Alex Po

3

Bu da şu şekilde elde edilebilir:

HTML:

<div *ngFor="let item of fakeArray(10)">
     ...
</div>

typescript:

fakeArray(length: number): Array<any> {
  if (length >= 0) {
    return new Array(length);
  }
}

Çalışma Demosu


2

Fill () yöntemi (kabul edilen cevapta belirtilen) argüman olmadan bir hata attığından, böyle bir şey öneririm (benim için çalışır, Açısal 7.0.4, Daktilo 3.1.6)

<div class="month" *ngFor="let item of items">
...
</div>

Bileşen kodunda:

this.items = Array.from({length: 10}, (v, k) => k + 1);

1
<div *ngFor="let number of [].constructor(myCollection)">
    <div>
        Hello World
    </div>
</div>

Bu, myCollection öğesinde defalarca tekrarlamanın güzel ve hızlı bir yoludur.

Bu nedenle, myCollection 5 olsaydı, Hello World 5 kez tekrarlanırdı.


1

İndeks ile özel Yapısal Direktif kullanma:

Açısal belgelere göre:

createEmbeddedView Katıştırılmış bir görünümü başlatır ve bu kaba ekler.

abstract createEmbeddedView(templateRef: TemplateRef, context?: C, index?: number): EmbeddedViewRef.

Param          Type           Description
templateRef    TemplateRef    the HTML template that defines the view.
context        C              optional. Default is undefined.
index          number         the 0-based index at which to insert the new view into this container. If not specified, appends the new view as the last entry.

Açısal, createEmbeddedView öğesini çağırarak şablon oluşturduğunda içeride kullanılacak içeriği de geçirebilir ng-template.

Bağlam isteğe bağlı parametresini kullanarak, bunu bileşen içinde kullanabilirsiniz ve tıpkı * ngFor'da olduğu gibi şablon içinde ayıklayabilirsiniz.

app.component.html:

<p *for="number; let i=index; let c=length; let f=first; let l=last; let e=even; let o=odd">
  item : {{i}} / {{c}}
  <b>
    {{f ? "First,": ""}}
    {{l? "Last,": ""}}
    {{e? "Even." : ""}}
    {{o? "Odd." : ""}}
  </b>
</p>

for.directive.ts:

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

class Context {
  constructor(public index: number, public length: number) { }
  get even(): boolean { return this.index % 2 === 0; }
  get odd(): boolean { return this.index % 2 === 1; }
  get first(): boolean { return this.index === 0; }
  get last(): boolean { return this.index === this.length - 1; }
}

@Directive({
  selector: '[for]'
})
export class ForDirective {
  constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) { }

  @Input('for') set loop(num: number) {
    for (var i = 0; i < num; i++)
      this.viewContainer.createEmbeddedView(this.templateRef, new Context(i, num));
  }
}

0

Bir düğmeye tıkladıktan sonra bir dizinin boyutunu dinamik olarak artırmak istiyorsanız lütfen dinamik çözümümü ekli olarak bulun (Bu soruya bu şekilde ulaştım).

Gerekli değişkenlerin tahsisi:

  array = [1];
  arraySize: number;

Diziye bir öğe ekleyen işlevi bildirin:

increaseArrayElement() {
   this.arraySize = this.array[this.array.length - 1 ];
   this.arraySize += 1;
   this.array.push(this.arraySize);
   console.log(this.arraySize);
}

İşlevi HTML olarak çağır

  <button md-button (click)="increaseArrayElement()" >
      Add element to array
  </button>

NgFor ile dizi üzerinden yineleme yapın:

<div *ngFor="let i of array" >
  iterateThroughArray: {{ i }}
</div>

HTML olarak <div *ngfor="let i of 4, i++"></div>olabilir herhangi bir yolu var mı
Nithila Shanmugananthan

bir dizi üzerinden yinelemeniz gerekir. Skalere ihtiyacınız varsa, doğru boyutta bir dizi üzerinde yineleme yapabilir ve buna ek olarak bir skaler başlatabilirsiniz: * ngFor = "dizi öğesine izin ver; let i = index"
Jan Clemens Stoffregen

0

Denediğim en basit yol

Ayrıca bileşen dosyanızda bir dizi oluşturabilir ve dizi olarak geri dönerek * ngFor yönergesi ile çağırabilirsiniz.

Böyle bir şey ....

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-morning',
  templateUrl: './morning.component.html',
  styleUrls: ['./morning.component.css']
})
export class MorningComponent implements OnInit {

  arr = [];
  i: number = 0;
  arra() {
    for (this.i = 0; this.i < 20; this.i++) {
      this.arr[this.i]=this.i;
    }
    return this.arr;
  }

  constructor() { }

  ngOnInit() {
  }

}

Ve bu işlev html şablon dosyanızda kullanılabilir

<p *ngFor="let a of arra(); let i= index">
value:{{a}} position:{{i}}
</p>

2
HTML olarak <div *ngfor="let i of 4, i++"></div>olabilir herhangi bir yolu var mı
Nithila Shanmugananthan

0

Çözümüm:

export class DashboardManagementComponent implements OnInit {
  _cols = 5;
  _rows = 10;
  constructor() { }

  ngOnInit() {
  }

  get cols() {
    return Array(this._cols).fill(null).map((el, index) => index);
  }
  get rows() {
    return Array(this._rows).fill(null).map((el, index) => index);
  }

Html'de:

<div class="charts-setup">
  <div class="col" *ngFor="let col of cols; let colIdx = index">
    <div class="row" *ngFor="let row of rows; let rowIdx = index">
      Col: {{colIdx}}, row: {{rowIdx}}
    </div>
  </div>
</div>

bu her elde yeni bir Dizi oluşturur. Tepegöz oluşturabilir
Remco Vlierman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.