网站搜索

javascript - 如何在使用 Angular 的 TypeScript 中通过动态键访问 JSON 对象的值


我想访问 JSON 对象中存在的值,并且可以配置用于接收响应的 targetPath。

下面是我的组件类,它将把列表中的数据绑定到 HTML 代码中的自动完成下拉菜单

可配置的键是 'path',我想将其值作为自定义 JSON 对象键 '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;
  }
}

从方法 getUserDetails() 接收到的响应中,我正在构建一个自定义的 JSON 对象数组,包含字段 'id' 和 'field',id 的键是已知的,它本身就是一个 'id',但 field 的键是可配置的,在我的情况下是路径。

但是看起来上面的逻辑在访问键时没有按预期工作,即我没有得到值

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

下面是我的 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>

如果我像下面这样更改赋值的使用,一切都能正常工作

字段: resp.contactMedium[0].characteristic.emailAddress

我的代码链接在这里:https://stackblitz.com/edit/primeng-autocomplete-demo-dyihrs?file=src%2Fapp%2Fapp.component.html

这里的期望是将从 getUserDetails() 接收到的 key: contactMedium[0].characteristic.emailAddress 的值分配给在 filterUserDetails() 中构建的自定义 JSON 对象中的 'field' key。

答案#1

你可以使用一个具有动态键的变量

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

obj[key] = somevalue;

或者获取值

var somevalue = obj[key];

答案#2

你应该意识到你的领域可能非常复杂,但在你提到的情况下,可以通过以下方法解决:

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

您可以将 resolveField 函数作为逻辑的一部分使用。您可以根据需要或要求对其进行修改,例如:这里仅考虑字母作为属性名称的一部分。

这是你代码的解决方案。