0

I have created fiddle with mock sample data that is formatted the same way as the AJAX response data.

When I try to implement my script into a SharePoint script editor and debug it, it tells me that data is undefined outside of my loadChartData()

I pass the data variable through the function scope but it still returns undefined, but in the success function of my ajax call it is defined?

function loadChartData() {
    $.ajax({
        url: uri,
        method: "GET",
        headers: {
            "Accept": "application/json; odata=verbose"
        },
        success: function(data) {
            if (data.d != null && data.d != undefined && data.d.results.length > 0) {
                
            }
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            alert("Status: " + textStatus);
            alert("Error: " + errorThrown);
        }

    });
}
loadChartData();

$( document ).ready(function() {

function insertChartData(data) {
    var msrCount = {
        Yes: 0,
        No: 0
    };
    var trCount = {
        Yes: 0,
        No: 0
    };
    var mmCount = {
        Yes: 0,
        No: 0
    };


    for (i = 0; i < data.d.results.length; i++) {
        if (data[i].Deliverable === "MSR") {
            switch (data[i].Retained) {
                case 'Yes':
                    msrCount.Yes++;
                    break;
                case 'No':
                    msrCount.No++;
                    break;
            }
            //console.log(msrCount);
        }
        if (data[i].Deliverable === "Trip Report") {
            switch (data[i].Retained) {
                case 'Yes':
                    trCount.Yes++;
                    break;
                case 'No':
                    trCount.No++;
                    break;
            }
        }
        if (data[i].Deliverable === "Meeting Minutes") {
            switch (data[i].Retained) {
                case 'Yes':
                    mmCount.Yes++;
                    break;
                case 'No':
                    mmCount.No++;
                    break;
            }
        }

    }

    const totMSRCount = (msrCount.Yes + msrCount.No);
    const totTRCount = (trCount.Yes + trCount.No);
    const totMMCount = (mmCount.Yes + mmCount.No);

    var completeMSRCount = ((msrCount.Yes / totMSRCount) * 100).toFixed(2);
    var completeTRCount = ((trCount.Yes / totTRCount) * 100).toFixed(2);
    var completeMMCount = ((mmCount.Yes / totMMCount) * 100).toFixed(2);

    var barMSR = new ProgressBar.Circle(container, {
        color: '#aaa',
        // This has to be the same size as the maximum width to
        // prevent clipping
        strokeWidth: 4,
        trailWidth: 1,
        easing: 'easeInOut',
        duration: 1400,
        text: {
            autoStyleContainer: false
        },
        from: {
            color: '#aaa',
            width: 1
        },
        to: {
            color: '#333',
            width: 4
        },
        // Set default step function for all animate calls
        step: function(state, circle) {

            var value = Math.round(circle.value() * 100);
            if (value === 0) {
                circle.setText('');
            } else {
                circle.setText(value + "%");
            }
            if (value <= 50) {
                circle.path.setAttribute('stroke', 'red');
                circle.path.setAttribute('stroke-width', state.width);
            }
            if (value > 50 && value <= 75) {
                circle.path.setAttribute('stroke', 'yellow');
                circle.path.setAttribute('stroke-width', state.width);
            }
            if (value > 75) {
                circle.path.setAttribute('stroke', 'green');
                circle.path.setAttribute('stroke-width', state.width);
            }
        }
    });
    barMSR.text.style.fontFamily = '"Raleway", Helvetica, sans-serif';
    barMSR.text.style.fontSize = '2rem';

    barMSR.animate(msrCount.Yes / totMSRCount);

    var barTR = new ProgressBar.Circle(container1, {
        color: '#aaa',
        // This has to be the same size as the maximum width to
        // prevent clipping
        strokeWidth: 4,
        trailWidth: 1,
        easing: 'easeInOut',
        duration: 1400,
        text: {
            autoStyleContainer: false
        },
        from: {
            color: '#aaa',
            width: 1
        },
        to: {
            color: '#333',
            width: 4
        },
        // Set default step function for all animate calls
        step: function(state, circle) {

            var value = Math.round(circle.value() * 100);
            if (value === 0) {
                circle.setText('');
            } else {
                circle.setText(value + "%");
            }
            if (value <= 50) {
                circle.path.setAttribute('stroke', 'red');
                circle.path.setAttribute('stroke-width', state.width);
            }
            if (value > 50 && value <= 75) {
                circle.path.setAttribute('stroke', 'yellow');
                circle.path.setAttribute('stroke-width', state.width);
            }
            if (value > 75) {
                circle.path.setAttribute('stroke', 'green');
                circle.path.setAttribute('stroke-width', state.width);
            }
        }
    });
    barTR.text.style.fontFamily = '"Raleway", Helvetica, sans-serif';
    barTR.text.style.fontSize = '2rem';

    barTR.animate(trCount.Yes / totTRCount);

    var barMM = new ProgressBar.Circle(container2, {
        color: '#aaa',
        // This has to be the same size as the maximum width to
        // prevent clipping
        strokeWidth: 4,
        trailWidth: 1,
        easing: 'easeInOut',
        duration: 1400,
        text: {
            autoStyleContainer: false
        },
        from: {
            color: '#aaa',
            width: 1
        },
        to: {
            color: '#333',
            width: 4
        },
        // Set default step function for all animate calls
        step: function(state, circle) {
            var value = Math.round(circle.value() * 100);
            if (value === 0) {
                circle.setText('');
            } else {
                circle.setText(value + "%");
            }
            if (value <= 50) {
                circle.path.setAttribute('stroke', 'red');
                circle.path.setAttribute('stroke-width', state.width);
            }
            if (value > 50 && value <= 75) {
                circle.path.setAttribute('stroke', 'yellow');
                circle.path.setAttribute('stroke-width', state.width);
            }
            if (value > 75) {
                circle.path.setAttribute('stroke', 'green');
                circle.path.setAttribute('stroke-width', state.width);
            }
        }
    });
    barMM.text.style.fontFamily = '"Raleway", Helvetica, sans-serif';
    barMM.text.style.fontSize = '2rem';

    barMM.animate(mmCount.Yes / totMMCount);

    $('#undr_txt1').html("Retained: (" + msrCount.Yes + ") | " + "Not Retained: (" + msrCount.No + ")");
    $('#undr_txt2').html("Retained: (" + trCount.Yes + ") | " + "Not Retained: (" + trCount.No + ")");
    $('#undr_txt3').html("Retained: (" + mmCount.Yes + ") | " + "Not Retained: (" + mmCount.No + ")");
}
insertChartData();
});

