简体   繁体   English

如何在一系列 Google 电子表格中循环

[英]How to loop in a range of Google Spreadsheets

I'm trying to render the data from a Google Spreadsheets with Express and after placing the range of the cells to render and loop into it, I have a error: "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client."我正在尝试使用 Express 呈现来自 Google 电子表格的数据,并且在放置要呈现的单元格范围并将其循环到其中后,出现错误:“错误 [ERR_HTTP_HEADERS_SENT]:在将标头发送到客户端后无法设置标头.”

The spreadsheet has 3 rows and 6 columns and I'm not sure what I'm doing wrong as the error is persistent and I cannot get rid of it of anyway.该电子表格有 3 行 6 列,我不确定我做错了什么,因为错误是持续存在的,无论如何我都无法摆脱它。

My code:我的代码:

 const express = require('express');
 const router = express.Router();
 const {google} = require('googleapis');
 const keys = require('../credentials.json');

 const {
   google
  } = require('googleapis');
  const keys = require('../credentials.json');

  /* GET portfolio page. */
  router.get('/', function (req, res, next) {

  const client = new google.auth.JWT(
  keys.client_email,
  null,
  keys.private_key,
   ['https://www.googleapis.com/auth/spreadsheets.readonly']
  );

  client.authorize(function (err) {
   if (err) {
     console.log(err);
     return;
     } else {
       console.log('Connected');
       gsrun(client);
     }
    });

     async function gsrun(cl) {
     const gsapi = google.sheets({
     version: 'v4',
     auth: cl
    });

     const optPort1 = {
     spreadsheetId: '1W1OKGmGU6Io-1FhWjZLyPkGZz9Ky829zurAzcwmXiHg',
     range: ['Portfolio Page!A4:F6']
   };


   let spreadvals1 = await gsapi.spreadsheets.values.get(optPort1);


   console.log(spreadvals1.data.values);


    const cols1 = spreadvals1.data.values || [];

    const colsdata = cols1.map((element) => {
    res.set('Content-Type', 'text/html');

    res.render('portfolio', {
       headlinePortfolio: element[0],
       subheadlinePortfolio: element[1],
       image1: element[3],
       client: element[4],
       campaign: element[5]
     })
   });
 }
 });

  module.exports = router;

My HTML looks like this:我的 HTML 如下所示:

   <div class="page-header">
   <div class="text-headline">
       <div class="salutation">{{headlinePortfolio}}</div>
   </div>
   <div class="text-subheadline">
       <div class="descr">{{subheadlinePortfolio}}</div>
   </div>
   <div class="port-row">         
       <ul class="flex-container-port">
           <li class="flex-item-img-mob">
              <img src="{{image1}}" alt="header-image" />
           </li>
           <li class="flex-item-img-desktop">
             <img class="img-port" src="{{image2}}" alt="header-image" />
           </li>
           <li class="flex-item-descr">
              <p class="bg-text">{{client1}}</p>
              <p class="descr-text">{{campaign1}}</p>
           </li>
       </ul>
   </div>
   </div>

So, some dummy data will be:因此,一些虚拟数据将是:

   Name Age Year
   John 21  5
   Paul 22  6
   Mark 23  7
   Maggie 24 8
   Beth 25  9
   Patsy26  10

The problem it is in this line:问题出在这一行:

const colsdata = cols1.map((element) => {
res.set('Content-Type', 'text/html');

res.render('portfolio', {
   headlinePortfolio: element[0],
   subheadlinePortfolio: element[1],
   image1: element[3],
   client: element[4],
   campaign: element[5]
 })

}) })

You cannot render more than once .不能多次渲染 Render calls the method res.send() which sends data to the front-end. Render 调用将数据发送到前端的方法res.send() So what is happening is: You are sending (res.send()) several times (because res.render is inside the map) thus the error.所以发生的事情是:您多次发送 (res.send())(因为 res.render 在地图内)因此出现错误。

For you prevent the render to send the data you have to provide a callback like so:为了防止渲染发送数据,您必须提供如下回调:

res.render('portfolio', {
   headlinePortfolio: element[0],
   subheadlinePortfolio: element[1],
   image1: element[3],
   client: element[4],
   campaign: element[5]
 }, ()=>console.log(`template created do something`))

and the when you are ready to send everything you will just try to send everything in one go with: res.send(data)当您准备好发送所有内容时,您将尝试一次性发送所有内容: res.send(data)

Also you router.get has to be async in order to the await keyword work.此外,您的router.get必须是异步的,以便await关键字工作。

More update:更多更新:

You have updated your answer therefore this is a more dumb down approach of everything that I had shared above.您已经更新了您的答案,因此这是我上面分享的所有内容的更愚蠢的方法。

You are trying to create one template but the problem is that you are creating multiple templates because you are using a function inside a loop .您正在尝试创建一个模板,但问题是您正在创建多个模板,因为您在循环中使用了一个函数 What you should be doing is to remove the function from the loop.您应该做的是从循环中删除该函数。

Unfortunately I cannot teach exactly how to achieve what you want to achieve.不幸的是,我无法准确地教您如何实现您想要实现的目标。 I will reproduce a minimum output so you can work from there:我将重现最小输出,以便您可以从那里工作:

Note: In order to simplify, everything that is not here should stay the same.注意:为了简化,不在此处的所有内容都应保持不变。

 /* GET portfolio page. */
  router.get('/', async function (req, res, next) {

     ...
    const cols1 = spreadvals1.data.values || [];


  // I have removed the .map fn. You should do the same

    res.set('Content-Type', 'text/html');
    res.render('portfolio', {
       headlinePortfolio: cols[0][0], //row 1 - elem (col) 1
       subheadlinePortfolio:cols[0][1], //row 1 - elem  (col) 2
       image1: cols[0][3], //row 1 - elem (col) 4
       client: cols[0][4],//row 1 - elem (col) 5
       campaign: cols[0][5], // row 1 - elem (col) 6
     })

 }
 });

  module.exports = router;

With the example above you will have no errors and it will only get the first row.使用上面的示例,您将没有错误,并且只会获取第一行。 If you want the next rows you will have to increase for row[1] , row[2] , row[3] and so forth... If you wanna multiple (separated) templates from different rows you will have to dig deeper and understand what I am saying about callbacks and implement it with map.如果你想要下一行,你将不得不增加row[1]row[2]row[3]等等......如果你想要来自不同行的多个(分离的)模板,你将不得不更深入地挖掘和理解我所说的回调并用 map 实现它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM