Tutorial 201 - Question-Level Events and Public Methods

An over view of events and public methods that are Question-specific, rather than assessment-wide. 

 

Introduction

When coding an assessment, it’s sometimes useful to handle events and query data at the Question level, in addition to the assessment level. For example, you may want to parse Question and/or response data each time it is changed or validated. Or, you may want to trigger events programmatically. Learnosity supports events and public methods that allow you to query data, and trigger or handle events, for one or more Questions in any assessment.

This tutorial is a basic overview of these features and will include code snippets for several of the events and methods discussed in the documentation. As part of our 200 series, this tutorial assumes that you are comfortable with JavaScript, and you are familiar with the Learnosity Items API and/or Questions API.

 

Binding and Trapping Events

Event listeners can be added to any or all Questions in an assessment using one of two methods. The first is the on() method—a common mechanism found in many frameworks, including Backbone.js, after which this approach was modelled. The on() method triggers its callback every time a corresponding event occurs, until the listener is explicitly removed using the off()method.

The second approach is to bind a listener to a Question for a single occurrence of the appropriate event, using the once() method. Instead of you removing the binding at the time of your choosing, the once() method automatically removes the event listener from the Question after the first event is trapped.

Both methods take two arguments: an event to listen for, and a callback function to execute when that event is received. Both methods can listen for the following Question-level events:

  • changed indicates the student initiated or changed a response to the Question,
  • validated the Question was validated by Learnosity to determine if the student response is correct or incorrect, or
  • masked the student masked a distractor, such as striking through it, as a visual cue to eliminate it from consideration while working through the Question.

 

Snippet 1: Viewing Question and Response Data

Note Uses the validated event, and the once()getQuestion(), and getResponse() methods

The following snippet shows a jQuery each loop using the once() method to apply a listener to every Question in the itemsApp instance of the Items API. The first time the listener detects the validated event, the sample showQuestionAndResponse function is triggered and logs to the console the Question and response JSON returned by the getQuestion() and getResponse() public methods:

