[英]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.