简体   繁体   中英

Chartjs / Javascript - My function not returning array properly, but console logs okay

Currently using Angular JS and ChartJS to try and put a chart on my page. The data is requested through a route in NodeJS and then the functions loop through the leads that are in the response and try to count how many were created on each day of the month.

When I console log the leadsPerDay it returns an array with everything how I would expect it, but the chart doesn't seem to render the dots appropriately. They all fall on the bottom which tells me it's finding my array because if I take it out, no dots. If I manually put in the array, it renders properly.

var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
  type: 'line',
  data: {
    labels: getDaysInMonth(currentMonth, currentYear),
    datasets: [{
      label: '# new leads created',
      data: getLeadsForMonth(currentMonth, currentYear),
      backgroundColor: [
        'rgba(255, 99, 132, 0.2)'
      ],
      borderColor: [
        'rgba(255,99,132,1)'
      ],
      borderWidth: 1
    }]
  },
  options: {
    scales: {
      yAxes: [{
        ticks: {
          beginAtZero: true
        }
      }]
    }
  },
  maintainAspectRatio: false
});

function getDaysInMonth(month, year) {
  var date = new Date(year, month, 1);
  var dates = [];
  while (date.getMonth() === month) {
    var currentDate = new Date(date).toISOString().replace(/T.*/, '').split('-').reverse().join('-');
    var catDate = currentDate.replace(/-2017/g, '').replace(/-/g, '/').split('/').reverse().join('/');;
    dates.push(catDate);
    date.setDate(date.getDate() + 1);
  }
  return dates;
}

function getLeadsForMonth(month, year) {

  // Create empty array to put leadCount in
  var leadsPerDay = new Array();

  /* Use $http.get to fetch contents*/
  $http.get('/pipedrive/getLeadsForMonth', function() {}).then(function successCallback(response) {

    // Loop through each lead and index them based on date
    var leads = response.data.data[0].deals;
    // Set date to first of the month
    var date = new Date(year, month, 1);
    // Define the month for the loop
    var currentMonth = date.getMonth();

    // Loop through the days in the month
    while (date.getMonth() === currentMonth) {
      // Save the date
      var currentDate = new Date(date).toISOString().replace(/T.*/, '');
      date.setDate(date.getDate() + 1);
      leadCount = 0;
      // Loop through each lead and search data for date
      for (i = 0; i < leads.length; i++) {
        if (leads[i].add_time.includes(currentDate)) {
          leadCount++
        }
      }
      leadsPerDay.push(leadCount);
    }
  }, function errorCallback(response) {
    console.log('There was a problem with your GET request.')
  });
  console.log(leadsPerDay);
  return leadsPerDay;
}

The problem here is that the chart is being rendered before the data is actually returned from your function, because you are making an asynchronous call to your endpoint.

Here is the current flow.

1) You instantiate a new chart which then synchronously calls 2 functions to get the labels ( getDaysInMonth ) and data ( getLeadsForMonth ).

2) The label function returns no problem with your label data. The data function however then does an async call to an endpoint to acquire data. $http.get returns a Promise and when it is ready you are processing the result and building your data array. Unfortunately at this point, the initial call to getLeadsForMonth has already returned with an empty array.

The reason you are able to see your data using console.log is probably just a timing issue. By the time the browser executes that statement chances are the $http.get already returned (especially true if you are running this on locahost) and the data is now present in the array (however the chart is already rendered so it does not show it).

Since you are asynchronously acquiring your data you have a couple of options.

1) Wait and create your chart after the data is acquired. You could do this by moving the chart creation code inside your $http.get callback. Something like this...

function getDaysInMonth(month, year) {
  var date = new Date(year, month, 1);
  var dates = [];
  while (date.getMonth() === month) {
    var currentDate = new Date(date).toISOString().replace(/T.*/, '').split('-').reverse().join('-');
    var catDate = currentDate.replace(/-2017/g, '').replace(/-/g, '/').split('/').reverse().join('/');;
    dates.push(catDate);
    date.setDate(date.getDate() + 1);
  }
  return dates;
};

