1
votes

I'm dealing with a strange problem in Vue. I'm trying to display a list of employees in the table. Employees are provided by a REST service and response looks exactly like this (shown below is one item from the paginatedList):

{
  "id": 10a,
  "code": 0000,
  "firstName": "John",
  "lastName": "Doe",
  "level": "WORKER",
  "specialization": {
    "id": 20,
    "name": "Default",
    "taem": {
      "id": 2,
      "name": "Builders",
      "system": false,
      "teamLead": null,
      "specializationDtos": null,
      "categoryDtos": null
    }
  },
  "team": {
    "id": 2,
    "name": "Builders",
    "system": false,
    "teamLead": null,
    "specializationDtos": null,
    "categoryDtos": null
  },
  "coachDto": null,
  "roles": [
    "DL"
  ]
}

In Vue, I'm using Vuex actions to preprocess raw data and return paginated list of employees. Then I'm trying to print it in the table using v-for like this:

<tr v-for="item in paginatedList" :key="item.id"
  v-on:click="selectRow(item)"
  v-bind:class="{selectedRow: selectedItem === item}"
>
  <td>{{item.id}}</td>
  <td>{{item.name}}</td>
  <td>{{item.team.name}}</td>
</tr>

And this is where it fails (kind of). Even though the table is displayed with no employee missing the team name, I'm getting warning from Vue:

[Vue warn]: Error in render: "TypeError: Cannot read property 'name' of undefined"

After clicking on the line of code, which causes the warning, it points to the place where I'm trying to render {{item.team.name}}

My first thought was that the employee with missing team was simply not displayed. In order to check it I came up with following workaround:

<td>{{getTeamName(item.team)}}</td>

And the method:

getTeamName(team) {
  return (team ? team.name : 'FAILED');
}

Warning/error disappears but there is no employee with FAILED team. What exactly is the problem with this? Is it possible to display properties of nested object like that or should I avoid it?

2
The problem is not with the nested object but somewhere else. Your loop looks Ok and example data looks fine so the issue must lie in the data you're getting back from the API / the way you're setting that data in the state. Can you post an exact response from your API call? Also, post the content of paginatedList.webnoob
edited, added one item from paginatedList (names obfuscated)mat.hudak
Nowhere in your paginated data does teamDto exist. When you access item.{something} it accesses the properties on that object so the prop needs to exist.webnoob
Also, you have a typo in the data: taem in specialization.webnoob
Ups, sorry, it happens on multiple pages, I used different data in code than they are in response. So, to explain employee => team, trainings => teamDtomat.hudak

2 Answers

4
votes

This can happen when the object your iterating doesn't yet have the data you're expecting but by the time you come to debug it, it does. I find this most often when using data which you're getting from a promise. With that in mind, just add a check to make sure that your data has loaded properly, in your case, this should suffice:

<tr v-for="item in paginatedList" :key="item.id"
  v-on:click="selectRow(item)"
  v-bind:class="{selectedRow: selectedItem === item}"
>
  <div v-if="item.team">
    <td>{{item.id}}</td>
    <td>{{item.name}}</td>
    <td>{{item.team.name}}</td>
  </div>
</tr>

I generally have a dataLoaded prop on my component which is initialised as false but set to true once I've finished messing with my data to avoid issues like this. I'd then check v-if="dataLoaded" around my whole component.

0
votes

It looks as though you have mis-spelled team in your object:

 "taem": {
      "id": 2,
      "name": "Builders",
      "system": false,
      "teamLead": null,
      "specializationDtos": null,
      "categoryDtos": null
    }

which I guess is why it can't render name of undefined.