0

I have a html chart that will display my array from a javascript function 'window.testDataArray'. I would like to replace the sample array with the array data from the server endpoint. I am not sure what I need to do to achieve this.

Client Side


window.testDataArray = function(){

        return [6.5,5.2,3.4,5.8] //sample array
    };

Updated Client Side(Not Working) I am not sure the syntax is correct here. Any help is very welcome. I am very new to javascript and node.js.

window.testDataArray = async function(){
        //      return [1,2,3,4,5,6,7,8,9,9,8,7,4,5,6,1,2,3] 
        try{
        return await fetch('http://localhost:3000/array').then(function (data) { 
            return data 
        }).catch(function(error){return 'testDataArray' + (error)
    });

        }
        catch(error){'Error testDataArray' + error}
    };

Server Side


const express = require('express');
const app = express();

app.get('/array', (req, res) => {
    test()
    async function test (){

    res.send(await local_db.get_data('heights'));//returns array e.g.[5.1,4.3,2.1,5.8] 
    }
    //await local_db.disconnect();
})


const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}...`));

//console.log("Server running at http://127.0.0.1:3000/ or http://localhost:3000/");

'window.testDataArray' is in utlis.js & is called from 'Line Chart.html'. window.testDataArray fails to get the array from the node.js server endpoint http://localhost:3000/array

Response to Answers Below (Unable to reproduce answer locally what am I missing?)

Thanks for the explanation Emissary your code works like a charm but I cannot get it to work with a local server. I do not intent to have this uploaded to the web. The browser response to the runkit endpoint is 'Cannot GET /' . But when I navigate to 'http://localhost:3000/array' I get [0,10,5,2,20,30,45]. Please see your code below. I have substituted your runkit endpoint for the local one.

<!DOCTYPE html>
<!-- saved from url=(0061)https://www.chartjs.org/samples/latest/charts/line/basic.html -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Line Chart</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
    <canvas id="myChart"></canvas>
    <style>

@keyframes chartjs-render-animation{from{opacity:.99}to{opacity:1}}.chartjs-render-monitor{animation:chartjs-render-animation 1ms}.chartjs-size-monitor,.chartjs-size-monitor-expand,.chartjs-size-monitor-shrink{position:absolute;direction:ltr;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1}.chartjs-size-monitor-expand>div{position:absolute;width:1000000px;height:1000000px;left:0;top:0}.chartjs-size-monitor-shrink>div{position:absolute;width:200%;height:200%;left:0;top:0}</style></head>

<body>
    <script>

        const chart = new Chart(
    document.getElementById('myChart').getContext('2d'), 
    { 
        type: 'line',
        // ... 
    }
)

//const API_HOST = 'https://so-58465005-mqksg0z5tsf8.runkit.sh'
const API_HOST = 'http://localhost:3000'

fetch(`${API_HOST}/array`)
    .then(response => response.json())
    .then(data => { 
        chart.config.data.labels = Array.from(Array(data.length)).map((_, i) => i + 1)
        chart.config.data.datasets.push({ label: 'my data', data })
        chart.update()
    })

    </script>
</body></html>

Please find server side code below. I have substituted '@runkit/runkit/express-endpoint/1.0.0' for 'express'. I must be missing something fundamental here? Thanks again for the help so far.

const express = require("express")
const cors = require('cors')

const app = express()

app.use(cors())

app.get("/array", (req, res) => {
    const data = [0, 10, 5, 2, 20, 30, 45]
    res.send(JSON.stringify(data))
    res.end();
})


const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}...`));
``
Alastair
  • 19
  • 4
  • `fetch('http://localhost:3000/array').then(() => { /* do something */ })` - [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) – Emissary Oct 19 '19 at 15:15
  • Thanks for the info, I am not getting a value from my function, am I doing anything wrong? window.testDataArray = function(){ return fetch('http://localhost:3000/array').then((data) => {return data }) }; – Alastair Oct 19 '19 at 15:55
  • probably this: [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call?answertab=oldest#tab-top) – Emissary Oct 19 '19 at 16:05
  • Thanks Emissary for the link, I have amended the code above but am still unable to get an array to my javascript function. Any ideas? – Alastair Oct 19 '19 at 16:29
  • The issue is that you can't treat an asynchronous call synchronously - `async` / `await` in general is syntactic sugar that allows you to write code imperatively but is still a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) chain under the hood. Whatever is using `testDataArray()` in your code needs to be restructured in a way where it does not expect an immediate result. Can you include enough client code for an [MCVE](https://stackoverflow.com/help/minimal-reproducible-example). – Emissary Oct 19 '19 at 16:46
  • I have uploaded the sample files as a zip. See the link above. I should see two lines plotted when the array reads in correctly. I have tried a few bits of code but it either breaks the chart or does not plot the second line as there is no array passed. – Alastair Oct 19 '19 at 18:14

1 Answers1

0

There are a few issues with your project, I've replicated your server on RunKit - please take note of two important components to this:

  • composite object types cannot be returned without serialising them on the server side and deserialising them in the client - HTTP data is transmitted as plain text - this is commonly done via JSON.
  • it isn't clear where you are serving the .html file from but looks likely that you'll be running into cross-origin errors - I included middleware to handle this, further reading into CORS available here.

To address the problem described in the question, you are currently trying to statically apply the data to the configuration before a request has responded. Instead try reacting to the data in the promise returned by fetch.

Forgetting async / await for now, this can be achieved by passing a callback function to .then - similar to how you are already responding to button click-events elsewhere in your attached example.

const chart = new Chart(
    document.getElementById('myChart').getContext('2d'), 
    { 
        type: 'line',
        // ... 
    }
)

const API_HOST = 'https://so-58465005-mqksg0z5tsf8.runkit.sh'

fetch(`${API_HOST}/array`)
    .then(response => response.json())
    .then(data => { 
        chart.config.data.labels = Array.from(Array(data.length)).map((_, i) => i + 1)
        chart.config.data.datasets.push({ label: 'my data', data })
        chart.update()
    })
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
<canvas id="myChart"></canvas>
Emissary
  • 9,954
  • 8
  • 54
  • 65
  • This works great from your runkit endpoint but I am unable to reproduce this locally. What am I doing wrong? See amended post above. Many thanks. – Alastair Oct 19 '19 at 22:54
  • `exports` is part of the RunKit API, try remove it from `const app = express()`. You're also now requesting `http://localhost:3000/array/array` in the edited code. – Emissary Oct 19 '19 at 23:24
  • Thank you!! It now works, I have updated the code above to remove my typo. – Alastair Oct 20 '19 at 08:41