Angular-TypeError:无法读取未定义的属性“ 0”

时间:2019-11-21 21:52:38

标签: javascript html angular typescript

我有一个从api返回的json对象,这是一个示例。

{
  "availablePermissions": [
    {
      "id": 25,
      "name": "Dashboard Access",
      "systemName": "DashboardAccess"
    }, {
      "id": 32,
      "name": "Claims Access",
      "systemName": "ClaimsAccess"
    }, {
      "id": 34,
      "name": "Purchasing Reports Access",
      "systemName": "PurchasingReportsAccess"
    }
  ],
  "availableApplicationRoles": [
    {
      "id": "6a8d97b8-7fd5-485c-8eff-5869232b7f26",
      "roleName": "Billing",
      "systemName": null
    }, {
      "id": "fbb6c213-2b19-4eec-891f-0552e3b14b5b",
      "roleName": "Power User",
      "systemName": null
    }
  ],
  "allowed": {
    "dashboardAccess": {
      "144ca9cc-9d56-4cd0-b9b2-c097d606d36e": false,
      "fbb6c213-2b19-4eec-891f-0552e3b14b5b": true
    },
    "claimsAccess": {
        "144ca9cc-9d56-4cd0-b9b2-c097d606d36e": false,
        "fbb6c213-2b19-4eec-891f-0552e3b14b5b": true
    },
    "purchasingReportsAccess": {
      "144ca9cc-9d56-4cd0-b9b2-c097d606d36e": false,
      "fbb6c213-2b19-4eec-891f-0552e3b14b5b": true
    }
  },
  "pager": {
    "pageIndex": 0,
    "pageSize": 10,
    "totalCount": 3,
    "totalPages": 1,
    "hasPreviousPage": false,
    "hasNextPage": false
  },
  "success": true,
  "message": null
}

现在在ngOnInit内部的组件中,我有将其绑定到名为acl的属性的代码,这是代码。

var dummyPermission = {
  id: "0",
  roleName:"Permission",
  systemName:null
}

var self = this;                

this.aclData.loadACL(dataTablesParameters, pageInfo)
  .subscribe(data => {
    if (data.success) {
      self.pluginService.lengthMenuAngularDataTable("#ACLTable", dataTablesParameters.length);
      self.acl = data;
      self.acl.availableApplicationRoles.unshift(dummyPermission);
      callback({
        recordsTotal: self.acl.pager.totalCount,
        recordsFiltered: self.acl.pager.totalCount,
        data: []
      });
      console.log("success load acl table");
      self.pluginService.witzThemeLoader(false);
      self.pluginService.datePicker();
    } else {
      self.pluginService.notificationPopup(null, "danger");
      self.pluginService.witzThemeLoader(false);
      self.pluginService.datePicker();
      console.log("error");
    }
  });

现在在我的html中,我尝试将它们呈现在表中,所以这是引发错误的行的代码。

<tr *ngFor="let pr of acl.availablePermissions">
  <td>
    <span>{{pr.name}}</span>
  </td>
  <td *ngFor="let cr of acl.availableApplicationRoles" [hidden]="cr.id == '0'">
    <input 
      attr.data-role-id="{{cr.id}}"
      attr.data-permission-name="{{pr.name}}"
      attr.data-system-name="{{pr.systemName}}"
      [checked]="acl.allowed[pr.systemName][cr.id]"
      class="allow allow_{{cr.id}}"
      type="checkbox" />
  </td>
</tr>

现在,当angular在获取数据后尝试呈现页面时,它似乎陷入了循环,并在控制台中每秒出现以下错误。

ERROR TypeError: Cannot read property '0' of undefined
    at Object.eval [as updateRenderer] (ACLComponent.html:85)
    at Object.debugUpdateRenderer [as updateRenderer] (core.js:14735)
    at checkAndUpdateView (core.js:13849)
    at callViewAction (core.js:14195)
    at execEmbeddedViewsAction (core.js:14153)
    at checkAndUpdateView (core.js:13845)
    at callViewAction (core.js:14195)
    at execEmbeddedViewsAction (core.js:14153)
    at checkAndUpdateView (core.js:13845)
    at callViewAction (core.js:14195)

