Search code examples
tin-can-api

Trying to pull certain data pieces of an LRS record, need catch-try assistance


I have a script that is 90% complete and working. I'm using the older code for getting LRS statements. It is the one that uses tincan.js. I am trying to pull down and parse the following: Actor, verb, object, timestamp and the id under contextActivities. It is the last one that is giving me fits. Could you please look at my last catch/try statement and tell me where I'm going wrong? Thank you.

<!DOCTYPE  html>
<!--Parsing "resumed" statements-->
<html lang='en'> 
    <head> 
        <meta charset='UTF-8'> 
        <title>Get my Statements</title> 
        <script type="text/javascript" src="build/tincan.js"></script> 
    </head> 
    <body> 
        <h1>Get statements  101</h1> 
        <div id='response'></div>
        <script>
      var lrs;

try {
    lrs = new TinCan.LRS(
        {

            endpoint: "https://lrs.adlnet.gov/xapi/",
            username: "xapi-tools",
            password: "xapi-tools",
            allowFail: false
        }
    );
}
catch (ex) {
    console.log("Failed to setup LRS object: " + ex);
    // TODO: do something with error, can't communicate with LRS
}


//Pulls all of the resumed statements

lrs.queryStatements(
    {
        params: {
            verb: new TinCan.Verb(
                {
                    id: "http://adlnet.gov/expapi/verbs/completed"
                }
            ),
            since: "2016-01-05T08:34:16Z"
        },
        callback: function (err, sr) {
            if (err !== null) {
                console.log("Failed to query statements: " + err);
                // TODO: do something with error, didn't get statements
                return;
            }

            if (sr.more !== null) {
                // TODO: additional page(s) of statements should be fetched
            }

            var container =  document.getElementById('response');
            //container.innerHTML = (err !== null ? 'ERROR' : JSON.stringify(sr.statements));
            container.innerHTML = (err !== null ? 'ERROR' : parseMyData(sr));
        }
    }
);


parseMyData = function(result) {
            var statements = result.statements;
            var output = '';
            var name,verb,activity, timestamp, context;
            for(var i=0;i<statements.length;i++){
                // check the statement for a usable name value
                // (priority = actor.name, actor.mbox, actor.account.name)
                if(statements[i].actor.name != null && statements[i].actor.name != "") {
                    name = statements[i].actor.name
                }else if(statements[i].actor.mbox != null && statements[i].actor.mbox != "") {
                    name = statements[i].actor.mbox
                }else{
                    name = statements[i].actor.account.name
                }
                // check the statement for a usable verb value
                // (priority = verb.display['en-US'], verb.id)
                try{
                    verb = statements[i].verb.display['en-US'];
                }catch(e){
                    verb = statements[i].verb.id;
                }
                // check the activity for a usable value
                // (priority = definition.name['en-US'], id)
                try{
                    activity = statements[i].target.definition.name['en-US'];
                }catch(e){
                    activity = statements[i].target.id;
                }
                try{
                    timestamp = statements[i].timestamp;
                }catch(e){
                    timestamp = statements[i].timestamp;
                }

                try{
                    context = statements[i].target.contextActivities.other['id'];
                }catch(e){
                    context = statements[i].activity.other['id'];
                }

                output +=   name + ' - ' +
                            verb + ' - ' + 
                            activity + ' - ' +
                            timestamp + ' - ' +
                            context +
                            '<br>' 
            }
            return output;
}

        </script> 
    </body> 
</html>

Solution

  • You are trying to access a property that will never exist:

    statements[i].target.contextActivities

    The last portion of that will exist in statements[i].context when it exists, which is not always unless you know the statement ahead of time. Pretty much all of the properties should be checked for null before accessing them, doing so will allow you to remove your try/catch blocks. The property names themselves are very stable and the library explicitly assigns null values to known properties. Additionally the other property will hold an array of Activities (when it is populated) so you should access them by index, so contextActivities.other[0].id etc.

    For the target property you should check that it is an instance of a particular class as it can contain multiple types of objects (so can actor but they effectively match). In general for this specific task you may also want to leverage the toString methods where possible, they do very similar work.