Here is the local scope of my success:

enter image description here

Why can't I access it?

5
  • Where are you calling loadChartData() function? Are you calling insertChartData() function from success of loadChartData() function? Aug 19 at 13:08
  • Check my updated code, I added all
    – BeerusDev
    Aug 19 at 13:09
  • Is it complete code? Where are you calling loadChartData() function? I don't see any calling between loadChartData() & insertChartData() functions? Aug 19 at 13:11
  • If I call it before insertChartData() it still says Data is undefined
    – BeerusDev
    Aug 19 at 13:18
  • Complete code has been added
    – BeerusDev
    Aug 19 at 13:50
1

Yeah, the problem is that when you define your insertChartData function, you are saying you are expecting it to get data passed in, but when you actually call it, you are not passing anything to the function.

$(document).ready(function () {

    // putting insertChartData(data) here does not pass data into the function.
    // this is the function definition, so what it is saying is that
    // the function is _expecting_ to get data passed in _when it is called_.
    // again, this is the part where you are defining the function, not actually
    // calling and executing it
    function insertChartData(data) {
        //
        // all your code in the function
        // ...
    }

    // here is where you are _calling_ insertChartData() to start it executing,
    // but you are not passing anything into it when you call it.  you should be
    // calling it like: insertChartData(someData)
    insertChartData();
});

The reason your fiddle works is that you define data as a variable in the global scope, so it is accessible from anywhere in your code, but after your $.ajax call, the data returned from SharePoint is only accessible in the local scope of your success function. (See your own screenshot: it says "Scope -> Local")

success: function (data) {
    if (data.d != null && data.d != undefined && data.d.results.length > 0) {
        // data here is not a global variable, it only exists
        // within the scope of this success function unless you
        // either store it in some globally available place
        // or pass it to another function. so what you should
        // probably do is, right here inside the success function
        // once you have the data:

        // pass the data to your function that is expecting it
        insertChartData(data);
    }
},

What I would do is

// define loadChartData in the global scope so it is accessible from anywhere

function loadChartData() {
    var uri = // whatever your uri is
    $.ajax({
        url: uri,
        method: "GET",
        headers: {
            "Accept": "application/json; odata=verbose"
        },
        success: function (data) {
            if (data.d != null && data.d != undefined && data.d.results.length > 0) {:
                // pass the data to your function that is expecting it
                insertChartData(data);
            }
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            alert("Status: " + textStatus);
            alert("Error: " + errorThrown);
        }
    });
}

// define insertChartData in the global scope so it is accessible from anywhere

function insertChartData(data) {
    //
    // all your code in the function
    // ...
}

$(document).ready(function () {

    // start off the chain of events by calling
    loadChartData();

    // once loadChartData's success function _has_ the data, 
    // it will pass it to your insertChartData function
});

To address your comment on the other answer:

It works until I get to the first if statement inside my for loop. Tells me (Cannot read property 'Deliverable' of undefined)

That's because you are trying to index directly into data, but data is not the array, data.d.results is the array.

You'll either have to change all of the places where you have

data[i]

to be

data.d.results[i]

or (because that will end up with some long, difficult to read code), just put data.d.results into another shorter named variable, and use that:

var results = data.d.results;

for (i = 0; i < results; i++) {
    if (results[i].Deliverable === "MSR") {
        switch (results[i].Retained) {
            case 'Yes':
                msrCount.Yes++;
                break;
            case 'No':
                msrCount.No++;
                break;
        }
    }

    // etc, etc...
}
1
  • When creating an item object to post to a SharePoint task list, what is the proper way to create the item that you set as data? I keep getting a 400 error and I think it is because of my AssignedTo value but I am not 100% sure how to assign that value as I cannot find any documentation.
    – BeerusDev
    Aug 25 at 19:58
1

Follow below pattern for code to work:

$(document).ready(function() {
    var endpointUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('ListName')/items";
    loadChartData(endpointUrl);
});

function loadChartData(uri) {
    $.ajax({
        url: uri,
        method: "GET",
        headers: {
            "Accept": "application/json;odata=verbose"
        },
        success: function(data) {
            if (data.d && data.d.results && data.d.results.length) {
                insertChartData(data);
            }
        },
        error: function(error) {
            console.log(error);
        }
    });
}

function insertChartData(data) {
    ...
}
2
  • Thank you! It works until I get to the first if statement inside my for loop. Tells me (Cannot read property 'Deliverable' of undefined)
    – BeerusDev
    Aug 19 at 16:10
  • @BeerusDev addressed your comment here in my answer Aug 19 at 16:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.