现在第85行是我在上面提供的html。

 <td *ngFor="let cr of acl.availableApplicationRoles" [hidden]="cr.id == '0'">

我只是不知道出了什么问题,我查看了看起来都还不错的数据,我只是不知道为什么会这样,有人可以解释吗?

更新

经过一些调试后,我得以深入了解问题所在,就在这里。

在我共享的api响应数据对象中,有一个名为“允许”的对象,这是格式。

"allowed": {
"dashboardAccess": {
  "144ca9cc-9d56-4cd0-b9b2-c097d606d36e": false,
  "fbb6c213-2b19-4eec-891f-0552e3b14b5b": true
},
"claimsAccess": {
    "144ca9cc-9d56-4cd0-b9b2-c097d606d36e": false,
    "fbb6c213-2b19-4eec-891f-0552e3b14b5b": true
},
"purchasingReportsAccess": {
  "144ca9cc-9d56-4cd0-b9b2-c097d606d36e": false,
  "fbb6c213-2b19-4eec-891f-0552e3b14b5b": true
}

}

现在在html中,我有这行。

[checked]="acl.allowed[pr.systemName][cr.id]"

现在这需要从上面允许的对象中过滤出一个与systemName匹配的对象,然后过滤出一个与id匹配的对象,问题是,它不是数组,所以返回为undefined。

我不确定如何处理此类对象,我们将不胜感激。

3 个答案:

答案 0 :(得分:1)

您将td隐藏在cr.id =='0'

 <td *ngFor="let cr of acl.availableApplicationRoles" [hidden]="cr.id == '0'">

虽然它确实隐藏了,但仍会创建td元素,并且语句将执行,但您的操作却出现了错误:

 [checked]="acl.allowed[pr?.systemName][cr.id]"

因为在这种情况下cr.id为0:

[checked]="acl.allowed[pr?.systemName][0]"

您需要添加条件或对容器使用* ngIf。

答案 1 :(得分:0)

您可以使用optional chaining,这应该可以解决问题

<!-- notice the ? after acl and cr -->
<td *ngFor="let cr of acl?.availableApplicationRoles" [hidden]="cr?.id == '0'">

基本上,所发生的是angular试图在返回数据之前呈现列表,以使其保持循环并抛出错误。如果将?放在acl后,将跳过*ngFor,直到返回数据

编辑

您需要像这样在所有引用cr上使用?

<tr *ngFor="let pr of acl?.availablePermissions">
  <td>
    <span>{{pr?.name}}</span>
  </td>
  <td *ngFor="let cr of acl?.availableApplicationRoles" [hidden]="cr?.id == '0'">
    <input 
      attr.data-role-id="{{cr?.id}}"
      attr.data-permission-name="{{pr?.name}}"
      attr.data-system-name="{{pr?.systemName}}"
      [checked]="acl.allowed[pr?.systemName][cr.id]"
      class="allow allow_{{cr?.id}}"
      type="checkbox" />
  </td>
</tr>

答案 2 :(得分:-1)

好的,所以我终于可以使用以下代码使它正常工作。

<tr *ngFor="let pr of acl.availablePermissions let i = index">
<td scope="col">
    <span>{{pr.name}}</span>
</td>
<td *ngFor="let cb of aclPermissions[i].cb">
    <input attr.data-role-id="{{cb?.roleId}}"
           attr.data-permission-name="{{pr?.permissionName}}"
           attr.data-system-name="{{cb?.systemName}}"
           class="allow allow_{{cb?.roleId}}"
           type="checkbox"
           [checked]="cb?.isChecked" />
</td>

如您所见,我现在正在使用索引,这有助于我循环到对象数组。

感谢大家的帮助。