function createChart(month, year) {
  // generate the labels
  var labels = getDaysInMonth(month, year),

  // Create empty array to put leadCount in
  var leadsPerDay = new Array();

  /* Use $http.get to fetch contents*/
  $http.get('/pipedrive/getLeadsForMonth', function() {}).then(function successCallback(response) {

    // Loop through each lead and index them based on date
    var leads = response.data.data[0].deals;
    // Set date to first of the month
    var date = new Date(year, month, 1);
    // Define the month for the loop
    var currentMonth = date.getMonth();

    // Loop through the days in the month
    while (date.getMonth() === currentMonth) {
      // Save the date
      var currentDate = new Date(date).toISOString().replace(/T.*/, '');
      date.setDate(date.getDate() + 1);
      leadCount = 0;
      // Loop through each lead and search data for date
      for (i = 0; i < leads.length; i++) {
        if (leads[i].add_time.includes(currentDate)) {
          leadCount++
        }
      }
      leadsPerDay.push(leadCount);
    }

    var ctx = document.getElementById("myChart");
    var myChart = new Chart(ctx, {
      type: 'line',
      data: {
        labels: labels,
        datasets: [{
          label: '# new leads created',
          data: leadsPerDay,
          backgroundColor: [
            'rgba(255, 99, 132, 0.2)'
          ],
          borderColor: [
            'rgba(255,99,132,1)'
          ],
          borderWidth: 1
        }]
      },
      options: {
        scales: {
          yAxes: [{
            ticks: {
              beginAtZero: true
            }
          }]
        }
      },
      maintainAspectRatio: false
    });
  }, function errorCallback(response) {
    console.log('There was a problem with your GET request.')
  });
};

createChart(currentMonth, currentYear);

2) Create an empty chart and then use the .update() prototype method to re-render the chart when the data is acquired. Something like this...

var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
  type: 'line',
  data: {
    labels: getDaysInMonth(currentMonth, currentYear),
    datasets: [{
      label: '# new leads created',
      data: [],
      backgroundColor: [
        'rgba(255, 99, 132, 0.2)'
      ],
      borderColor: [
        'rgba(255,99,132,1)'
      ],
      borderWidth: 1
    }]
  },
  options: {
    scales: {
      yAxes: [{
        ticks: {
          beginAtZero: true
        }
      }]
    }
  },
  maintainAspectRatio: false
});

getLeadsForMonthAndUpdateChart(myChart, currentMonth, currentYear);

function getLeadsForMonthAndUpdateChart(chart, month, year) {
  // Create empty array to put leadCount in
  var leadsPerDay = new Array();

  /* Use $http.get to fetch contents*/
  $http.get('/pipedrive/getLeadsForMonth', function() {}).then(function successCallback(response) {

    // Loop through each lead and index them based on date
    var leads = response.data.data[0].deals;
    // Set date to first of the month
    var date = new Date(year, month, 1);
    // Define the month for the loop
    var currentMonth = date.getMonth();

    // Loop through the days in the month
    while (date.getMonth() === currentMonth) {
      // Save the date
      var currentDate = new Date(date).toISOString().replace(/T.*/, '');
      date.setDate(date.getDate() + 1);
      leadCount = 0;
      // Loop through each lead and search data for date
      for (i = 0; i < leads.length; i++) {
        if (leads[i].add_time.includes(currentDate)) {
          leadCount++
        }
      }
      leadsPerDay.push(leadCount);
    }

    // add the data to the chart and re-render
    chart.data.datasets[0].data = leadsPerDay;
    chart.update();
  }, function errorCallback(response) {
    console.log('There was a problem with your GET request.')
  });
};

Here is a codepen example that demonstrates the second option (updating the chart with new data) for you to look at as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM