angular - such - clave de acceso y valor del objeto usando*ngFor
ngfor only supports binding to iterables such as arrays (17)
Actualizar
En 6.1.0- beta.1 se introdujo KeyValuePipe https://github.com/angular/angular/pull/24319
<div *ngFor="let item of {''b'': 1, ''a'': 1} | keyvalue">
{{ item.key }} - {{ item.value }}
</div>
Versión previa
Otro enfoque es crear la directiva
NgForIn
que se utilizará como:
<div *ngFor="let key in obj">
<b>{{ key }}</b>: {{ obj[key] }}
</div>
ngforin.directive.ts
@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);
}
}
}
Estoy un poco confundido acerca de cómo obtener la
key
y el
value
de un objeto en angular2 mientras uso
*ngFor
para iterar sobre el objeto.
Sé que en angular 1.x hay una sintaxis como
ng-repeat="(key, value) in demo"
pero no sé cómo hacer lo mismo en angular2. He intentado algo similar, sin éxito:
<ul>
<li *ngFor=''#key of demo''>{{key}}</li>
</ul>
demo = {
''key1'': [{''key11'':''value11''}, {''key12'':''value12''}],
''key2'': [{''key21'':''value21''}, {''key22'':''value22''}],
}
Aquí hay un plnkr con mi intento: http://plnkr.co/edit/mIj619FncOpfdwrR0KeG?p=preview
¿Cómo puedo obtener
key2
y
key2
dinámicamente usando
*ngFor
?
Después de buscar mucho, encontré la idea de usar tuberías, pero no sé cómo hacerlo.
¿Hay alguna tubería incorporada para hacer lo mismo en angular2?
Índice de uso:
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;
}
Uso:
for (const key OF Object.keys(mydemo)) {
@ Martin tuvo una importante objeción a la respuesta aceptada debido a que la tubería crea una nueva colección en cada detección de cambio. En su lugar, crearía un HtmlService que proporciona una gama de funciones de utilidad que la vista puede usar de la siguiente manera:
@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...
}
Al igual que en la
última versión de Angular (v6.1.0)
, Angular Team ha agregado una nueva tubería incorporada para el mismo nombre que la tubería de valor
keyvalue
para ayudarlo a iterar a través de objetos, mapas y matrices, en el módulo
common
del paquete angular.
Por ejemplo -
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;
}
}
Ejemplo de trabajo bifurcado
échale un vistazo aquí para obtener más información útil:
- https://github.com/angular/angular/blob/master/CHANGELOG.md#features-3
- https://github.com/angular/angular/commit/2b49bf7
Si está utilizando Angular v5 o inferior o desea lograr el uso de tubería, siga esta respuesta
- clave de acceso y valor del objeto usando ngfor
Aquí está la solución simple
Puede usar iteradores de mecanografía para esto
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]
}
}
}
};
}
}
Creo que Object.keys es la mejor solución para este problema. Para cualquiera que encuentre esta respuesta y esté tratando de descubrir por qué Object.keys les está dando [''0'', ''1''] en lugar de [''clave1'', ''clave2''], una historia de advertencia: tenga cuidado con la diferencia entre " de "y" en ":
Ya estaba usando Object.keys, algo similar a esto:
for (const key IN Object.keys(mydemo)) {
Sin embargo, en lugar de
[{key: ''0'', value: undefined}, {key: ''1'', value: undefined}]
Inadvertidamente escribí
myObj[''key'']
que "funcionó" perfectamente bien sin ningún error y regresó
<div *ngFor="let value of Objects; index as key">
Eso me costó unas 2 horas buscando en Google y maldiciendo ...
(golpea la frente)
Desde Angular 6.1 puede usar la tubería keyvalue :
<div *ngFor="let item of testObject | keyvalue">
Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>
Pero tiene el inconveniente de que ordena la lista resultante por el valor clave. Si necesitas algo neutral:
@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;
}
}
No olvide especificar el atributo pure: false pipe. En este caso, la tubería se invoca en cada ciclo de detección de cambio, incluso si la referencia de entrada no ha cambiado (así es el caso cuando agrega propiedades a un objeto).
Elaboración de la respuesta de @ Thierry con ejemplo.
No hay una tubería o método incorporado para obtener la
key and value
del bucle * ngFor.
entonces tenemos que crear una tubería personalizada para lo mismo.
Como dijo Thierry, aquí está la respuesta con el código.
** La clase pipe implementa el método de transformación de la interfaz PipeTransform que toma un valor de entrada y una matriz opcional de cadenas de parámetros y devuelve el valor transformado.
** El método de transformación es esencial para una tubería. La interfaz PipeTransform define ese método y guía tanto las herramientas como el compilador. Es opcional; Angular busca y ejecuta el método de transformación independientemente. para más información sobre tuberías consulte aquí
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;
}
}
y la parte HTML es:
<ul>
<li *ngFor=''#key of demo | keys''>
Key: {{key.key}}, value: {{key.value}}
</li>
</ul>
Working Plnkr http://plnkr.co/edit/50LlK0k6OnMnkc2kNHM2?p=preview
actualizar a RC
según lo sugerido por user6123723 (gracias) en el comentario aquí está la actualización.
<ul>
<li *ngFor=''let key of demo | keys''>
Key: {{key.key}}, value: {{key.value}}
</li>
</ul>
Gracias por la tubería, pero tuve que hacer algunos cambios antes de poder usarla en angular 2 RC5. Cambió la línea de importación de Pipe y también agregó el tipo de any a la inicialización de la matriz de claves.
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;
}
}
Hay una biblioteca realmente agradable que hace esto entre otras buenas tuberías. Se llama ngx-pipes .
Por ejemplo, la tubería de claves devuelve las claves de un objeto, y la tubería de valores devuelve los valores de un objeto:
tubo de llaves
<div *ngFor="let key of {foo: 1, bar: 2} | keys">{{key}}</div>
<!-- Output: ''foo'' and ''bar -->
tubería de valores
<div *ngFor="let value of {foo: 1, bar: 2} | values">{{value}}</div>
<!-- Output: 1 and 2 -->
No es necesario crear su propia tubería personalizada :)
Ninguna de las respuestas aquí funcionó para mí fuera de la caja, esto es lo que funcionó para mí:
Crear
pipes/keys.ts
con contenido:
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;
}
}
Agregue a
app.module.ts
(su módulo principal):
import { KeysPipe } from ''./pipes/keys'';
y luego agregue al conjunto de declaraciones de su módulo algo como esto:
@NgModule({
declarations: [
KeysPipe
]
})
export class AppModule {}
Luego, en su plantilla de vista, puede usar algo como esto:
<option *ngFor="let entry of (myData | keys)" value="{{ entry.key }}">{{ entry.value }}</option>
Aquí hay una buena referencia que encontré si quieres leer más.
Puede crear una tubería personalizada para devolver la lista de claves para cada elemento. Algo como eso:
<tr *ngFor="let c of content">
<td *ngFor="let key of c | keys">{{key}}: {{c[key]}}</td>
</tr>
y úsalo así:
@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;
}
}
Editar
También puede devolver una entrada que contenga clave y valor:
<span *ngFor="let entry of content | keys">
Key: {{entry.key}}, value: {{entry.value}}
</span>
y úsalo así:
<div *ngFor="let item of testObject | keyvalue">
Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</div>
Si ya está usando Lodash, puede hacer este enfoque simple que incluye clave y valor:
<ul>
<li *ngFor=''let key of _.keys(demo)''>{{key}}: {{demo[key]}}</li>
</ul>
En el archivo mecanografiado, incluya:
import * as _ from ''lodash'';
y en el componente exportado, incluya:
_: any = _;
Tenga
Object.keys
accesibles en la plantilla y
*ngFor
en
*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(){}
}
Tienes que hacerlo así por ahora, sé que no es muy eficiente, ya que no quieres convertir el objeto que recibes de 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;
});
cambiar el tipo de demostración a matriz o iterar sobre su objeto y pasar a otra matriz
public details =[];
Object.keys(demo).forEach(key => {
this.details.push({"key":key,"value":demo[key]);
});
y de html:
<div *ngFor="obj of details">
<p>{{obj.key}}</p>
<p>{{obj.value}}</p>
<p></p>
</div>
puede obtener la clave del objeto dinámico al intentar esto
{{key}} -> {{value}}