0

I am trying to display json data on a website using view engine (ejs) but I am facing following error Cannot read property 'firstname' of undefined this is my program

node.js

io.readEmp().then(function(data){
    res.render('Dashboard',{data:data});
}).catch(function(err){console.log(err.message);});

index.ejs

<ul class="list-group list-group-flush">
    <% for(var key in data){%>
        <li class="list-group-item"><%= data.key.firstname %></li><%}%>
</ul>

jsonfile

{
    "id01":{"firstname":"abc","lastname":"xy"},
    "id02":{"firstname":"pqr","lastname":"xy"}
}

error

Cannot read property 'firstname' of undefined
Dhruvin modi
  • 613
  • 1
  • 8
  • 13

3 Answers3

0

Like I was trying to say earlier. Turning an Object into an array is better. Because if you are using a hashMap structure these can be deeply nested. Example being an object like the below

  {"id01":{
  "address": {
    "street": "123 Main St",
    "city": "San Francisco",
    "state": "CA"
  },
  "dogs": {
    "spot": {
      "type": "German Shepherd",
      "foods": {
        "soft" : {
          "Purina": "Cat Chow"
        },
        "unconventional": {
          "vomit": "Vomit",
          "squirrels" : "Squirrels"
        }
      }
    },
    "spike": {
      "type": "Doberman"
    }
  }
}}

will result in something looking like this using the method suggested.

<ul class="list-group list-group-flush">
    <% for(var key in data){%>
        <li class="list-group-item"><%= data[key].firstname %></li>
        <li class="list-group-item"><%= data[key].address.street %></li>
        <li class="list-group-item"><%= data[key].address.city %></li>
        <li class="list-group-item"><%= data[key].address.state %></li>
        <li>
          <ul>
            <% for(var dogKey in data[key].dogs){%>
                <li class="list-group-item"><%= data[key].dogs[dogKey].type %></li>
                <li>
                  <ul>
                    <% for(var dogFoodKey in data[key].dogs[dogKey].foods){%>
                        <li class="list-group-item"><%= data[key].dogs[dogKey].foods[dogFoodKey]. %></li>
                    <%}%>
                  </ul>
                </li>
            <%}%>
          </ul>
        </li>
    <%}%>
</ul>

It is terribly untidy. It needs a serious refactoring. As a practice you should not repeat yourself.

Instead, I would suggest the following which re-writes the object into an array as it receives it.

<ul class="list-group list-group-flush">
    <% for(var person in Object.values(data)){%>
        <li class="list-group-item"><%= person.firstname %></li>
        <li class="list-group-item"><%= person.address.street %></li>
        <li class="list-group-item"><%= person.address.city %></li>
        <li class="list-group-item"><%= person.address.state %></li>
        <li>
          <ul>
            <% for(var dog in person.dogs){%>
                <li class="list-group-item"><%= dog.type %></li>
                <li>
                  <ul>
                    <% for(var food of Object.values(dog.foods)){%>
                        <li class="list-group-item"><%= food %></li>
                    <%}%>
                  </ul>
                </li>
            <%}%>
          </ul>
        </li>
    <%}%>
</ul>
  • yup error is gone but the values(i.e abc & pqr) are not displaying on site. – Dhruvin modi Jan 02 '19 at 18:51
  • He should not have to transform his JSON data to make this work. – Paul Jan 02 '19 at 19:03
  • nope, it is still in object form. let me try...and I also want to know the reason behind. – Dhruvin modi Jan 02 '19 at 19:05
  • You should as a practice, use arrays either at runtime or compile and search because it results in better code when iterating. Please check out my updated post that goes into more detail as to why you should have this going through as an array either in the JSON file or when using your template engine. – None of your Beez Wax Jan 02 '19 at 20:00
0

If you have data as an object like you display then 'key' will be the item key and you need to use the key access notation for an object thusly:

<ul class="list-group list-group-flush">
    <% for(var key in data){%>
        <li class="list-group-item"><%= data[key].firstname %></li><%}%>
</ul>

'key' for the first item will be "id01", so this is equivalent (on the first pass) for saying data.id01.firstname.

Paul
  • 35,689
  • 11
  • 93
  • 122
  • Please, reread my solution. I have given a more detailed example showing what I meant about this not being the proper way of handling a hashmap example – None of your Beez Wax Jan 02 '19 at 19:51
  • @Moosecouture that's a matter of opinion; in cases where the OP is generating their own data the risk you present is extremely small to nonexistent, and there can be equally good reasons for maintaining the object structure rather than switching it to an array. – Paul Jan 02 '19 at 20:28
  • Hence, why I presented a maintainable DRY code that does not look like this `data[key].firstname` and instead makes it look DRY `person.firstname` – None of your Beez Wax Jan 02 '19 at 20:30
  • Coding is all opinion. Writing something like this will likely make it very hard to get hired in a modern company though. Hence, Object.values or Object.entities if you need the ID of the hashmap for a link. Just be careful out there. Hashmaps are a great way of preventing duplicates but they have their limits. Iteration and size are two major reasons for not being in a practice of doing data[key].some[innerKey].somemore[inneInnerKey] – None of your Beez Wax Jan 02 '19 at 21:07
-1

you need to make few changes as below in your index.ejs file

<ul class="list-group list-group-flush">
<% for(var key in data){%>
 <li class="list-group-item">
      <%= key.firstname %>
</li>
<%}%> 
</ul>

Note: you have to use key.firstname and not data.key.firstname