Paridhi
Paridhi

Reputation: 9

Issues Rendering Plotly OHLC Plot with EJS and Passing Data

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

Answers (1)

GreenSaiko
GreenSaiko

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:

  1. 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) %>");
        ...
    
  2. 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

Related Questions