表单提交后,函数运行很快, chart.js 出现一秒钟然后消失

After form submit, function runs quickly and chart.js shows up for a second then goes away

我有一个 Javascript 项目,我从 API 来源接收 Covid-19 数据。用户输入他们希望查看数据的国家/地区(从 2020 年 3 月到今天),然后使用 chart.js 将数据绘制到屏幕上。我在用户输入国家/地区的输入字段中添加了一个事件侦听器,并以这种方式检索数据。但是,当我调用我的函数来绘制数据图 ( graphIt() ) 时,该函数发生一秒钟然后消失。我理解为什么会发生这种情况,因为该函数只被调用一次,所以它很快就完成了。但是,我怎样才能让 chart.js 一直保持下去呢?我会把代码的重要部分放在这里!

index.html

        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.min.js"></script>
        <script src="{% static 'viewCasesChart/index.js' %}"></script>

        <div id="banner">
          <div id="banner_details">
            <h2>CoData</h2>
          </div>
        </div>    
    
       <div id="one_line">
         <div id="main_title">
           <h1>Covid-19 Data</h1>
         </div>
      
         <div id="user_query_data">
           <form id="country_form">
             <input type="text" placeholder="Country" id="country">
             <input type="submit" value="Search">
           </form>
         </div>
       </div>

       <div id="confirmed_graph">
         <canvas id="myChart" height="500" width="300"></canvas>
       </div>

