Guide on separating a Chart.js chart with reactive attributes into its own component in Svelte

After creating a Skeleton Project using the command npm create svelte@latest myapp, I proceeded to install Chart.js with

npm install svelte-chartjs chart.js
and then created a basic bar chart:

<script>
  import { Bar } from 'svelte-chartjs';
  import { Chart, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js';

  Chart.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale);

  let numbers = [10, 20, 30];
  let dates = ['1/1/2024', '1/2/2024', '1/3/2024'];

  $: data = {
    labels: dates,
    datasets: [
      {
        label: 'Random Number',
        data: numbers,
        backgroundColor: 'rgba(98,  182, 239,0.4)',
        borderColor: 'rgba(98,  182, 239, 1)',
        borderWidth: 2
      }
    ]
  };

  let options = {
    responsive: true,
    maintainAspectRatio: false
  };

  async function generate() {
    const response = await fetch('/generate');
    let fetchedData = await response.json();

    dates = fetchedData.dates;
    numbers = fetchedData.numbers;
  }
</script>

<h1>Fetch Data from API endpoint</h1>

<button on:click={generate}>Request</button>

<div>
  <Bar {data} {options} />
</div>

The data is fetched from the /generate API endpoint which generates random numbers (between 10 and 30) and corresponding dates. Pressing the Request button updates the bar chart with new values. The output image can be viewed https://i.sstatic.net/G0k7u.png.

The contents of the routes/generate/+server.js file (simulating the API endpoint) that updates the arrays are as follows:

import { json } from '@sveltejs/kit';

function getRandomNumber(min, max) {
  return Math.floor(Math.random() * (max - min) + min);
}

function generateDates(numDates) {
  var today = new Date();
  var dates = []
  
  for (let i = 0; i < numDates; i++) {
    let dateString = today.toLocaleDateString('en-US');
    dates.push(dateString);
    today.setDate(today.getDate() + 1);
  }

  return dates;
}

export function GET() {
  let length = getRandomNumber(1, 10);
  let numberData = Array.from({ length: length }, () => getRandomNumber(10, 30));
  let dateData = generateDates(length);
  
  return json({dates: dateData, numbers: numberData});
}

The data length is randomly chosen between 1 and 10, starting from the current date. An example response from the API endpoint looks like:

{"dates":["2/8/2024","2/9/2024","2/10/2024"],"numbers":[14,23,23]}

To enhance readability and reusability, I aim to separate the Bar chart-specific code into a distinct component. However, I want the labels and dataset attributes to reactively update when new data is fetched.

If you have any suggestions on how to achieve this, please share!

Answer №1

Develop a component called BarChart.svelte to isolate the chart-specific code:

<script>
  import { Bar } from 'svelte-chartjs';
  import { Chart, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js';

  Chart.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale);

  export let dates = [];
  export let numbers = [];

  $: data = {
    labels: dates,
    datasets: [
      {
        label: 'Random Number',
        data: numbers,
        backgroundColor: 'rgba(98,  182, 239,0.4)',
        borderColor: 'rgba(98,  182, 239, 1)',
        borderWidth: 2
      }
    ]
  };

  let options = {
    responsive: true,
    maintainAspectRatio: false
  };
</script>

<Bar {data} {options} />

To enable updating of the dates and numbers variables from another component, these need to be exported. Import the new component into the existing one and assign the retrieved values using the attributes of the bar chart:

<script>
  import BarChart from './BarChart.svelte';

  let numbers = [10, 20, 30];
  let dates = ['1/1/2024', '1/2/2024', '1/3/2024'];

  async function generate() {
    const response = await fetch('/generate');
    let data = await response.json();

    dates = data.dates;
    numbers = data.numbers;
  }
</script>

<h1>Fetch Data from API endpoint</h1>

<button on:click={generate}>Request</button>

<div>
  <BarChart {dates} {numbers} />
</div>

Note: It is recommended to place the BarChart.svelte component alongside the fetching component. In case there are multiple components, consider creating a separate components folder for better organization.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Changing the name of '_next' to 'next' within the output folder: NextJS

While developing my NextJS chrome extension, I encountered an issue when trying to 'load unpacked' extension. An error message popped up stating that "Cannot load extension with file or directory name _next. Filenames starting with _ are reserved ...

What factors cause variations in script behavior related to the DOM across different browsers?

When looking at the code below, it's evident that its behavior can vary depending on the browser being used. It appears that there are instances where the DOM is not fully loaded despite using $(document).ready or similar checks. In Firefox, the "els ...

The complete page gets re-rendered when Nuxt child routes are used

When I attempt to utilize child routes, my goal is to maintain specific data on the page while modifying other content. To illustrate this concept, I have created a straightforward example available at this link. After selecting "cat" and increasing the ...

