Кутовий 2 - NgДля використання цифр замість колекцій


191

...наприклад...

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

Можна зробити щось на кшталт ...

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

... без звернення до не елегантного рішення, як-от:

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

?


8
У мене така ж проблема. Дійсно засмучений, не можна робити таких простих речей з кутовим 2.
albanx

1
Можливо, це може бути корисним: stackoverflow.com/questions/3895478/…
Pizzicato

Відповіді:


197

В межах свого компонента ви можете визначити масив чисел (ES6), як описано нижче:

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]
  }
}

Дивіться це посилання для створення масиву: Tersest спосіб створення масиву цілих чисел від 1..20 в JavaScript .

Потім ви можете повторити цей масив за допомогою ngFor:

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

Або коротко:

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

5
Так, Тьєррі! Дійсно, це не ваша вина, але все ж у тому ж контексті :( Це зовсім не елегантно. Але оскільки ви дуже кваліфікований розробник A2, я можу припустити, що кращого рішення немає. Це сумно!
Марко-молодший,

Насправді, у Angular2 в синтаксисі циклу немає нічого для цього. Вам потрібно використовувати те, що надає JavaScript для створення масивів. Наприклад: Array(5).fill(4)створити[4,4,4,4,4]
Thierry Templier

3
PS: @View анотацію видалено в angular2 beta 10 та вище.
Pardeep Jain

23
Використання Array.fill()в Angular 2 Typescript видає таку помилку Supplied parameters do not match any signature of call t arget.- Перевірка документів Array.prototype.fill, вона говорить про те, що потрібно 1 аргумент ... developer.mozilla.org/uk/docs/Web/JavaScript/Reference/…
Джошуа Рассел

5
Array(5).fill(1).map((x, i) => i + 1); /*[1,2,3,4,5]*/це вирішує помилку в TS
mshahbazm

90

@OP, ви були жахливо близькі зі своїм "неелегантним" рішенням.

Як щодо:

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

Ось я отримую Arrayконструктор з порожнього масиву:, [].constructorтому що Arrayце не розпізнаний символ у синтаксисі шаблону, і я занадто лінивий зробити Array=Arrayабо counter = Arrayв компонентах typecript, як @ pardeep-jain зробив у своєму четвертому прикладі. І я називаю це без того, newщо newне потрібно для отримання масиву з Arrayконструктора.

Array(30)і new Array(30)є рівнозначними.

Масив буде порожній, але це не має значення , тому що ви на самому справі просто хочете використовувати iз ;let i = indexв циклі.


12
Це найкраща відповідь.
kagronick

Це рішення запускає виявлення змін. Я здогадуюсь завдяки новому масиву.
Tobias81

1
@ Tobias81, ви могли б детальніше? Ви хочете сказати, що кожного разу, коли програма запускає виявлення змін, вміст * ngFor переробляється через те, що масив відтворений? Це, безумовно, варто відзначити. Можна було обійти його, фактично створивши поле масиву в ТС для посилання, так що це те саме при кожному запуску виявлення змін. Але це було б точно менш елегантно, ніж бажано. Чи є однакова проблема виявлення змін у другому прикладі вибраної відповіді Тьєррі Темплієра? <li *ngFor="let number of [0,1,2,3,4]">{{number}}</li>
jcairney

це найкраще рішення для цієї проблеми
khush

1
@ Tobias81, я перевіряв, чи виявлення змін не відтворює вміст ngFor неодноразово, вкладаючи оператор друку всередину конструктора компонента, який я створюю як дочірній приклад директиви ngFor. Я не бачу, щоб компоненти були відтворені під час кожної ітерації виявлення змін, тому не думаю, що насправді існує проблема (принаймні, у Angular 8).
jcairney

83

Ні, поки немає методу для NgДля використання номерів замість колекцій, на даний момент * ngFor приймає колекцію лише як параметр, але ви могли це зробити, виконавши наступні методи:

Використання труби

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>

Використання масиву чисел безпосередньо в HTML (Перегляд)

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

Використовуючи метод Спліт

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

Використання створення нового масиву в компоненті

<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);
  }
}

Робоча демонстрація


4
Ви також можете використовувати Array.fill()метод генерації масиву замість того, res.push()як показано у відповіді Thierrys.
Günter Zöchbauer

