@RachChen不在模板中:common: NgFor has been removed as it was deprecated since v4. Use NgForOf instead. This does not impact the use of*ngFor in your templates.(jaxenter.com/road-to-angular-5-133253.html)
@martin仅使用Object.keys()来检索管道中的键时,实际上会造成这种性能损失吗?
您应该使用keys.unshift(...)而不是keys.push(...),这将保留循环中键的顺序。
更新
在6.1.0-beta.1中引入了KeyValuePipe https://github.com/angular/angular/pull/24319
1
| {{ item.key }} - {{ item.value }} |
柱塞示例
先前版本
另一种方法是创建NgForIn指令,该指令的用法如下:
1
| {{ key }}: {{ obj[key] }} |
柱塞示例
ngforin.directive.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @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;
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);
}
}
} |
在Angular 6.1中,您可以使用键值管道:
1
| Key: {{item.key}} and Value: {{item.value}} |
但是它不方便按键值对结果列表进行排序。
如果您需要中立的东西:
1 2 3 4 5 6 7 8 9 10 11 12
| @Pipe({ name: 'keyValueUnsorted', pure: false })
export class KeyValuePipe implements PipeTransform {
transform(input: any): any {
let keys = [];
for (let key in input) {
if (input.hasOwnProperty(key)) {
keys.push({ key: key, value: input[key]});
}
}
return keys;
}
} |
不要忘记指定pure:false管道属性。在这种情况下,即使输入引用未更改(在向对象添加属性时也是如此),管道在每个更改检测周期被调用。
-
已经在stackoverflow.com/a/51491848/5043867上共享了相同的答案
用示例详细说明@Thierry的答案。
没有从* ngFor循环获取key and value的内置管道或方法。所以我们必须为它创建自定义管道。正如thierry所说的,这就是代码的答案。
**管道类实现了PipeTransform接口的transform方法,该方法接受输入值和可选的参数字符串数组,并返回转换后的值。
**变换方法对于管道至关重要。 PipeTransform接口定义该方法,并指导工具和编译器。它是可选的; Angular无论如何都会寻找并执行transform方法。
有关管道的更多信息,请参阅此处
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 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部分是:
1 2 3 4 5 6 7 8 9
| <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所建议(感谢)在评论中此处为更新。
1 2 3 4 5 6 7 8 9
| <ul>
<li *ngFor='let key of demo | keys'>
Key: {{key.key}}, value: {{key.value}}
</li>
</ul> |
-
这需要更新:这里不赞成在表达式内部得到"#"的警告。用" let"代替! ("
->
- ] * ngFor = demo的键|键>键:{{key.key}},值:{{key.value}}
"):myComponent @ 56:6
-
不知道这是否是新的,但可以从docs中引用:>我们必须将管道包含在AppModule的声明数组中。
@Marton对接受的答案有重要的反对意见,理由是管道在每次更改检测时都会创建一个新的集合。相反,我将创建一个HtmlService,它提供一系列实用程序功能,该视图可以按如下方式使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Component({
selector: 'app-myview',
template: `{{i + ' : ' + items[i]}}`
})
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...
} |
-
以及比* ngFor中的Object.keys(...)更好?
-
因为它将抛出:TypeError: Cannot read property keys of undefined。模板似乎不支持它。
-
这可以很好地作为解决方案,并且可以避免上述性能问题。 stackoverflow.com/questions/35534959/
-
你好,这个b不能在template选项中使用,而是在模板实际的html代码中使用吗?谢谢
如果您已经在使用Lodash,则可以执行以下简单方法,其中包括键和值:
1 2 3 4 5 6 7
| <ul>
<li *ngFor='let key of _.keys(demo)'>{{key}}: {{demo[key]}}
</li>
</ul> |
在打字稿文件中,包括:
1
| import * as _ from 'lodash'; |
在导出的组件中,包括:
-
抱歉,但无需使用类似Lodash的额外库来进行此类操作。无论如何,总是欢迎新方法:)
感谢管道,但我必须进行一些更改才能在angular 2 RC5中使用它。更改了Pipe导入行,并在key数组初始化中添加了any的类型。
1 2 3 4 5 6 7 8 9 10 11 12
| 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:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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(您的主模块):
1
| import { KeysPipe } from './pipes/keys'; |
然后将如下所示的内容添加到模块声明数组中:
1 2 3 4 5 6
| @NgModule({
declarations: [
KeysPipe
]
})
export class AppModule {} |
然后,在您的视图模板中,您可以使用如下代码:
1
| <option *ngFor="let entry of (myData | keys)" value="{{ entry.key }}">{{ entry.value }}</option> |
如果您想了解更多信息,这是一个很好的参考。
-
我可以知道您提供的答案和上面提供的其他答案(仅使用管道)有何区别?好像和上面一样
-
当然1.上面的示例使用* ngFor ="#entry"代替* ngFor =" let entry of",并且我的编译器不接受#entry语法,引用也不使用#。"让(myData |键)进入"似乎是一个更好的解决方案。 2.我的编译器没有验证示例管道类,因为它缺少显式数据类型,因此我添加了它。 3.上面的示例没有显示如何将Pipe集成到我的答案所做的项目中,您需要将其导入到主模块中。
-
哈哈,不错,因为当时答案是包括#等的语法。顺便说一句,您的答案无疑也是正确的
有一个真正的漂亮库在其他漂亮的管道中执行此操作。这就是ngx-pipes。
例如,键管道返回对象的键,而值管道返回对象的值:
钥匙管
1 2
| {{key}}
<!-- Output: 'foo' and 'bar --> |
价值观管道
1 2
| {{value}}
<!-- Output: 1 and 2 --> |
无需创建自己的自定义管道:)
-
一个很好的选择,但是如果我们可以使用像管道这样的简单代码来做到这一点,那就是为什么要使用外部库来实现简单的代码和平
-
嗯...不过是烟斗吗?导入库时,它仅在package.json中一行,而在模块中另两行。另一方面,自定义管道需要一个单独的文件,其中包含大约10-20行代码以及模块中的导入行。我们发现在我们的项目中使用ngx-pipes非常容易。我们为什么要重新发明轮子? :)
-
是的,毫无疑问,实际上它是一种观点,您可以在这两者之间选择,没有一个是错误的方法。
-
别忘了,如果您编写自定义管道,则还必须测试该自定义管道。因此,这就是10-20行管道代码,然后大概20-40行测试代码来测试管道。
使用索引:
用法:
-
这对我来说是新事物,更好。如果您可以在示例中添加示例和答案:)您还可以为我提供相同的任何文档吗?
这是简单的解决方案
您可以为此使用打字稿迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import {Component} from 'angular2/core';
declare var Symbol;
@Component({
selector: 'my-app',
template:`
<h4>Iterating an Object using Typescript Symbol</h4>
Object is : <p>
{{obj | json}}
</p>
============================
Iterated object params are:
{{o}}
`
})
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]
}
}
}
};
}
} |
将演示类型更改为数组
或遍历对象并推送到另一个数组
1 2 3 4
| public details =[];
Object.keys(demo).forEach(key => {
this.details.push({"key":key,"value":demo[key]);
}); |
和从HTML:
1 2 3 4 5 6 7 8 9
| <p>
{{obj.key}}
</p>
<p>
{{obj.value}}
</p>
<p>
</p> |
您可以通过尝试这样做来获得动态对象的密钥
我认为Object.keys是解决此问题的最佳方法。对于遇到此问题并试图找出Object.keys为什么要给它们['0','1']而不是['key1','key2']的人,请注意一个故事-当心"的"和"中:
我已经在使用Object.keys,类似于以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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;
} |
但是,代替
1
| for (const key OF Object.keys(mydemo)) { |
我无意间写了
1
| for (const key IN Object.keys(mydemo)) { |
哪个"工作"完美无误,然后返回
1
| [{key: '0', value: undefined}, {key: '1', value: undefined}] |
这花了我大约2个小时的时间进行谷歌搜索和诅咒。
(拍打额头)
您现在必须这样做,我知道效率不是很高,因为您不想转换从firebase收到的对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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;
}); |