简体   繁体   中英

Function running with each loop iteration, instead of only the last

I have a function renderActualChart() that renders a chart on my screen.

That requires an input with all the chart settings, since each chart is dynamic based on the value selected from the table to chart i call a forEach loop on the promise i get back from Firebase with the user's data.

I need renderLabsCharts(doc) to run all of its loops FIRST... then i want renderActualChart() to run since the data will be ready at that point.

I have tried using a counter to only run that function on the last loop iteration but when i run in browser it still hits every single forEach loop, i don't get it....

var itemsProcessed = 0;
var size ;
function getDataFromFirebase(){

    console.log('uid before results call: ' + userUid)


db.collection('lab-results')
.where("uid", "==", userUid)
.orderBy("labTestDate", "desc")
.get()
.then((snapshot) => {
    size = snapshot.size;
    snapshot.docs.forEach(doc => {

        itemsProcessed++;
        console.log('itemProcessed: ' + itemsProcessed);
        console.log('size: ' + size)

        console.log(doc.data());


        //Render results for tables and dropdowns on screen
        renderLabResults(doc);
        renderLabResultDeleteList(doc);

        var el = document.getElementById('chart-form');
        if(el){
            //Only render the chart when the drop down is changed
            el.addEventListener("change", function() {
                console.log(' YYYYYY RENDER LABS CALLED YYYYYYYY')
                //Call builder to create the input file to build the chart with the selected lab data
                renderLabsCharts(doc);

                if(itemsProcessed === size){
                    console.log('XXXXXXXX LAST ITEM XXXXX')
                    //Call the code to render the chart, which needs the output from renerLabsCharts that contains the data values for the chart
                     renderActualChart();
                }else{
                    console.log('WHY AM I NEVER HITTING HERE?' + itemsProcessed + ' ' + size)
                }

        });

        }

    })

})
////////////////////////////////////////////////////////////////////////////
// CHARTS
//////////////////////////////////////////////




var labelsString = ''
var dataString = ''
var chartLabel = ''

const chartForm = document.querySelector('#chart-form');


function renderLabsCharts(doc){

    var labTime = doc.data().labTestDate;
     var labTimeDate = labTime.toDate();
     var clearTestDate = moment(labTimeDate).format('DDMMMYYYY');

 console.log('selected value for chart: ' + chartForm.labsLoggedList.value)
 console.log('labTestName: '+ doc.data().labTestName) 


 if(doc.data().labTestName == chartForm.labsLoggedList.value){

    chartLabel = doc.data().labTestName + ' ' + doc.data().labUnits;
    labelsString = labelsString + '"' + clearTestDate + '",';
    dataString = dataString + doc.data().labResult + ',';
    console.log('labelsString: ' + labelsString)
    console.log('dataString: ' + dataString)
    }



}

function renderActualChart(){


    console.log('render chart called')
    console.log('labelsString: ' + labelsString)
    console.log('dataString: ' + dataString)
  //remove comma from front
  //labelsString = labelsString.replace(/(,$)/g, "");
  //dataString = dataString.replace(/,$/g, "");
 // Bar chart
 var chartData = {
    type: 'bar',
    data: {
    //labels: [labelsString],
    labels: ["12DEC2012","11NOV2011"],
    datasets: [
        {
        label: chartLabel,
        backgroundColor: ["#c45850", "#c45850","#c45850","#c45850","#c45850"],
        data: [47,30,100,33,11]
        }
    ]
    },
    elements: {
        rectangle: {
            borderWidth: 2,
        }
    },
    responsive: true,
    options: {
    legend: { display: true },
    title: {
        display: true,
        text: 'Historical Lab Results'
    }
    }
}

    new Chart(document.getElementById("bar-chart-labs"), chartData );

THIS IS WHAT I GET ON INITAL PAGE LOAD

itemProcessed: 1
appLabs.js:188 size: 3
appLabs.js:137 labTime: Timestamp(seconds=1355328660, nanoseconds=0)
appLabs.js:138 labTimeDate: Wed Dec 12 2012 11:11:00 GMT-0500 (Eastern Standard Time)
appLabs.js:143 clearTestDate: 2012-12-12 11:11 AM
appLabs.js:187 itemProcessed: 2
appLabs.js:188 size: 3
appLabs.js:137 labTime: Timestamp(seconds=1355328660, nanoseconds=0)
appLabs.js:138 labTimeDate: Wed Dec 12 2012 11:11:00 GMT-0500 (Eastern Standard Time)
appLabs.js:143 clearTestDate: 2012-12-12 11:11 AM
appLabs.js:187 itemProcessed: 3
appLabs.js:188 size: 3
appLabs.js:137 labTime: Timestamp(seconds=1321027860, nanoseconds=0)
appLabs.js:138 labTimeDate: Fri Nov 11 2011 11:11:00 GMT-0500 (Eastern Standard Time)
appLabs.js:143 clearTestDate: 2011-11-11 11:11 AM

THEN WHEN I CHANGE THE DROP DOWN, I ONLY GET THIS

 YYYYYY RENDER LABS CALLED YYYYYYYY
appLabs.js:510 selected value for chart: GLUCOSE
appLabs.js:511 labTestName: GLUCOSE
appLabs.js:519 labelsString: "12Dec2012",
appLabs.js:520 dataString: 11111,
appLabs.js:206 XXXXXXXX LAST ITEM XXXXX
appLabs.js:530 render chart called
appLabs.js:531 labelsString: "12Dec2012",
appLabs.js:532 dataString: 11111,
appLabs.js:201  YYYYYY RENDER LABS CALLED YYYYYYYY
appLabs.js:510 selected value for chart: GLUCOSE
appLabs.js:511 labTestName: SODIUM
appLabs.js:206 XXXXXXXX LAST ITEM XXXXX
appLabs.js:530 render chart called
appLabs.js:531 labelsString: "12Dec2012",
appLabs.js:532 dataString: 11111,
appLabs.js:201  YYYYYY RENDER LABS CALLED YYYYYYYY
appLabs.js:510 selected value for chart: GLUCOSE
appLabs.js:511 labTestName: GLUCOSE
appLabs.js:519 labelsString: "12Dec2012","11Nov2011",
appLabs.js:520 dataString: 11111,111111,
appLabs.js:206 XXXXXXXX LAST ITEM XXXXX
appLabs.js:530 render chart called
appLabs.js:531 labelsString: "12Dec2012","11Nov2011",
appLabs.js:532 dataString: 11111,111111,

because of closure itemsProcessed inside callback function of change event always returns the last value of itemsProcessed in the loop,

pass itemsProcessed into a closure could solve problem

if(el){
    (function(index) {
      el.addEventListener("change", function() {
         console.log(' YYYYYY RENDER LABS CALLED YYYYYYYY')
          //Call builder to create the input file to build the chart with the selected lab data
           renderLabsCharts(doc);

           if(index=== size){
            console.log('XXXXXXXX LAST ITEM XXXXX')
            //Call the code to render the chart, which needs the output from renerLabsCharts that contains the data values for the chart
                         renderActualChart();
            }else{
                        console.log('WHY AM I NEVER HITTING HERE?' + itemsProcessed + ' ' + size)
           }

     });
    }(itemsProcessed)
}

So the problem is, like you said, that the compatison takes place only after the loop is done, because drop-down change is being done at a later time and itemsProcessed is still in the same context it was when the loop ran for the last times- eg always equals to size.

So, to solve this, first take the whole call-back function you pass to addEventListener outside:

function dropdownChangeCallback(itemsDone){
    console.log(' YYYYYY RENDER LABS CALLED YYYYYYYY')
    renderLabsCharts(doc);

    if(itemsDone === size){
       console.log('XXXXXXXX LAST ITEM XXXXX')
       renderActualChart();
    }else{
       console.log('WHY AM I NEVER HITTING HERE?' + itemsDone + ' ' + size)
}

Then, inside your loop (and inside the if(el) ), you use bind to pass the value you need, like this:

el.addEventListener("change", dropdownChangeCallback.bind(itemsProcessed));

When the callback is called, it will use the value of the binded variable (in this case- itemsProcessed) that it had at the time of binding.

To read more about binding, context and more- you can refer here: Bind variables to callback function , or here for easier-to-read info including some extra stuff that are important to know about JS functions.

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