index.js

    document.addEventListener('DOMContentLoaded', () => {
    //make a global variable and put default value into it
    var country = "Italy";

    document.getElementById('country_form').addEventListener('submit', () => {
        var delayInMilliseconds = 100000; //
        country = document.getElementById('country').value;
        console.log("test 1", country);

        graphit();
    })
    
    async function graphit() {
        document.getElementById('myChart').style.display = "block";
        const dataset = await dataToGraph();
        
        console.log("dataset.xs", dataset.xs);
        console.log("dataset.ys", dataset.ys);

        const ctx = document.getElementById('myChart').getContext('2d');
        const myChart = new Chart(ctx, {
            type: 'line',
            data: {
                labels: dataset.xs,
                datasets: [{
                    label: `Covid 19 Confirmed cases in ${country}`,
                    data: dataset.ys,
                    backgroundColor: ['rgba(255, 99, 132, 0.2)'],
                    borderColor: ['rgba(255, 99, 132, 1)'],
                    borderWidth: 1,
                    fill: false,
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                
                scales: {
                    yAxes: [{
                        scaleLabel: {
                            display: true,
                            labelString: 'Confirmed Cases'
                        }
                    }],
                    xAxes: [{
                        scaleLabel: {
                            display: true,
                            labelString: 'Date'
                        }
                    }],
                }     
            }
        });
    };
    
    async function dataToGraph() {
        const xs = [];
        const ys = [];
        
        var today = new Date();
        var dd = String(today.getDate()).padStart(2, '0');
        var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
        var yyyy = today.getFullYear();
        today = yyyy + '-' + mm + '-' + dd;
        console.log("test 2", country);
        fetch(`https://webhooks.mongodb-stitch.com/api/client/v2.0/app/covid-19-qppza/service/REST-API/incoming_webhook/countries_summary?country=${country}&min_date=2020-04-22&max_date=${today}`)
        .then(response => response.json())
        .then(days => {
            days.forEach(day => {
                ys.push(day.confirmed);
                xs.push(day.date);
            })
        })
        
        console.log("xs", xs);
        console.log("ys", ys);
        console.log(`https://webhooks.mongodb-stitch.com/api/client/v2.0/app/covid-19-qppza/service/REST-API/incoming_webhook/countries_summary?country=${country}&min_date=2020-04-22&max_date=${today}`);
        return { xs, ys };
    };
}); // Edit: final closing brackets were missing

event.preventDefault() 在表单提交时丢失:

您的图表未出现的原因是您的表单提交中缺少 event.preventDefault() 语句。因此,您的表单正在发送 HTTP 请求(默认操作)而不是执行您的代码。

我编辑了你的代码:

  1. 已添加 event.preventDefault() 在表单提交时
  2. 在函数外声明变量以避免重复声明
  3. 消除了 async 功能,因为 fetch() 是一个 Promise(已经像异步回调一样工作,等待来自服务器的响应)
  4. 重新排列顺序:
    首先在表单提交时调用 dataToGraph()(使用 fetch() 获取数据)
    然后,当 fetch()-API 返回数据(异步)时,调用 graphit()
  5. 重新分配数据到您的图表(x 轴和 y 轴数据)和顶部标签,然后update()图表
  6. 为 chart.js 的最终版本改编代码 v3.5.1 以提高性能(v3.x 不兼容 v2.x):
  7. 为意大利 dataToGraph()
  8. 加载初始数据

运行 代码片段 并输入一个国家 ('Italy', 'G德国', ....)
(区分大小写:第一个字母必须是大写字母)

// define all variables here outside functions
// in order to avoid re-assigning multiple times
let xs = [];
let ys = [];
let dataset = {};

dataset.xs = xs;
dataset.ys = ys;

let country = "Italy";

let today = new Date();
let dd = String(today.getDate()).padStart(2, '0');
let mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
let yyyy = today.getFullYear();
today = yyyy + '-' + mm + '-' + dd;

const delayInMilliseconds = 100000;

const ctx = document.getElementById('myChart').getContext('2d');

const myChart = new Chart(ctx, {
    type: 'line',
    data: {
        labels: dataset.xs,
        datasets: [{
            label: `Covid 19 Confirmed cases in ${country}`,
            data: dataset.ys,
            backgroundColor: ['rgba(255, 99, 132, 0.2)'],
            borderColor: ['rgba(255, 99, 132, 1)'],
            borderWidth: 1,
            fill: false,
        }]
    },
    options: {
        responsive: true,
        maintainAspectRatio: false,
        scales: {
            yAxes: { // <-- axis is not array '[{' anymore, now object '{'
                scaleLabel: {
                    display: true,
                    labelString: 'Confirmed Cases'
                }
            },
            xAxes: { // <-- axis is not array '[{' anymore, now object '{'
                scaleLabel: {
                    display: true,
                    labelString: 'Date'
                }
            }
        }
    }
});

// Load initial data for Italy
document.getElementById('country').value = country;
dataToGraph();

// here goes your Event-Listener with function as argument;
document.getElementById('country_form').addEventListener('submit', dataToGraph);

function dataToGraph(event) {
  if (event) event.preventDefault(); // <-- this was missing
  
  country = document.getElementById('country').value;
  // console.log("test 1", country);
  
  // give feedback to user that data is loading in background
  myChart.data.datasets[0].label =  `loading ... ${country}`;
  myChart.update();

  // set all variables to empty again:
  xs = [];
  ys = [];
  dataset = {};
  dataset.xs = xs;
  dataset.ys = ys;

  // fetch() is a Promise, i.e. it is like an async callback already,
  // hence no need to call async again.
  fetch(`https://webhooks.mongodb-stitch.com/api/client/v2.0/app/covid-19-qppza/service/REST-API/incoming_webhook/countries_summary?country=${country}&min_date=2020-04-22&max_date=${today}`)
    .then(response => response.json())
    .then(days => {
        days.forEach(day => {
            ys.push(day.confirmed);
            xs.push(day.date);
        });
        dataset.xs = xs;
        dataset.ys = ys;
        // console.log("xs", xs);
        // console.log("ys", ys);
        // console.log(`https://webhooks.mongodb-stitch.com/api/client/v2.0/app/covid-19-qppza/service/REST-API/incoming_webhook/countries_summary?country=${country}&min_date=2020-04-22&max_date=${today}`);
        // console.log(dataset);
        
        // now you can graph it
        graphit();
    })
    //return { xs, ys };
};


function graphit() {
    document.getElementById('myChart').style.display = "block";
    // const dataset = dataToGraph();

    // console.log("dataset.xs", dataset.xs);
    // console.log("dataset.ys", dataset.ys);

    // re-assign the datasets again (x- and y-axis)
    myChart.data.labels = dataset.xs;
    myChart.data.datasets[0].data = dataset.ys;
    myChart.data.datasets[0].label =  `Covid 19 Confirmed cases in ${country}`;
    // now update your chart
    myChart.update();
};
<!-- <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.min.js"></script> -->

  <!-- get the latest version of Chart.js, now at v3.5.1 -->
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

  <div id="banner">
    <div id="banner_details">
      <h2>CoData</h2>
    </div>
  </div>

 <div id="one_line">
   <div id="main_title">
     <h1>Covid-19 Data</h1>
   </div>

   <div id="user_query_data">
     <form id="country_form">
       <input type="text" placeholder="Country" id="country">
       <input type="submit" value="Search">
     </form>
   </div>
 </div>

 <div id="confirmed_graph">
   <canvas id="myChart" height="500" width="300"></canvas>
 </div>

最后的注释:
您可能会考虑将 x: { type: 'time' ... 功能添加到您的图表中,这样可以更好地显示 x 坐标轴标签(日期)。有关更多详细信息,请参阅我的回答 chart.js time series

顺便说一下:不错 API - 我喜欢

欢迎使用堆栈溢出