Как правильно перебирать массив в шаблоне EJS после вызова AJAX (с использованием ExpressJS)?

Поэтому я пытаюсь перебрать массив объектов, которые я получил от http-вызова, используя мой внутренний API, используя request модуль / пакет. Пока что я могу получить свои данные из API и отобразить полный объект на моей странице. Я хотел бы отобразить его на своей странице и просмотреть его, используя систему шаблонов EJS. Я знаю, что могу использовать AngularJS для внешнего интерфейса, но я хотел бы увидеть, как далеко я могу идти только на стороне сервера.

Итак, ниже мой код:

server.js

// Prepend /api to my apiRoutes
app.use('/api', require('./app/api'));

api.js

var Report = require('./models/report');
var express  = require('express');
var apiRoutes = express.Router();

apiRoutes.route('/reports', isLoggedIn)  
     .get(function (req, res,next) {
          // use mongoose to get all reports in the database
          Report.find(function (err, reports) {
                 // if there is an error retrieving, send the error.
                 // nothing after res.send(err) will execute
                 if (err)
                    return res.send(err);
                    res.json(reports);
          });
    });

routes.js

var User = require('./models/user');
var request = require('request');
module.exports = function (app, passport) {

    app.get('/reports', isLoggedIn, function (req, res) {
        res.render('pages/new-report.ejs', {
            user: req.user,
            title:'New Report'
        });
    });


    request({
        uri:'http://localhost:2016/api/reports',
        method:'GET'
    }).on('data',function(data){
        console.log('decoded chunk:' + data)
    }).on('response',function(resp){
        resp.on('data', function(data){
            console.log('received:' + data.length + ' bytes of compressed data');
            app.get('/timeline', isLoggedIn, function (req, res) {
                res.render('pages/timeline', {
                    user: req.user,
                    title:'Timeline',
                    reports: data
                });
            });
        })
    }); 
}  

reports.ejs
Так что, если я просто выведу весь reports объект как этот <p><%= reports %></p> на моей странице все работает нормально, и я получаю что-то вроде этого:

[
  {
    "_id": "5775d396077082280df0fbb1",
    "author": "57582911a2761f9c77f15528",
    "dateTime": "30 June 2016 - 07:18 PM",
    "picture": "",
    "description": "",
    "location": [
      -122.46596999999997,
      37.784495
    ],
    "latitude": 37.784495,
    "longitude": -122.46596999999997,
    "address": "4529 California St, San Francisco, CA 94118, USA",
    "contact": "John Doe",
    "type": "Financial",
    "__v": 0,
    "updated_at": "2016-07-01T02:21:10.259Z",
    "created_at": "2016-07-01T02:21:10.237Z",
    "tags": [
      "tag1,tag2"
    ]
  }
]

Но если я пытаюсь перебрать объект, как показано ниже, он получает UNDEFINED как возвращаемое свойство моего объекта отчета, и я, очевидно, получаю бесконечный цикл.

<ul class="timeline">
    <% reports.forEach(function(report) { %>
    <li class="timeline-yellow">
        <div class="timeline-time">
            <span class="date" style="text-align:left">
            <%= report.type %> </span>
            <span class="time" style="font-weight:700;font-size:25px;line-height:20px;text-align:left;">
            <%= report.dateTime %> </span>
        </div>
    </li>
    <% }) %>
</ul>

Я пробовал другой вариант цикла, но я все еще не смог:

<ul class="timeline">
    <% for (var i = 0; i < reports.length; i++) { %>
    <li class="timeline-yellow">
        <div class="timeline-time">
            <span class="date" style="text-align:left">
            <%= report[i].type %>
            4/10/13 </span>
            <span class="time" style="font-weight:700;font-size:25px;line-height:20px;text-align:left;">
            <%= report[i].dateTime %> </span>
        </div>
    </li>
    <% } %>
</ul>

4 ответа

Синтаксис для for зациклиться ejs идеально, но имя итеративного массива - report, и вы, кажется, используете report[i] внутри итерации, который должен быть изменен как reports [i], что должно работать.

reports.ejs