What are alternative ways to communicate with the backend in Backbone without relying on model.save()?

Is there a more effective method to communicate with my backend (node.js/express.js) from backbone without relying on the .save() method associated with the model? Essentially, I am looking to validate a user's input on the server side and only procee ...

Navbar in bootstrap appears to be flashing when it is in its expanded

Example Link On smaller screens, the bootstrap navbar menu does not collapse by default when clicking on a menu item. To fix this issue, I added attributes data-toggle="collapse" and data-target="#navbar-collapse" to each menu item so that the menu will ...

Utilizing the `this` keyword within a click handler that is passed through an intermediary function

If I initially have a click event handler in jQuery set up like this jQuery('#btn').click(_eventHandler); And handling the event as follows function _eventHandler(e){ jQuery(this).text('Clicked'); } Does the this keyword serve a ...

What could be causing jQuery document ready to restrict access to global variables?

Currently, I am working on a project that involves three separate JavaScript files (example1.js, example2.js, and example3.js) being scripted into a single HTML file (index.html). These JS files are responsible for making an API call and manipulating the r ...

Interact with HTML Radio Buttons to Trigger Input Opening

I need to have a message saying "We're sorry..." and a "black box" displayed only when the radio button is set to YES, otherwise keep it hidden. Can I achieve this using JavaScript only, or is there a way to do it with HTML alone? <h3 >Did you ...

Customizing the JavaScript code created by the "Change Variable by..." block in Blockly

I'm currently working on a Blockly Project where I am passing data from the blocks as JavaScript code. One of my goals is to make some adjustments to the output code in order to make it more user-friendly for beginners. While it is possible to modify ...

Techniques for implementing a JS script within a useEffect hook in a functional component

I am currently working on a useEffect hook in my project, within which there is an if-else block that includes a Javascript function called 'B1.X.Change' inside the else statement. However, I am facing difficulty binding 'B1.X.Change' t ...

Automatic closing of multile- vel dropdowns in Bootstrap is not enabled by default

I have successfully implemented bootstrap multilevel dropdowns. However, I am facing an issue where only one child is displayed at a time. <div class="container"> <div class="dropdown"> <button class="btn btn-default dropdown-to ...

D3 - Error: Unable to access property 'text' of an undefined method

I want to create a visual representation of significant events that have occurred in the United States over the past 30 years. Below is a snippet of code I am using for this project: var mevent = svg.append("text") .attr("class", "year event") .at ...

Solving Promises with Arrays in JavaScript

Currently, I am working on a project and facing an issue that I need help with. Let me give you some background on what I am trying to achieve. First, I am making concurrent API calls using Axios in the following manner: const [...result] = await Promise. ...

Include an additional section in the stunning Radar Chart

I am trying to use the amCharts 4 library to create a Radar graph similar to this example: https://i.sstatic.net/9S0ka.png In the example, there are two categories being compared with bullets surrounding each one, right? The code I currently have is as ...

What is the best way to include a swf video in a list of hyperlinks?

My current code displays an image inside a box, and I am looking to replace the image with either a swf video or .AVI video. I have the object video code to play a swf video, but I need the video to be played within the box where the image is currently l ...

It seems like my ajax function is functioning properly, but the data is not getting submitted

Having trouble sending the value of my selector to a PHP file through AJAX. The success function is working, and when I directly visit "your_php_script.php" it functions as expected. However, why is the PHP page not showing up on the page with the AJAX r ...

How can I locate a Forum or Node using a JWT Token as a reference point?

Could someone please guide me on locating my forum using my JWT token? exports.getByOwnerID = function (req, res, next) { Forum.find({createdBy: req.body.createdBy}) .then(doc => { if(!doc) { return res.status(400).end();} return res.sta ...

Decreased storage space requirements following transfer to S3 bucket using nodejs

I am currently facing an issue with uploading files from a specific folder location to an S3 bucket using the nodejs aws-sdk. The files I am working with are deepzoom images (.dzi). While the files seem to be successfully uploaded to my S3 bucket, I have n ...

Patience is key when letting AJAX calls complete their execution in jQuery functions

In each of my 3 functions, I have a synchronous AJAX call. Here is an example: function() { a(); b(); c(); } a() { ajaxGet(globals.servicePath + '/Demo.svc/GetDemoList/' + sessionStorage.SessionId,function(data, success) {}, '&apos ...

Trouble with $sce in Angular.js causing limitations on passing desired content into my directive

I've successfully developed a directive that animates a PNG Sequence. Everything functions perfectly when I manually input the image url, but when attempting to pass a dynamic url, I encounter an error related to $sce disallowing it. Below is the cod ...