-1

I am trying to iterate over an array that is part of an object.

Below is my user schema

var UserSchema = new Schema({
    username: String,
    email: String,
    password: String,
    company: String,
    contact: Number,
    country: String,
    isLoggedIn: Boolean,
    createdOn: { type: Date, default: Date.now },
    ads: [{ type: Schema.Types.ObjectId, ref: 'Ad' }],
    notification: {
        counter: {type: Number, default: 0},
        notidata: [{
            itemdate: { type: Date, default: Date.now },
            data: {
                heading: String,
                para: String
            },
            read: {type: Boolean, default: false}
        }]
    }
});

Let's say there are two notidata (array elements [0] and [1] in the database. I am trying to print all the notidata in this case two of it that are in the db.

Here is my view

 <div class="collapse navbar-collapse" id="navbarNavDropdown">
        <ul class="navbar-nav ml-auto">

            <li class="nav-item dropdown ">
                {{#each session.user.notification.notidata.[0]}}
                <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownMenuLink">
                    <a href="/users" class=" dropdown-item list-group-item-action flex-column align-items-start">
                        <div class="d-flex w-100 justify-content-between">
                            <h6 class="mb-1">{{data.heading}}</h6>
                        </div>
                        <p class="mb-1">{{data.para}}</p>
                    </a>
                    <div class="dropdown-divider"></div>
                    <a class="dropdown-item" href="#">View All</a>
                </div>
                {{/each}}
            </li> 

I am getting 1 drop down div that too empty. Firstly why is it printing one div since there are two elements in notification.notidata secondly, why is {{data.heading}} and {{data.para}} not getting printed. Thank a ton for the help! :)

mysamza
  • 387
  • 1
  • 6
  • 22

2 Answers2

0

Changing {{#each session.user.notification.notidata.[0]}} to this: {{#each session.user.notification.notidata}} worked on my sample web-application which I created to mock your web application set-up. For simplicity sake, I mocked out a session object: (from your UserSchema and example notidata array) and created a simple handlebar template containing a list using the data.properties you desire (para, and heading). The HTML in this case doesn't matter as it could be anything, the point is just to show that {{#each}} handlebarjs annotation worked as expected within your template. I suspect the problem is in your notification array and for one reason or another this array only contains 1 element. Pasted below is the relevant files of the sample web application, to see the whole sample project please look here: https://github.com/nathanwright1242/handlebarTest.

Index.html (notice the handlebarjs template hook: handlebarsTmpl)

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">    
  <title>Handlebarjs Templating example</title>
  <meta name="description" content="The HTML5 Herald">
  <meta name="author" content="SitePoint">

  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">
  <div id='handlebarHook'></div>
</head>

<body>

  <script id="handlebarsTmpl" type="text/template">
   <div>
        {{#each session.user.notification.notidata}}
        <ul class="list-group">
            <li class="list-group-item">{{data.heading}}</li>
            <li class="list-group-item">{{data.para}}</li>
       </ul>
       {{/each}}
   </div>
  </script>

  <!-- bootstrap4 dependencies -->
  <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js" integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh" crossorigin="anonymous"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script>
  <!-- backbonejs dependencies -->
  <script src='js/lib/underscore-min.js'></script>
  <script src='js/lib/backbone-min.js'></script>
  <!-- handlebarsjs -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.js"></script>
  <!-- normal app separation -->
  <script src='js/views/HandleBarView.js'></script>
  <script src='js/app.js'></script> 

</body>
</html>

HandleBarView.js (View that will populate the handlebar template with dynamic data from your session object)

var app = app || {}

app.HandleBarView = Backbone.View.extend({
    el: '#handlebarHook',
    template: $('#handlebarsTmpl').html(),
    initialize: function(notidata){
        this.notidata = notidata;
        this.render();
    },
    render: function(){
        let templateScript = Handlebars.compile(this.template);
        this.$el.html(templateScript( this.notidata ));
        return this;
    }
});

app.js (Entry point in the web app, passing in the session object: mocked the same as your schema and example data)

  var app = app || {};

$(function() {
let data = {
    session: {
        user: {}
    }
};
data.session.user = {
    'username': 'testuser',
    'email': 'test@gmail.com',
    'password': 'password',
    'company': 'myCompany',
    'contact': 1234,
    'country': 'United States',
    'isLoggedIn': true,
    'createdOn': '2018-09-27T22:59:41.655Z',
    'ads': [],
    'notification': {
        'counter': 1,
        'notidata': [ 
            { data: { heading: 'Welcome edited', para: 'MaujouharatMarketPlace welcomes you!' }, read: false, itemdate: '2018-09-27T22:59:41.655Z' }, 
            { data: { heading: 'This is second notification', para: 'yes man' }, read: false, itemdate: '2018-09-27T22:59:41.655Z' } 
        ] 
    }
};
    new app.HandleBarView(data);
});

Result: (Verification of code by viewing the project's index file)

result

Nathan
  • 7,853
  • 4
  • 27
  • 50
  • I have changed the code as per your suggestion, it is now printing but just the first element [0] even though there clearly are two elements in notidata. How to successfully iterate? – mysamza Sep 27 '18 at 22:34
  • Can you log this data structure: session.user.notification.notidata? This way we can verify that notidata has all the elements and can fix the mapping from the template view – Nathan Sep 27 '18 at 22:45
  • [ { data: { heading: 'Welcome edited', para: 'MaujouharatMarketPlace welcomes you!' }, read: false, itemdate: 2018-09-27T22:59:41.655Z }, { data: { heading: 'This is second notification', para: 'yes man' }, read: false, itemdate: 2018-09-27T22:59:41.655Z } ] – mysamza Sep 27 '18 at 22:59
  • @MesamAbbas try the edited answer out and see if that progresses you any further. The first #each should grab each row of the notidata: 1st Iteration:{"data":{"heading":"Welcome edited","para":"MaujouharatMarketPlace welcomes you!"},"read":false,"itemdate":"2018-09-27T22:59:41.655Z"} Then on the second iteration: {"data":{"heading":"This is second notification","para":"yes man"},"read":false,"itemdate":"2018-09-27T22:59:41.655Z"}. The nested #each should grab the data object for each row i.e. {"heading":"Welcome edited","para":"MaujouharatMarketPlace welcomes you!"} then the two properties – Nathan Sep 27 '18 at 23:48
  • Just tried. Nothing prints now. With previous suggestion of yours at least one element was getting printed now, nothing. – mysamza Sep 28 '18 at 10:08
  • I have posted my latest try as the answer here. – mysamza Sep 28 '18 at 15:49
0

I have tried this

 {{#each session.user.notification.notidata}}

                    <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownMenuLink">

                        <a href="/users" class=" dropdown-item list-group-item-action flex-column align-items-start">
                            <div class="d-flex w-100 justify-content-between">

                                <small>heading -> {{data.heading}}</small>


                            </div>
                            <p class="mb-1"></p>
                            <small></small>
                        </a>


                        <div class="dropdown-divider"></div>
                        <a class="dropdown-item" href="#">View All</a>
                    </div>
                    {{/each}}

It will just print one element. Even thought when I print {{session.user.notification.notidata}} is see Object object, Object object rightly so since there are two elements in the notidata array.

Here is how the db looks like

{
   "_id":"5bad3c53967c040c3c86c504",
   "notification":{
      "counter":1,
      "notidata":[
         {
            "data":{
               "heading":"second"
            }
         },
         {
            "data":{
               "heading":"third"
            }
         }
      ]
   },
   "ads":[

   ],
   "username":"rghe",
   "email":"gbngt@dc.com",
   "password":"dfg",
   "country":"AUS",
   "createdOn":"2018-09-27T20:23:47.820Z",
   "__v":0
}
mysamza
  • 387
  • 1
  • 6
  • 22
  • Are there any errors from the console? Also, although there are 2 elements in the database, could the view that passes in the JavaScript object to the template for rendering somehow only be passing in an array of 1 element? It is weird that it works for one element and not all the elements in the array. This makes me think that maybe the array only has one element by the time it hits the template. I posted an edited answer where I show it working with the same set-up on my end. – Nathan Sep 28 '18 at 18:02