ключ доступа и значение объекта с помощью *ngFor
немного запутался о том, как получить Key and Value объекта в angular2 в то время как usng *ngFor для итерации по объекту. я знаю в угловой 1.х есть следующий синтаксис
ng-repeat="(key, value) in demo"
но в angular2 я не знаю, я устал то же самое, но не добился успеха. я пробовал ниже код, но не работает, пожалуйста, скажите мне, где я делаю неправильно.
<ul>
<li *ngFor='#key of demo'>{{key}}</li>
</ul>
demo = {
'key1': [{'key11':'value11'}, {'key12':'value12'}],
'key2': [{'key21':'value21'}, {'key22':'value22'}],
}
вот plnkr, где я пробовал то же самое :
http://plnkr.co/edit/mIj619FncOpfdwrR0KeG?p=preview
Я хочу сделать key1 и key2 динамическое использование *ngFor. Как его получить?
я искал много нашел идею использования трубы, но как использовать я не знаю.
есть ли встроенная труба для того, чтобы сделать то же самое в angular2 ?
15 ответов:
есть
Object.keysдоступно в шаблоне и использовать его в*ngFor.@Component({ selector: 'app-myview', template: `<div *ngFor="let key of objectKeys(items)">{{key + ' : ' + items[key]}}</div>` }) export class MyComponent { objectKeys = Object.keys; items = { keyOne: 'value 1', keyTwo: 'value 2', keyThree: 'value 3' }; constructor(){} }
вы можете создать пользовательский канал для возврата списка ключей для каждого элемента. Что-то вроде этого:
import { PipeTransform, Pipe } from '@angular/core'; @Pipe({name: 'keys'}) export class KeysPipe implements PipeTransform { transform(value, args:string[]) : any { let keys = []; for (let key in value) { keys.push(key); } return keys; } }и использовать его как это:
<tr *ngFor="let c of content"> <td *ngFor="let key of c | keys">{{key}}: {{c[key]}}</td> </tr>Edit
вы также можете вернуть запись, содержащую ключ и значение:
@Pipe({name: 'keys'}) export class KeysPipe implements PipeTransform { transform(value, args:string[]) : any { let keys = []; for (let key in value) { keys.push({key: key, value: value[key]}); } return keys; } }и использовать его как это:
<span *ngFor="let entry of content | keys"> Key: {{entry.key}}, value: {{entry.value}} </span>
а в последний релиз Angular (v6.1.0), угловая команда добавила новую встроенную трубу для того же имени, что и
keyvalueтруба, чтобы помочь вам перебирать объекты, карты и массивы, вcommonмодуль углового пакета. Например -<div *ngFor="let item of testObject | keyvalue"> Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b> </div>Рабочий Разветвленный Пример
проверьте здесь для получения дополнительной полезной информации -
- https://github.com/angular/angular/blob/master/CHANGELOG.md#features-3
- https://github.com/angular/angular/commit/2b49bf7
Если вы используете угловой v5 или ниже, или вы хотите достичь с помощью трубы, следуйте этому ответу
обновление
на 6.1.0-бета.1KeyValuePipe был представлен https://github.com/angular/angular/pull/24319
<div *ngFor="let item of {'b': 1, 'a': 1} | keyvalue"> {{ item.key }} - {{ item.value }} </div>предыдущие версии
другой подход заключается в создании
NgForInдиректива, которая будет использоваться как:<div *ngFor="let key in obj"> <b>{{ key }}</b>: {{ obj[key] }} </div>ngforin.директива.ТС
@Directive({ selector: '[ngFor][ngForIn]' }) export class NgForIn<T> extends NgForOf<T> implements OnChanges { @Input() ngForIn: any; ngOnChanges(changes: NgForInChanges): void { if (changes.ngForIn) { this.ngForOf = Object.keys(this.ngForIn) as Array<any>; const change = changes.ngForIn; const currentValue = Object.keys(change.currentValue); const previousValue = change.previousValue ? Object.keys(change.previousValue) : undefined; changes.ngForOf = new SimpleChange(previousValue, currentValue, change.firstChange); super.ngOnChanges(changes); } } }
разработка ответа @Thierry с примером.
нет встроенной трубы или метода для получения
key and valueиз цикла * ngFor. поэтому мы должны создать пользовательский канал для того же. как сказал Тьерри вот ответ с кодом.** класс pipe реализует метод преобразования интерфейса PipeTransform, который принимает входное значение и необязательный массив строк параметров и возвращает преобразованное значение.
* * метод преобразования имеет важное значение для a труба. Интерфейс PipeTransform определяет этот метод и направляет как инструмент, так и компилятор. Это необязательно; Angular ищет и выполняет метод преобразования независимо. для получения дополнительной информации с уважением pipe см. здесь
import {Component, Pipe, PipeTransform} from 'angular2/core'; import {CORE_DIRECTIVES, NgClass, FORM_DIRECTIVES, Control, ControlGroup, FormBuilder, Validators} from 'angular2/common'; @Component({ selector: 'my-app', templateUrl: 'mytemplate.html', directives: [CORE_DIRECTIVES, FORM_DIRECTIVES], pipes: [KeysPipe] }) export class AppComponent { demo = { 'key1': 'ANGULAR 2', 'key2': 'Pardeep', 'key3': 'Jain', } } @Pipe({name: 'keys'}) export class KeysPipe implements PipeTransform { transform(value, args:string[]) : any { let keys = []; for (let key in value) { keys.push({key: key, value: value[key]}); } return keys; } }и HTML часть:
<ul> <li *ngFor='#key of demo | keys'> Key: {{key.key}}, value: {{key.value}} </li> </ul>рабочий Plnkr http://plnkr.co/edit/50LlK0k6OnMnkc2kNHM2?p=preview
обновление до RC
как предложил user6123723 (спасибо) в комментарии вот обновление.
<ul> <li *ngFor='let key of demo | keys'> Key: {{key.key}}, value: {{key.value}} </li> </ul>
@Мартон был главное возражение против принятого ответа на том основании, что канал создает новую коллекцию при каждом обнаружении изменений. Вместо этого я бы создал HtmlService, который предоставляет ряд служебных функций, которые представление может использовать следующим образом:
@Component({ selector: 'app-myview', template: `<div *ngFor="let i of html.keys(items)">{{i + ' : ' + items[i]}}</div>` }) export class MyComponent { items = {keyOne: 'value 1', keyTwo: 'value 2', keyThree: 'value 3'}; constructor(private html: HtmlService){} } @Injectable() export class HtmlService { keys(object: {}) { return Object.keys(object); } // ... other useful methods not available inside html, like isObject(), isArray(), findInArray(), and others... }
Если вы уже используете Lodash, вы можете сделать этот простой подход, который включает в себя как ключ, так и значение:
<ul> <li *ngFor='let key of _.keys(demo)'>{{key}}: {{demo[key]}}</li> </ul>в TypeScript-файлов, включают в себя:
import * as _ from 'lodash';и в экспортируемом компоненте включите:
_: any = _;
из углового 6.1 вы можете использовать keyvalue трубы:
<div *ngFor="let item of testObject | keyvalue"> Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b> </div>но это неудобно, что сортирует полученный список по значению ключа. Если вам нужно что-то нейтральное:
@Pipe({ name: 'keyValueUnsorted' }) export class KeyValuePipe implements PipeTransform { transform(value: any, args: string[]): any { let keys = []; for (let key in value) { keys.push({ key: key, value: value[key]}); } return keys; } }
Спасибо за трубу, но мне пришлось внести некоторые изменения, прежде чем я мог использовать его в angular 2 RC5. Изменена строка импорта канала, а также добавлен тип any для инициализации массива ключей.
import {Pipe, PipeTransform} from '@angular/core'; @Pipe({name: 'keys'}) export class KeysPipe implements PipeTransform { transform(value) { let keys:any = []; for (let key in value) { keys.push( {key: key, value: value[key]} ); } return keys; } }
ни один из ответов здесь не работал для меня из коробки, вот что сработало для меня:
создать
pipes/keys.tsсодержание:import { Pipe, PipeTransform } from '@angular/core'; @Pipe({name: 'keys'}) export class KeysPipe implements PipeTransform { transform(value:any, args:string[]): any { let keys:any[] = []; for (let key in value) { keys.push({key: key, value: value[key]}); } return keys; } }добавить
app.module.ts(основной модуль):import { KeysPipe } from './pipes/keys';а затем добавить в свой модуль объявления массива что-то вроде этого:
@NgModule({ declarations: [ KeysPipe ] }) export class AppModule {}тогда в вашем шаблоне просмотра вы можете использовать что-то вроде этого:
<option *ngFor="let entry of (myData | keys)" value="{{ entry.key }}">{{ entry.value }}</option>здесь это хорошая ссылка, которую я нашел, если вы хотите прочитать больше.
есть очень хорошая библиотека, которая делает это среди других приятных труб. Это называется фабриката необходмо предусмотреть трубы.
например, keys pipe возвращает ключи для объекта, а values pipe возвращает значения для объекта:
ключи трубы
<div *ngFor="let key of {foo: 1, bar: 2} | keys">{{key}}</div> <!-- Output: 'foo' and 'bar -->значения pipe
<div *ngFor="let value of {foo: 1, bar: 2} | values">{{value}}</div> <!-- Output: 1 and 2 -->нет необходимости создавать свои собственные трубы:)
вот простое решение
вы можете использовать итераторы typescript для этого
import {Component} from 'angular2/core'; declare var Symbol; @Component({ selector: 'my-app', template:`<div> <h4>Iterating an Object using Typescript Symbol</h4><br> Object is : <p>{{obj | json}}</p> </div> ============================<br> Iterated object params are: <div *ngFor="#o of obj"> {{o}} </div> ` }) export class AppComponent { public obj: any = { "type1": ["A1", "A2", "A3","A4"], "type2": ["B1"], "type3": ["C1"], "type4": ["D1","D2"] }; constructor() { this.obj[Symbol.iterator] = () => { let i =0; return { next: () => { i++; return { done: i > 4?true:false, value: this.obj['type'+i] } } } }; } }
Я думаю, что объект.ключи-лучшее решение этой проблемы. Для всех, кто сталкивается с этим ответом и пытается выяснить, почему объект.ключи дает им ['0',' 1'] вместо ['key1', 'key2'], предостерегающий рассказ-остерегайтесь разницы между "ИЗ"и " в":
Я уже использовал объект.ключи, что-то похожее на это:
interface demo { key: string; value: string; } createDemo(mydemo: any): Array<demo> { const tempdemo: Array<demo> = []; // Caution: use "of" and not "in" for (const key of Object.keys(mydemo)) { tempdemo.push( { key: key, value: mydemo[key]} ); } return tempdemo; }впрочем, вместо
for (const key OF Object.keys(mydemo)) {Я нечаянно написал
for (const key IN Object.keys(mydemo)) {который "работал" отлично без каких-либо ошибок и возвращается
[{key: '0', value: undefined}, {key: '1', value: undefined}]это стоило мне около 2 часов гуглить и ругаться..
(хлопает себя по лбу)
вы должны сделать это так, как сейчас, я знаю, не очень эффективно, как вы не хотите, чтобы преобразовать объект, который вы получаете от firebase.
this.af.database.list('/data/' + this.base64Email).subscribe(years => { years.forEach(year => { var localYears = []; Object.keys(year).forEach(month => { localYears.push(year[month]) }); year.months = localYears; }) this.years = years; });
изменить тип демо в массив или повторите свой объект и нажмите на другой массив
public details =[]; Object.keys(demo).forEach(key => { this.details.push({"key":key,"value":demo[key]); });и из html:
<div *ngFor="obj of details"> <p>{{obj.key}}</p> <p>{{obj.value}}</p> <p></p> </div>
Comments