18

I have a simple object literal which is address as shown here

address: {
    country: String,
    state: String,
    city: String,
    zip: String,
    street: String
}

and its inside an object which i'm passing with express.js render function.

in my template page i'm trying to for loop inside this object as shown:

<% for (var prop in artist.address ) { %>
  <%- artist.address[prop] %>
<% } %>

which output the data but includes the ejs functions as well like so:

function () { return this.get(path); } function () { return this.get(path); } yafo 09988 jerusalem israel israeli [object Object] undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined [object Object] [object Object] function () { var self = this , hookArgs // arguments eventually passed to the hook - are mutable , lastArg = arguments[arguments.length-1] , pres = this._pres[name] , posts = this._posts[name] , _total = pres.length , _current = -1 , _asyncsLeft = proto[name].numAsyncPres , _next = function () { if (arguments[0] instanceof Error) { return handleError(arguments[0]); } var _args = Array.prototype.slice.call(arguments) , currPre , preArgs; if (_args.length && !(arguments[0] == null && typeof lastArg === 

so how do i need to iterate my object?

Boaz Hoch
  • 1,219
  • 1
  • 12
  • 36
  • good answer here: http://stackoverflow.com/questions/14379274/javascript-iterate-object – snozza Aug 01 '15 at 18:07
  • Is `address` actually a `mongoose.Schema` and `artist.address` is a `mongoose.Document`? – mscdex Aug 03 '15 at 13:37
  • no, the artist is a mongoose.schema var artistSchema = mongoose.Schema({ address: { country: String, state: String, city: String, zip: String, street: String }, .... – Boaz Hoch Aug 03 '15 at 17:16

3 Answers3

11

You're seeing all of the inherited properties in addition to the "own" properties you've added on top.

There's two ways to solve this. One is to use hasOwnProperty() to ensure you don't see inherited properties:

<% for (var prop in artist.address) {
     if (Object.prototype.hasOwnProperty.call(artist.address, prop)) { %>
       <%- artist.address[prop] %>
<%   }
   } %>

Or use Object.keys() which returns an array of only non-inherited properties and iterate over that:

<% Object.keys(artist.address).forEach(function(prop) { %>
  <%- artist.address[prop] %>
<% }); %>

Since this is mongoose related, you may also try iterating over artist.address.toObject() (using the public API) or artist.address._doc (using a private API) or perhaps up a level on the artist object.

mscdex
  • 104,356
  • 15
  • 192
  • 153
  • still doing : <% Object.keys(artist.address).forEach(function(prop) { %> <%- artist.address[prop] %> <% }); %> is returning: function () { return this.get(path); } function () { return this.get(path); } yafo 09988 – Boaz Hoch Aug 03 '15 at 05:26
  • What are the names of the unexpected properties? – mscdex Aug 03 '15 at 13:32
10

using plain JS you can use Object.keys

var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']

In your example

var artist = { address: { city: 'Tel Aviv' } };
Object.keys(artist.address).forEach(function(key){
  <%- artist.address[city] %> //key will city the output will be 'Tev Aviv' 
});

Another cool way is to use lodash: lodash forEach

    _([1, 2]).forEach(function(n) {
  console.log(n);
}).value();
Doron Segal
  • 2,242
  • 23
  • 22
  • 18
    This answers how to iterate in Javascript, OPs title question was how to iterate in with EJS. This answer is misleading for those brought here looking for an answer to question in title. – Cleanshooter Apr 03 '17 at 14:06
  • This is too much clearer answer – mercury Jul 23 '22 at 20:33
4

OK so i dived into it here is an explanation, i had an object:

address : {
  country: String,
  state: String,
  city: String,
  zip: String,
  street: String
}

i needed to display only those properties and not inherited once so i iterate over the object and got its own properties:

<% Object.keys(artist.address).forEach(function(prop) { %>
   // ["country" , "state" , "city" etc ]
  <%- artist.address[prop] %> // so artist.address.state logs "New York City"
<% }); %>

but the problem was that my artist.address object had two more properties: each one holds a function with a return.

function () { return this.get(path); } function () { return this.get(path); }

so i checked for properties that holds a string like so:

<% Object.keys(artist.address).forEach(function(prop) {
  if( typeof artist.address[prop] == "string" ) { %>
    <%- artist.address[prop] %>
  <% } %>
<% }); %> 
Boaz Hoch
  • 1,219
  • 1
  • 12
  • 36
  • you need to figure out when are you want to use ejs client or server. if you using it on the server side and lets say its express: the return object should look like this: controller: return res.render('template/something.ejs', { _: require('lodash'), artist: artistDocument }); view template <% _.(artist.address).forEach(function(prop){ %> <%- artist.address[prop] %> <% }); %> client side just use cdn service to get lodash – Doron Segal Aug 03 '15 at 22:14