Andrew
Andrew

Reputation: 69

Iteration with Pug over an object

Passing an object to Pug from app.js

router.get('/', getMenuList, function (req, res, next) {
  res.render('menu_items', {
   title: 'The Weekly Menu',
   message: 'The List',
   dataset
  });
});

The dataset looks like

menu_date   dish_name         Display
2018-10-01  Fish              2018-10-01: Fish
2018-10-01  Green Beans       2018-10-01: Green Beans with Mushrooms and cream
2018-10-02  Out To Dinner     2018-10-02: Out To Dinner
2018-10-03  Oysters           2018-10-03: Oysters an the half shell
2018-10-03  Sauce Mignette    2018-10-03: Sauce Mignette

What I want to display on HTML is a nested list like

2018-10-01
       Fish
       Green Beans
2018-10-02
       Out to diner
2018-10-03
       Oysters
       Sauce Mignette

My PUG code as follows iterates over the object but I don't know how to get nested list

extends layout

block content
    h2= title
    -var wtf = dataset.length
    -var n = 0
    h1= message
    each item in dataset
        ul
            li #{item.Menu_Date}

Posted below is the app.js which writes an html page. The code is ugly. Not facile with javascript, HTML, or CSS.

    //submit
    var express = require('express');  
    var bodyParser = require('body-parser');  
    var app = express();  
    app.use(bodyParser.json());
    var tedious = require('tedious');
    var Promise = require('promise');
    app.use(bodyParser.urlencoded({ extended: false }));
    var path = require('path');
    var fs = require('fs');  
    
    var router = express.Router();
    var menu_data = [];    
    var menu = [];
    
    app.engine('pug', require('pug').__express);
    app.set('views', path.join(__dirname, 'views'));  
    app.set('view engine', 'pug');
    
    app.use(router);  
    app.use(express.static(path.join(__dirname, 'public')));
    
    
    router.get('/', getMenuList, function (req, res, next) {
         var item = [];
         for(var row of menu_data ){
           if(menu.length == 0) {
             var newItem = {Date: row.MenuDate, Items: item};
                      
             menu.push(newItem);            
           }
           if(row.MenuDate != menu[menu.length -1].Date) {
            
            item = [];
             
             var newItem = {Date: row.MenuDate, Items: item};
             menu.push(newItem);
           }
           var newDish = {Dish: row.Item};
           
           menu[menu.length -1].Items.push(row.Item);
          /* var i = 0;
           while(i < menu[menu.length -1].Items.length) {
             console.log( menu[menu.length -1].Items[i]);
             i++;
           }
           */           
         }
         
         fs.writeFileSync('./views/message.html', '<!DOCTYPE html><html><head><title>The Weekly Menu</title><link rel="stylesheet" href="/stylesheets/style.css"></head><body>', 'utf8', function(err){
          if (err) throw err;
         });
         fs.appendFileSync('./views/message.html', '<h1>Why the drama</h1>', function(err){
           if (err) throw err;
         });
        for(index = 0; index < menu.length ; index++ ) {
            //console.log(menu[index].Date);
            if(index ===0){
              fs.appendFileSync('./views/message.html', '\r\n<ul>', function(err){
                if(err) throw err;
              });
            }
            fs.appendFileSync('./views/message.html', '\r\n<li>'  + menu[index].Date + '</li>', function(err){
              if(err) throw err;
            });
    
                for(newindex = 0; newindex < menu[index].Items.length; newindex++) {
                    //console.log(menu[index].Items[newindex])
                    if(newindex === 0 ){
                    fs.appendFileSync('./views/message.html','\r\n<ul>', function(err){
                      if(err) throw err;
                      });
                    }
                    fs.appendFileSync('./views/message.html', '\r\n<li> ' + menu[index].Items[newindex] + '</li>', function(err){
                      if(err) throw err;
                      });
                  }
                  fs.appendFileSync('./views/message.html', '\r\n</ul', function(err){
                    if(err) throw err;
                  });
          }  // end of outer loop
    
          fs.appendFileSync('./views/message.html', '\r\n</ul>\r\n\<a href=\"http://localhost:3030/index\"> Input Menu Items</a>\r\n</body>\r\n</html>', function(err){
            if(err) throw err;
          });
                    
       /* res.render('menu_items', {
          title: 'The Weekly Menu',
          message: 'The List',
          menu_data,
          menu
         
      }); */
    
       res.sendfile('./views/message.html');
    });
    
    router.get('/index', function(req, res) {
        res.render('index')
    });
    
    router.post('/update',submitMenuItem, function (req, res) {  
          var menu_data = req.body.menuDate;
          var description = req.body.theItem;
          
        res.render('update', {
            title: 'All Quiet on the Western Front',
            menuDate: menu_data,
            MenuItem: description    
        });
    });
    
    // end of submitMenuItem
    
    function getMenuList( req, res, next) {
        var promise = new Promise(function(fulfill, reject){      
        var Connection = require('tedious').Connection;
        var Request = require('tedious').Request;
        var config = JSON.parse(fs.readFileSync('./config/config.json', 'utf8'));
        var connection = new Connection(config);
        
        connection.on('connect', function (err) {
                if (err) {
                  console.log(err);
             } else {
                  executeStatement();
             }
        });
       /* function MenuItem(Menu_Date, Name, Display)
        {
          this.Menu_Data = Menu_Date;
          this.Name = Name;
          this.Display = Display;
        }  */
        
        function executeStatement() {
             var sql = "select dt_ofItem ,dish_name  FROM LA_COUNTY.dbo.mn_items order by dt_ofItem"; 
            
             var Request = require('tedious').Request;
             request = new Request(sql, function (err, rowCount) {
                  if (err) {
                       reject(err);
                  } else {
                      if(rowCount < 1) {
                          callback(null, false);
                      }
                      else {
                       fulfill(menu_data);
                      }
                  }
             });
           
             request.on('row', function (columns) {
                 var Menu_Date = ""
                  columns.forEach(function (column) {
                      
                      if(column.metadata.colName=== "dt_ofItem"){
                          
                          Menu_Date = column.value.toDateString();
                          
                       }
                      if(column.metadata.colName==="dish_name") {
                          //console.log(column.value);
                          //console.log('WTF');
                      //var item = new MenuItem(Menu_Date, column.value, Menu_Date + ": " + column.value);
                      var menu_stuff = {
                        MenuDate: Menu_Date,
                        Item: column.value  
                    };
                      menu_data.push(menu_stuff);
                          //menu_data.push("Date" Menu_Date ,"Item" column.value );
                          //item = null;
                      }
                  });                  
             });
                  
             request.on('doneProc', function (rowCount, more, returnStatus, rows) {
                  next(null, rows);
                  connection.close()

                 // console.log(menu_data[0].MenuDate);

                  menu_data = [];
    
             });
    
             connection.execSql(request);
        }
        });
    }  // end getclients
    
    
    
    function submitMenuItem( req, res, next) {
    var menu_date = req.body.menuDate;
    var description = req.body.theItem;
        
    var Connection = require('tedious').Connection;
    
    var config = JSON.parse(fs.readFileSync('./config/config.json', 'utf8'));
    
     var connection = new Connection(config);
    
      var connection = new Connection(config);
    
      connection.on('connect', function(err) {
    
          executeStatement();
        });

      function executeStatement() {
        var sql = "insert LA_County.dbo.mn_items (dt_ofItem, dish_name) values ('" + menu_date + "','" + description + "')"
        var Request = require('tedious').Request;
        request = new Request(sql, function(err, rowCount) {
          if (err) {
            reject(err);
          } else {
            if(rowCount < 1) {
                callback (null, false);
          }
          else {
              fulfill(menu_date);
          }
        }
        });
      
        request.on('row', function(columns) {
          columns.forEach(function(column) {
            //console.log(column.value);
          });
        });
        
        request.on('doneProc', function (rowCount, more, returnStatus, rows) {
            next(null, rows);
    
                connection.close()
             });  

        connection.execSql(request);
      }    
    
    } // end of submitMenuItem

