Búsqueda de sitios web

javascript - Cómo acceder al valor de un objeto JSON con una clave dinámica en typescript con angular


Quiero acceder al valor presente en un objeto JSON con targetPath configurable para la respuesta recibida.

A continuación está mi clase de componente que enlazará los datos presentes en la lista con el menú desplegable de autocompletado en el código HTML

La clave configurable es 'path', cuyo valor quiero proporcionar como una clave en un objeto JSON personalizado con la clave 'field'.

import { Component, ViewChild } from '@angular/core';
import { MenuItem } from 'primeng/api';
import { SelectItem } from 'primeng/api';
import { SelectItemGroup } from 'primeng/api';
import { FilterService } from 'primeng/api';
import { AutoComplete } from 'primeng/autocomplete';
import { CountryService } from './countryservice';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  providers: [CountryService, FilterService]
})
export class AppComponent {
  userDetails: any[];

  selectedUserDetails: any[];

  selectedValue: any;

  selectedUserDetail: any;

  path: string = 'contactMedium[0].characteristic.emailAddress';

  testVal: string;

  constructor() {}

  ngOnInit() {
    this.userDetails = [
      {
        id: 'cont-609',
        contactMedium: [
          {
            characteristic: {
              emailAddress: '[email '
            }
          }
        ]
      },
      {
        id: 'cont-610',
        contactMedium: [
          {
            characteristic: {
              emailAddress: '[email '
            }
          }
        ]
      },
      {
        id: 'cont-611',
        contactMedium: [
          {
            characteristic: {
              emailAddress: '[email '
            }
          }
        ]
      },
      {
        id: 'cont-612',
        contactMedium: [
          {
            characteristic: {
              emailAddress: '[email '
            }
          }
        ]
      },
      {
        id: 'cont-614',
        contactMedium: [
          {
            characteristic: {
              emailAddress: '[email '
            }
          }
        ]
      }
    ];
  }

  filterUserDetails(event) {
    const filteredNew: any[] = [];
    this.getUserDetails().then(response => {
      for (let resp of response) {
        this.testVal = resp[this.path];
        filteredNew.push({
          id: resp.id,
          field: resp[this.path]
        });
      }
    });

    this.selectedUserDetails = filteredNew;
  }

  getUserDetails(): Promise<any[]> {
    return Promise.resolve(this.userDetails);
  }

  chooseItem(event) {
    this.selectedUserDetail =
      event.contactMedium[0].characteristic.emailAddress;
  }
}

A partir de la respuesta recibida del método getUserDetails(), estoy construyendo un arreglo personalizado de objetos JSON con los campos 'id' y 'field', la clave para id es conocida, que en sí misma es un 'id', pero la clave para field es configurable, que en mi caso es path.

Pero parece que la lógica anterior donde se accede a la clave no está funcionando como se esperaba, es decir, no estoy obteniendo el valor para

  filterUserDetails(event) {
    const filteredNew: any[] = [];
    this.getUserDetails().then(response => {
      for (let resp of response) {
        this.testVal = resp[this.path];
        filteredNew.push({
          id: resp.id,
          field: resp[this.path]
        });
      }
    });

    this.selectedUserDetails = filteredNew;
  }

A continuación está mi código HTML

<h5>Dropdown Testing</h5>
<p>selectedUserDetail : {{selectedUserDetail}}</p>
<p>TestVal : {{testVal}}</p>
<p-autoComplete [(ngModel)]="selectedUserDetail" [suggestions]="selectedUserDetails"
  (completeMethod)="filterUserDetails($event)" [dropdown]="true" field="field">
  <ng-template let-userDetails pTemplate=" item">
    <div>{{userDetails.field}}</div>
  </ng-template>
</p-autoComplete>

Si cambio el uso de la asignación como se muestra a continuación, todo funciona bien

campo: resp.contactMedium[0].characteristic.emailAddress

El enlace de mi código está aquí: https://stackblitz.com/edit/primeng-autocomplete-demo-dyihrs?file=src%2Fapp%2Fapp.component.html

La expectativa aquí es asignar el valor de la clave: contactMedium[0].characteristic.emailAddress recibido de getUserDetails() al objeto JSON personalizado que se está construyendo en filterUserDetails() a la clave 'field'.

Respuesta #1

Puedes usar una variable que tenga la clave dinámica

var obj = {
  ...
}
var key = ...;

obj[key] = somevalue;

o para obtener el valor

var somevalue = obj[key];

Respuesta #2

Debes tener en cuenta que tu campo puede ser muy complejo, pero en el caso que mencionaste, se puede resolver con esto:

resolveField(data: any, field: string): any {
  if (data && field) {
    let fields: string[] = field.split('.');
    let value = data;
    for(let i = 0, len = fields.length; i < len; ++i) {
      if (value == null) {
        return null;
      } else {
        const pos: number = fields[i].match(/\d+/g)?.[0];
        if(pos != null) {
          const property = fields[i].match(/^\w+/g);
          value = value[property][pos];
        } else {
          value = value[fields[i]];
        }
      }
    }
    return value;
  } else {
    return null;
  }
}

Puedes usar la función resolveField como parte de tu lógica. Puedes modificarla, como quieras o se requiera, por ejemplo: aquí se consideran solo las letras como parte de los nombres de las propiedades.

Aquí está la solución para tu código.