<ul class="timeline">
    <% for (var i = 0; i < reports.length; i++) { %>
    <li class="timeline-yellow">
        <div class="timeline-time">
            <span class="date" style="text-align:left">
            <%= reports[i].type %>
            4/10/13 </span>
            <span class="time" style="font-weight:700;font-size:25px;line-height:20px;text-align:left;">
            <%= reports[i].dateTime %> </span>
        </div>
    </li>
    <% } %>
</ul>

Надеюсь это поможет.

I guess something like this .. 

<% if (reports.length > 0){%> // Checking if there are reports
  <ul class="timeline">
      <%  for (let report of reports){ %>
        <li class="timeline-yellow">
          <div class="timeline-time">
            <span class="date" style="text-align:left">
              <%= report.type %> 
               4/10/13 </span>
              <span class="time" style="font-weight:700;font-size:25px;line- 
  height:20px;text-align:left;">
              <%= report.dateTime %> </span>
          </div>
      </li>
      <% } %>
  </ul>
 <%}%>
<%}%>

Вот моя рабочая версия с использованием loopback3 и ejs:

В server/boot/routes.js:

      module.exports = function(app) {
  const router = app.loopback.Router();

  router.get('/', function(req, res){
    app.models.ZenGarden.find()
        .then(plants => {
          console.log('plants: ', plants)
          res.render('index', {plants:plants})
        }).catch(err => {
          console.log('Failed to find in ZenGarden: ', err)
          res.render('index')
        })
  });

  router.post('/', function(req, res){
    var plants = req.body.plants;
    if (plants) {
      for (var i = 0; i < plants.length; i++) {
        console.log(plants[i])
        app.models.ZenGarden.upsert(plants[i])
            .then().catch(err => console.log(err))
      }
    }
    return res.render('index', {plants:plants})
  })

  app.use(router);
};

В server/views/index.ejs:

      <div>
    <form action='/' method='POST'>
        <% if (plants) { %>
            <table>
                <tr><td>Name</td><td>Count</td></tr>
                <% for (var i = 0; i < plants.length; i++) { %>
                    <tr>
                        <input type='hidden' value=<%= plants[i].id %> name='plants[<%= i %>][id]'>
                        <input type='hidden' value="<%= plants[i].name %>" name='plants[<%= i %>][name]'>
                        <td><%= plants[i].name %></td>
                        <td><input type='text' value=<%= plants[i].count %> name='plants[<%= i%>][count]'</td></tr>
                <% } %>
            </table>
            <button type='submit'>Save</button>
        <% } else { %>
            <p>No plant in Zen Garden :-(</p>
        <% } %>
    </form>
</div>

Обязательно добавьте следующее в server/server.js:

      const path = require('path')
const bodyparser = require('body-parser')

app.set('view engine', 'ejs')
app.set('views', path.resolve(__dirname, 'views'))

app.middleware('initial', bodyparser.urlencoded({extended:true}))
app.middleware('initial', bodyparser.json())

Вот определение модели ZenGarden(common/models/zen-garden.json):

      {
  "name": "ZenGarden",
  "base": "PersistedModel",
  "idInjection": true,
  "options": {
    "validateUpsert": true
  },
  "properties": {
    "name": {
      "type": "string",
      "required": true
    },
    "count": {
      "type": "number",
      "required": true
    }
  },
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": {}
}

Async - это служебный модуль, который предоставляет простые мощные функции для работы с асинхронным JavaScript. Хотя изначально он был разработан для использования с Node.js и устанавливается через

npm install --save async

Для документации, посетите http://For%20Documentation,%20visit%20http://caolan.github.io/async/

Примеры

// assuming openFiles is an array of file names and saveFile is a function
// to save the modified contents of that file:

async.each(openFiles, saveFile, function(err){
    // if any of the saves produced an error, err would equal that error
});
// assuming openFiles is an array of file names

async.each(openFiles, function(file, callback) {

  // Perform operation on file here.
  console.log('Processing file ' + file);

  if( file.length > 32 ) {
    console.log('This file name is too long');
    callback('File name too long');
  } else {
    // Do work to process file here
    console.log('File processed');
    callback();
  }
}, function(err){
    // if any of the file processing produced an error, err would equal that error
    if( err ) {
      // One of the iterations produced an error.
      // All processing will now stop.
      console.log('A file failed to process');
    } else {
      console.log('All files have been processed successfully');
    }
});
Другие вопросы по тегам