Reputation: 9
I am trying to render a Plotly OHLC plot in my chart.ejs
file and pass a variable called result
to it. However, when I attempt to use EJS templating to include result
in the chart.ejs
file, the plot does not display. I also tried using <script>
tags for the logic, but the plot still doesn't show. I made another file chart.js
to contain the logic concerning the plot but I'm not sure how to make it work.
What could be causing this issue, and how can I successfully render the Plotly OHLC plot with the result data in my EJS template?
index.js:
import express from "express";
import axios from "axios";
const app = express();
const port = 3000;
app.use(express.static("public"));
app.set("view engine", "ejs"); // Set EJS as the view engine
const base_url = "https://api.coingecko.com/api/v3";
app.get("/", (req, res) => {
res.render("index.ejs", { result: null, error: null });
});
app.get("/ohlc", async (req, res) => {
const { id, currency, days } = req.query;
if (!id || !currency || !days) {
return res
.status(400)
.json({ error: "Please provide id, currency, and days parameters." });
}
try {
const ohlc_result = await axios.get(`${base_url}/coins/${id}/ohlc`, {
params: {
vs_currency: currency,
days: days,
},
});
let day = [];
let open = [];
let high = [];
let low = [];
let close = [];
for (let i = 0; i < ohlc_result.data.length; i++) {
const unix_timestamp = ohlc_result.data[i][0];
const date = new Date(unix_timestamp);
const formattedDate = date.toISOString().split('T')[0];
if (!day.includes(formattedDate)) {
day.push(formattedDate);
open.push(ohlc_result.data[i][1]);
high.push(ohlc_result.data[i][2]);
low.push(ohlc_result.data[i][3]);
close.push(ohlc_result.data[i][4]);
}
}
// Create the OHLC trace
const result = {
x: day,
open: open,
high: high,
low: low,
close: close,
type: "ohlc",
increasing: { line: { color: "#17BECF" } },
decreasing: { line: { color: "#7F7F7F" } },
};
console.log("OHLC Result:", ohlc_result.data);
console.log("Formatted Result:", result);
res.render("chart.ejs", { result: result });
} catch (error) {
console.log(error.message);
res.status(500).send(error.message);
}
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
chart.js:
const trace = {
x: result.x,
open: result.open,
high: result.high,
low: result.low,
close: result.close,
type: "ohlc",
increasing: { line: { color: "#17BECF" } },
decreasing: { line: { color: "#7F7F7F" } },
};
const layout = {
title: "OHLC Chart",
dragmode: "zoom",
xaxis: {
title: "Date",
type: "date",
},
yaxis: {
title: "Price",
type: "linear",
},
};
Plotly.newPlot("ohlc-result-div", [trace], layout);
chart.ejs:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CryptoLens</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="styles/main.css">
<script src='https://cdn.plot.ly/plotly-2.35.2.min.js'></script>
<!-- <script src="/chart.js" defer></script> -->
</head>
<body>
<h1>OHLC Chart</h1>
<!-- THE FOLLOWING DOES NOT WORK -->
<!-- <script>
const trace = {
x: result.x,
open: result.open,
high: result.high,
low: result.low,
close: result.close,
type: "ohlc",
increasing: { line: { color: "#17BECF" } },
decreasing: { line: { color: "#7F7F7F" } },
};
const layout = {
title: "OHLC Chart",
dragmode: "zoom",
xaxis: {
title: "Date",
type: "date",
},
yaxis: {
title: "Price",
type: "linear",
},
};
Plotly.newPlot("ohlc-result", [trace], layout);
</script> -->
<div id="ohlc-result-div"><!-- Plotly chart will be drawn inside this DIV --></div>
</body>
</html>
I understand that there is some issue with sending over result
to chart.ejs
, I'm just not sure what.
Upvotes: 0
Views: 61
Reputation: 346
The problem here is how you're using the variables passed to the render engine.
The variables you pass to the render()
function are only available during rendering and only for code in EJS tags <% ... %>
. You can read more on EJS variables on this answer.
Which means that in the <script>
there is no result
variable defined. From what I see, you have two options:
Pass EJS variable to script
The probably faster and simpler solution would be to just pass the variable to the script tag. Technically it would be as simple as
<script>
let resultInScript = <%= result %>
...
But there are some caveats. First and foremost, most IDEs will display this as an error, even though it will execute. That is simply because it is not aware of EJS syntax inside a <script>
and it can be avoided by surrounding the tags with any string delimiters ("
quotes, '
apostrophe, `
backtick) like this:
<script>
let resultInScript = "<%= result %>"
...
Next problem are objects. Looking back at the previous issue, if we think about it no matter what exactly the variable in the EJS tags is, it will always be a string on the javascripts end. So if we were to simply pass result
like we did up to now, resultInScript
would simply be [object Object]
as a string. So the final form of all this together would look like
<script>
let resultInScript = JSON.parse("<%= JSON.stringify(result) %>");
...
AJAX request to server
The other solution would be to, on page load, send an asynchronous request to the server and get the data like that.
So you would create a route on your server, something like app.get('/ohcl/data'...
, and on page load immediately send a request to the server´. Depending on how important the data is you can just make a GET request with the data as query params or make a POST request with the data in the body. Not that this makes it super secure, but at least not having them as query params.
This would also make your page loading time better and have the data/charts load in like, depending on how fast the data is retrieved, at most some seconds and at best some miliseconds.
Hope this helps, feel free to ask if something is unclear.
Upvotes: 0