在 AJAX 调用(使用 ExpressJS)之后,在 EJS 模板中循环遍历数组的正确方法是啥?

Posted

技术标签:

【中文标题】在 AJAX 调用(使用 ExpressJS)之后,在 EJS 模板中循环遍历数组的正确方法是啥?【英文标题】:What is the proper way to loop through an array in an EJS template after an AJAX Call (using ExpressJS)?在 AJAX 调用(使用 ExpressJS)之后,在 EJS 模板中循环遍历数组的正确方法是什么? 【发布时间】:2016-11-05 20:28:21 【问题描述】:

因此,我尝试使用 request 模块/包循环访问从 http 调用中获得的对象数组到我的内部 API。到目前为止,我能够从 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 因此,如果我只是在我的页面上像这样<p><%= reports %></p> 输出整个reports 对象,一切正常,我会得到这样的结果:

[
  
    "_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 作为我的 report 对象的返回属性,我显然会得到一个无限循环。

<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>

【问题讨论】:

【参考方案1】:

ejsfor 循环的语法是完美的,但迭代的数组名称是 reports 并且您似乎在迭代中使用了 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>

希望这会有所帮助。

【讨论】:

【参考方案2】:
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>
 <%%>
<%%>

【讨论】:

请解释一下你的答案 基本上他会发送一个名为报告的数组作为响应。 EJS 让您可以使用 javascript 编写 - 最好看这里:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…【参考方案3】:

这是我使用 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);
;

在服务器/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": 

【讨论】:

以上是关于在 AJAX 调用(使用 ExpressJS)之后,在 EJS 模板中循环遍历数组的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

将视图渲染到 ExpressJS 中的变量中(用于 AJAX 响应)

expressjs不返回任何响应给html

ExpressJS:承诺和错误处理中间件

使用 Passport 和 ExpressJS 进行 Facebook 身份验证 - 为啥不调用验证回调?

使用 CORS 登录 expressjs 应用程序

在使用 Newtonsoft 之后,ajax 调用在 asp.net 中返回 HTML 响应而不是 Json