here is the PUG code. Which I am very very unsure about

extends layout

block content
    h2= title
    -var wtf = menu_data.length
    //h1 #{wtf}
    -var n = 0
    h1= message
    ul
        while n < wtf
            li= menu_data[n++].MenuDate



    ul
        each entry in menu
            li= entry.Date
            -var i = entry.Items.length
            h3 #{i}
            -var q = 0
            ul
                each dish in entry.Items
                    li dish
                //while q <  i
                    //li= entry.Items[q]
            
            
    a(href='http://localhost:3030/index') Input Menu Items
    
        app.listen(3030);  
        module.exports = app;  

For a more complete view the code is on GIT

Sorry if I am not doing these posts according to Hoyle.

Upvotes: 4

Views: 4558

Answers (1)

Graham
Graham

Reputation: 7802

In order to get this working you'll need to massage your data a little bit in the route.

We'll create an array of objects with the date as the keys and an array of dishes as the properties for each date. We want to use an array as the core object as key order is not guaranteed iterating JavaScript objects, but it is in arrays.

Doing this will make it easy for the Pug template to iterate through and give you the nested list you want. Adding complex conversion logic into the template itself isn't a good idea, the route is the best place to store that.

Here is the pug-friendly array that we'll want to dynamically build:

[
    {
      "date": "2018-10-01",
      "items": ["Fish", "Green Beans"]
    },
    {
      "date": "2018-10-02",
      "items": ["Out to Diner"]
    },
    {
      "date": "2018-10-03",
      "items": ["Oysters", "Sauce Mignette"]
    }
]

Here's how to convert it (I'm assuming your dataset variable is sorted here, if not then you'll need to use a different algorithm to do this):

var menu = [];

for(var row of dataset){

  // see if the date on the current row is the same as the last date in the menu array
  if( row.menu_date != menu[menu.length - 1].date ) {

    // add new object to the end of the array
    menu.push({
      "date": row.menu_date,
      "items": []
    });

  }

  // add item from current row to the end of the array in the last menu date entry
  menu[menu.length - 1].items.push(row.dish_name);

}

Pass the menu variable into the res.render function instead of the dataset, then the template can iterate through this object like this:

ul
  each entry in menu
    li= entry.date
      ul
        each item in entry.items
          li= item

If you ever need to change the logic here (adding fields, changing list format, etc.) or debug your code, keeping the template simpler makes it very easy.

Upvotes: 4

Related Questions