[英]How to send a ejs file as HTML email from nodejs application as cronjob
[英]Script won't run from ejs file in nodejs application
我正在尝试使用nodejs,express,mysql和ejs使网页显示图表,但是我显然不了解ejs / javascript等的工作原理。 我需要运行一个脚本来设置图表(来自chart.js模块),但它不会输出任何形式的图表。
我试过的
以下脚本将无法运行:
<canvas id="myChart" width="50%" height="100px"></canvas>
<script scr="map-access-data.js" type="text/javascript"></script>
<script id ="map-popularity" type="text/javascript">
var Chart = require('chart');
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: getMapAccessNames(),
datasets:[{
label: "Map Selection Popularity",
data: getMapAccessData(),
backgroundColor: getMapColors(),
borderColor: getMapColors(),
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
</script>
该文件的第一个脚本中引用的map-access-data.js文件:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'admin',
password : 'pass',
database : 'db'
});
connection.connect();
function getNumMaps(){
connection.query("SELECT NAME, COUNT(*) FROM map_access GROUP BY NAME ORDER BY NAME", function(err, rows){
return rows.length();
});
}
function getMapAccessData(){
var arr = [];
connection.query("SELECT NAME, COUNT(*) FROM map_access GROUP BY NAME ORDER BY NAME", function(err, rows){
for(i in rows){
arr.push(i.count);
}
});
}
function getMapAccessNames(){
var arr = [];
connection.query("SELECT NAME, COUNT(*) FROM map_access GROUP BY NAME ORDER BY NAME", function(err, rows){
for(i in rows){
arr.push(i.name);
}
});
return arr;
}
function getMapColors(){
var arr = [];
for(var i = 0; i < getNumMaps(); i++){
arr.push('rgba(255,99,132,1)');
}
return arr;
呈现此代码的实际文件:
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<% include header.ejs %>
<h1><%= title %></h1>
<p>See how people are using our app <br/></p>
<% include map-access-chart %>
</body>
</html>
这里有很多误解:HTML文件将提供给您的客户端,该客户端将看到<script>
标记,从Web服务器请求它们,并执行代码。 您不能期望Web浏览器在您的服务器上运行SQL查询),因此显然,这不是您想要执行此JS代码的方式。
太多的地方是错误的,这将是一个漫长的答案。 这是您的两个主要误解:
然后是您的许多小错误:
for (i in rows)
所以我是项目索引(我想您是因为您将其命名为i),所以使用i.count
SELECT COUNT(*) FROM
然后使用.count
属性,我不确定如果没有AS count
,它将起作用 在这一点上,我只能猜测您的SQL和Chart使用情况没有更好,抱歉:(虽然,我会尝试为您指明正确的方向。
因此,首先,您需要从Node.js服务器执行此JS代码。 通常的步骤是:
后续步骤的样本数据结构:
/
+- app.js
+- lib/
+- map-access-data.js
+- views/
+- index.ejs
+- map-access-chart.ejs
+- stylesheets/
+- styles.css
所需的服务器依赖项: npm install express ejs mysql
,其余部分用于客户端(如chart
)
// app.js
const express = require('express')
const app = express()
// Serve public static assets, like stylesheets and client-side JS
app.use(app.static('public'))
// Configure EJS template engine
app.set('view engine', 'ejs')
// Your route
app.get('/', (req, res) => {
// Your route handler
// req is client's request
// res is server's response
})
// Start web server on http://localhost:8000
app.listen(8000)
OK,在服务器端,您可以使用MySQL和类似系统。 但是首先我们需要解决另一个问题。
实际上,异步是Node的一个非常重要的组成部分,但是我们不能在这里解决所有问题。 您将拥有关键字,我让您进行研究以驯服该部分。 我将使用async
/ await
这样您在阅读代码时就不会太受困扰,而使用util.promisify
来转换方法。 您必须了解的内容:
connection.query
将查询一个远程服务器,在Node中它将异步完成,这意味着您不会立即得到任何结果,但是您的代码也不会被停止(或者它将被阻塞,这很糟糕) then
方法的函数; 在使用promise时,您必须返回那些对象,这些对象表示将来的数据,也是访问它的唯一方法 async
的特定语法,它允许您wait
承诺的数据,但是您的async函数仍将是异步的,这意味着它返回一个包装器,而不是您的实际结果,除非您也wait
它 这是您的错误:
getNumMaps
,您的return
值在回调中。 该回调在函数返回自己的结果之后被调用,因此它将只返回未定义 getMapAccessData
您甚至都不需要返回任何内容,但仍未定义 getMapAccessNames
,最后您返回了一些东西! 但是由于connection.query是异步的,因此您将在函数返回arr
后将数据推送到数组中,因此它始终返回[]
并且我将向您添加执行同一请求的三遍,听起来很浪费;)因此,您知道您想最终将所有这些都包含在Chart实例中,我们不要将其拆分为4个都执行相同查询的函数,而是使用调整后的格式生成单个结果。
// lib/map-access-data.js
const mysql = require('mysql')
const connection = mysql.createConnection(/* your config here */)
// get promises instead of using callbacks
const util = require('util')
const queryCallback = connection.query.bind(connection) // or we'll have issues with "this"
const queryPromise = util.promisify(queryCallback) // now this returns a promise we can "await"
// our asynchronous method, use "async" keyword so Node knows we can await for promises in there
async function getChartData () {
const rows = await queryPromise("SELECT name, COUNT(*) AS count FROM map_access GROUP BY name ORDER BY name")
// Array#map allows to create a new array by transforming each value
const counts = rows.map(row => row.count)
const names = rows.map(row => row.name)
const colors = rows.map(row => 'rgba(255,99,132,1)')
// Return an object with chart's useful data
return {
labels: names,
data: counts,
colors: colors,
}
}
好的,现在您有了一个仅在服务器端可用的功能,可以满足您的需求。
现在,您需要能够从app.js
调用它,这意味着您需要:
// lib/map-access-data.js
…
// Export your function as default
module.exports = getChartData
// app.js
const getChartData = require('./lib/map-access-data)
这称为CommonJS模块
现在,在路由处理程序中,您可以简单地调用async函数,并等待其结果:
// app.js
…
app.get('/', async (req, res) => {
// Your route handler
const data = await getChartData()
})
现在您可以使用数据了,仍然在服务器端,现在必须为客户端生成有效的HTML,当前的外观如下:
<!DOCTYPE html>
<html>
… a bunch of HTML …
<p>See how people are using our app <br/></p>
<canvas id="myChart" width="50%" height="100px"></canvas>
<!-- NO! it's not a client JS, it's server JS, client CANNOT download it -->
<script scr="map-access-data.js" type="text/javascript"></script>
<script id ="map-popularity" type="text/javascript">
var Chart = require('chart'); // NO! you can't *require* from client
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: getMapAccessNames(), // NO! You can't call server methods from client
datasets:[{
…
显然,我们需要修复一些问题:
map-access-data.js
的引用,这毫无意义 chart.js
,就像从CDN中添加 在这里,我认为可以使用Ajax请求来代替将真实数据直接注入HTML中,但是我不了解Chart,因此我将让您完成这一部分。 提供JSON数据的Express应用绝对是微不足道的,只需res.send(data)
,然后在客户端执行一些Ajax。 让我们看看将数据直接注入HTML以打破所有障碍的版本:
JSON.stringify
) <script>
添加一些JS,然后运行它,每个人都很高兴 <!-- views/map-access-chart.ejs -->
<canvas id="myChart" width="50%" height="100px"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js"></script>
<script id ="map-popularity" type="text/javascript">
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: <%- JSON.stringify(data.labels) %>,
datasets:[{
label: "Map Selection Popularity",
data: <%- JSON.stringify(data.data) %>,
backgroundColor: <%- JSON.stringify(data.colors) %>,
borderColor: <%- JSON.stringify(data.colors) %>,
borderWidth: 1
…
// app.js
…
// Your route handler
const data = await getChartData()
// Render 'index.ejs' with variables 'title' and 'data' available
res.render('index', {
title: 'Page title',
data: data,
})
现在,当您从终端运行node app.js
并转到http:// localhost:8000时,您应该会看到结果。 我猜还会有很多剩余的错误,但这将是一个更好的开始:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.