так, я можу, але чи є щось не так push? Я маю на увазі обидва методи правильні, але все-таки, якщо такі є різними. між ними.
Pardeep Jain

3
Ні, все-таки приємне рішення +1. Я просто вважаю Array.fill()більш елегантним, ніж цикл, використовуючи push, і він, ймовірно, більш ефективний.
Günter Zöchbauer

1
Мені подобається це рішення з counter = Array, дуже розумним;)
Веррі

11

Я не міг винести ідею виділити масив для простого повторення компонентів, тому я написав структурну директиву. У найпростішій формі, що не робить індекс доступним для шаблону, це виглядає приблизно так:

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


Я погоджуюся, що підхід до масиву некрасивий, але це здається передчасною оптимізацією для мене.
Алуан Хаддад

3
Звичайно, але і вправа щодо написання директиви. З іншого боку, це не довше труби, що було б другим розумним підходом.
пдудити

Це хороший момент, не так багато можливостей отримати деякі з ваших концепцій спеціальних структурних директив.
Алуан Хаддад

Ніцца один @pdudits - Ще працює з останніми версіями: plnkr.co/edit/8wJtkpzre3cBNokHcDL7?p=preview [соромтеся оновити plnkr]
AT

5

Я вирішив це так, використовуючи Angular 5.2.6 і TypeScript 2.6.2:

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);
}

Він може використовуватися в такому компоненті:

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

Помилка при перевірці та твердженнях, пропущених спеціально для короткості (наприклад, що відбувається, якщо крок негативний).


2
Чи є якісь -то способи в HTML як про <div *ngfor="let i of 4, i++"></div>може бути
Nithila Shanmugananthan

5

Ви також можете використовувати так

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:

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

Я не перевіряв код, але він повинен працювати.


Чи є якісь -то способи в HTML як про <div *ngfor="let i of 4, i++"></div>може бути
Nithila Shanmugananthan

Якщо вам потрібно iабо вказівник у коді, тоді ви можете зробити*ngFor="let i of range; let i = index"
Алекс По


2

Оскільки метод fill () (згаданий у прийнятій відповіді) без аргументів викликає помилку, я б запропонував щось подібне (працює для мене, Angular 7.0.4, Typescript 3.1.6)

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

У коді компонента:

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

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

Це приємний і швидкий спосіб повторити протягом моєї кількості колекцій.

Отже, якби myCollection було 5, Hello World повторився б 5 разів.


1

Використання спеціальної структурної директиви з індексом:

Відповідно до кутової документації:

createEmbeddedView Вмикає вбудований вигляд і вставляє його в цей контейнер.

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.

Коли angular створює шаблон, викликаючи createEmbeddedView, він також може передавати контекст, який буде використовуватися всередині ng-template.

Використовуючи контекстний необов'язковий параметр, ви можете використовувати його в компоненті, витягуючи його всередині шаблону так само, як і з * ngFor.

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>

для.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

Будь ласка, знайдіть додане моє динамічне рішення, якщо ви хочете динамічно збільшувати розмір масиву після натискання на кнопку (ось як я потрапив до цього питання).

Виділення необхідних змінних:

  array = [1];
  arraySize: number;

Заявіть про функцію, яка додає елемент до масиву:

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

Викликати функцію в html

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

Ітерація через масив з ngFor:

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

Чи є якісь -то способи в HTML як про <div *ngfor="let i of 4, i++"></div>може бути
Nithila Shanmugananthan

вам доведеться перебирати масив. Якщо вам потрібен скаляр, ви можете перебирати масив потрібного розміру та інстанціювати скаляр додатково: * ngFor = "нехай елемент масиву; нехай i = індекс"
Ян Клеменс Стоффреген

0

Найпростіший спосіб, який я спробував

Ви також можете створити масив у своєму компонентному файлі, і ви можете викликати його за допомогою директиви * ngFor, повернувшись як масив.

Щось на зразок цього ....

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() {
  }

}

І цю функцію можна використовувати у вашому файлі шаблонів html

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

2
Чи є якісь способи у <div *ngfor="let i of 4, i++"></div>
форматі

0

Моє рішення:

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:

<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>

це створює новий масив при кожному отриманні. Не
вдалося
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.