$.each(itemsApp.questions(), function( responseID, question ) {
    question.once("validated", showQuestionAndResponse);
    function showQuestionAndResponse() {
        console.log(question.getQuestion());
        console.log(question.getResponse());
    }
}

This can be handy for debugging, as you can inspect the Question data and validation object along with the student response. Because this snippet uses the once() method, you don’t need to remove the callback manually.

 

Snippet 2: Show Score Upon Validation

Note Uses the on()isValid()getScore()getMetadata(), and off()methods.

The snippet below binds the validated event to each Question using the on() method. When validated, the score and max_score are retrieved from the Question data using the getScore() method. The isValid() method is also used to check to see if the student’s response is correct. If so, a congratulatory message is prepended to the score.

The getMetadata() method is used to parse the metadata object from which the sheet_reference (the ID of the DOM element containing the item) is retrieved. If the required div already exists, the score is added to the div. Otherwise, the div and score are both appended to the Item parent.

$.each(itemsApp.questions(), function(responseID, question) {
    question.on("validated", showScore);

    function showScore() {
        var score = question.getScore();
        var scoreString = (question.isValid()) ?
            "Congratulations! " : "";
        scoreString += "Score: " + score.score + " of " +
            score.max_score;

        var meta = question.getMetadata();
        var item = $(".learnosity-item[data-reference=" +
            meta.sheet_reference + "]");
        var scoreDiv = item.find("div.score");

        if (scoreDiv.length) {
            scoreDiv.html(scoreString);
        } else {
            item.append('<div class="score">' + scoreString +
                '</div>');
        }
    }

});

Event listeners bound with the on() method can be removed with the off() method. The latter takes two arguments: the event and listener pair you want to remove.

$.each(itemsApp.questions(), function( responseID, question ) {
  question.off("validated", showQuestionAndResponse);
});

 

Snippet 3: Confirming that All Questions are Attempted Before Submitting

 

Note Uses isAttempted() method

The Assess rendering type offers the option of automatically warning a student if any Questions remain unattempted when submitting an assessment. This feature is not provided when rendering assessments inline, but you can use the isAttempted() method to add this feature on your own.

The intent of inline rendering in the Items API is to give developer and designer control over all facets of the assessment, including buttons. As such, buttons for submit, save, and so on, are not automatically provided. The snippet that follows uses a simple custom button to submit the assessment after first checking to see if every Question has been attempted. If not all Questions have been attempted, it prompts the user to be sure he or she wants to submit the assessment. If so, the submit() method of the Items API instance is called.

$("#submitBtn").click(function() {
  var okToSubmit = true;
  $.each(itemsApp.questions(), function(responseID, question) {
    if (!question.isAttempted()) {
      okToSubmit = confirm("One or more questions have not been
        attempted. Are you sure you want to submit?");
      return false;
    }
  });
  if (okToSubmit) { itemsApp.submit(); }
});

You can also optionally react to submission successes and failures by adding a submit settings object to the submit() method above. The following lines log a message and the response IDs submitted when successful, or a message and event data when the submission fails.


$.each(itemsApp.questions(), function( responseID, question ) {
  question.off("validated", showQuestionAndResponse);
});

To use this object, just pass it to Learnosity as an argument of the aforementioned submit()method, as shown in the edited line below (change in bold):

if (okToSubmit) { itemsApp.submit(submitSettings); }

Note Users of the Assess rendering type can also customize this feature. As part of the configuration property, developers can prevent submission until a threshold percentage (0-100) of Questions are attempted (or valid). The JSON below requires that all Questions are attempted before submitting.

"submit_criteria": {
    "type": "attempted",
    "threshold": 100
}

 

Triggering Events Manually

Using Learnosity’s Provide Instant Feedback feature, a student can validate a Question at will by clicking the Check Answers button that appears with each Question. If you would rather build your own control for this purpose, you can manually trigger validation using the validate() method.

 

Snippet 4: Validate All Questions Manually

Note Uses the validate() method, and discusses the trigger() method.

The following snippet uses a custom button to validate an entire inline assessment at once, rather than Question by Question as is common with the Provide Instant Feedback feature.

$("#validateBtn").click(function() {
  $.each(itemsApp.questions(), function(responseID, question) {
    question.validate();
  });
});

Additionally, you can trigger the changed event manually using the trigger() method.

question.trigger("changed");

(You can also trigger the validated event separately, or the masked event when working with distractor masking. We’ll talk about masking in a moment.)

 

Special Use Cases

Specific Question types support additional Question-level public methods. (For each of the following quick snippets, ‘60001’ is a sample response ID for an applicable Question.)


begin()pause()stop(): Self-explanatory methods used to control audio Questions.

var audioQuestion = itemsApp.question("60001");
audioQuestion.begin();


mapValidationMetadata(): This method is commonly used when displaying distractor rationale—in particular, a per-response rationale when Questions that include more than one distractor (such as multiple choice) appear in an assessment. The method creates an object that maps distractor rationale to its corresponding distractor in correct, incorrect, and unattempted responses. Check out Tutorial 202: Displaying Distractor Rationale to see this method in action.


isMaskable()masking(): These methods are used with Question types, such as multiple choice, that support masking distractors—visual cues that make it easier to eliminate choice by process of elimination. The first method seeks a boolean that describes if the Question type is maskable. The second method enables/disables masking with a given mask ui-style.

var question = myLearnosityApp.question("60001");
if (question.isMaskable()) {
    question.masking(true);
}

 

What you learned

In this tutorial we learned how to use events and public methods to parse Question-specific data, and react to events at the Question level, rather than at the assessment level. This overview demonstrated code use via basic snippets, and points to additional uses of this approach for further discussion.

 

Was this article helpful?

Did you arrive here by accident? If so, learn more about Learnosity.