Submit a request
Submit a request

Tutorial 203 - Displaying Hints

Show assessment question hints on demand. 

 

Introduction

As with distractor rationale, it’s a breeze to add hints to an assessment using Learnosity APIs. This tutorial is based on Tutorial 202: Displaying Distractor Rationale, and will use the same approach to display hints that have been added to Question data using the Learnosity Author site or embedded Question Editor.

Hints are entered in the metadata section of the Author site or Question Editor. There is more than one school of thought about when and how hints should be shown to a student. As such, the last mile of displaying optional information such as hints (or the aforementioned distractor rationale) is up to you. You can store hints in Question data, and Learnosity provides the code to retrieve this information at runtime—but without dictating how the hints should be displayed.

In this tutorial, we will use Question-level events and public methods to display a single hint when a user clicks a button. It’s possible to place multiple hints into the metadata hint property (the Worked Solutions demo shows such an example), or even customize your metadata fields to accommodate a more elaborate hint system. But we’ll start simple here, with a single hint, and you can pick up where we leave off.

Note: This tutorial assumes you are familiar with the Learnosity Items APIPHP, and jQuery.
 

The Request and Host Page

This tutorial uses the same PHP to secure and sign the API request, and the same HTML and CSS for the host page, as the Displaying Distractor Rationale tutorial. We’ve reproduced the code here for your convenience, but if you need additional explanations of any of the following code block, please see Tutorial 202.

Note: This tutorial uses demo values for the consumer key and secret. In production, you must use your own consumer key and secret.

 

  1  <?php
  2
  3  include_once 'config.php';
  4
  5  use LearnositySdkRequestInit;
  6  use LearnositySdkUtilsUuid;
  7
  8  $request = [
  9    'user_id'        => 'student_1234',
 10    'session_id'     => Uuid::generate(),
 11    'items'          => ['act1','act2','act3','act4','act5','act6'],
 12    'rendering_type' => 'inline',
 13    'state'          => 'initial',
 14    'type'           => 'submit_practice',
 15    'activity_id'    => 'tutorial_activity',
 16    'name'           => 'Distractor Rationale Example',
 17    'course_id'      => 'tutorial_course',
 18    'config'         => [
 19        'renderSubmitButton'  => true
 20    ]
 21  ];
 22
 23  $Init = new Init('items', $security, $consumer_secret, $request);
 24  $signedRequest = $Init->generate();
 25
 26  ?>
 27
 28  <!DOCTYPE html>
 29  <html lang="en">
 30    <head>
 31      <meta charset="utf-8">
 32      <title>Distractor Rationale</title>
 33      <style>
 34        body {
 35          background-color:#F2F2F2;
 36        }
 37        .learnosity-item {
 38          background-color:#FFFFFF;
 39          padding:20px;
 40          margin:20px 0px;
 41        }
 42        .distractor {
 43          margin-top:5px;
 44          padding:10px;
 45          background-color:#EBCCD1;
 46          color:#b94a48;
 47        }
 48      </style>
 49    </head>
 50    <body>
 51      <h1>Distractor Rationale Tutorial</h1>
 52      <div style="width:750px;">
 53        <span class="learnosity-item" data-reference="act1"></span>
 54        <span class="learnosity-item" data-reference="act2"></span>
 55        <span class="learnosity-item" data-reference="act3"></span>
 56        <span class="learnosity-item" data-reference="act4"></span>
 57        <span class="learnosity-item" data-reference="act5"></span>
 58        <span class="learnosity-item" data-reference="act6"></span>
 59        <span class="learnosity-submit-button"></span>
 60      </div>
 61
 62      <!--scripts go here-->
 63
115    </body>
116  </html>?>

 

Initializing the API

When initializing the Items API, we’ll follow the consistent pattern of passing to the init method the signed request created in the PHP block above, as well as an event object. We’ll use the event object to provide a ready listener that will be triggered when the API is loaded and ready to go. The final call will ultimately look like this:

 

var itemsApp = LearnosityItems.init(<?php echo $signedRequest; ?>, eventOptions);

With the signed request complete, let’s focus on the event object.

 

Parsing and Setting up The Hint

We’ll be using jQuery to simplify selectors along the way so, in addition to referencing the Items API in line 63, we’ll also include jQuery in line 62. Our script then begins with an object called responseIDHints. This will simply associate the appropriate hint with each Question’s response ID.

The eventOptions object defined in line 68 has only one function, which is the ready listener. It begins with a loop that walks through all the Questions in the Items API instance. The API provides the Question data and response ID for each Question so we can use both to our advantage. Line 72 retrieves each Question’s hint from the metadata section of the Question data using the public method getMetadata(). It then stores the hint in the aforementioned responseIDHintsobject using the Question’s response ID as a key.

Line 74 creates a hint button with Learnosity button style classes, and a data attribute that holds the Question’s response ID. Line 74 appends that data to the DOM element with the same ID. Lines 77 through 79 create a click event handler for the button that calls the renderHint function (passing in a reference to the button), which we’ll discuss in a moment.

 

62  <script src="js/vendor/jquery.min.js"></script>
63  <script src="//items.learnosity.com/"></script>
64  <script>
65
66    var responseIDHints = {};
67
68    var eventOptions = {
69      readyListener: function () {
70
71        $.each(itemsApp.questions(), function(responseID, question) {
72          responseIDHints[responseID] = question.getMetadata().hints;
73
74          var btnHint = '<button type="button" class="btn btn-default btn-sm"
75              data-responseid="' + responseID + '">Hint</button>';
76          $("#" + responseID).append(btnHint);
77
78          $("button").click(function() {
79            renderHint($(this));
80          });
81
82          question.on("changed", function(){
83            $("#" + responseID + "_hint").fadeOut();
84          });
85        });
86
87      }
88    }

Finally, lines 81 through 83 use the Question-level public method on() to bind the changed event to the button. Each time the Question response is changed, the hint will fade out. This gives the end user the chance to see a hint and then try again after thinking about a new answer. Next let’s look at how to show the hint when the button is clicked.

 

Displaying the Hint (Assessment)

To display the hint, we parse the Question’s response ID in line 90, stored earlier in the button’s responseid data attribute. We then retrieve the corresponding hint from the responseIDHints object in line 92.

Lines 94 through 98 first check to see if a hint DOM element exists for the relevant Question. If so, line 95 populates the element and fades it in. If not, line 97 creates a div for this purpose, appends it to the Question, and then fades it in. The div is given an ID derived from the response ID and “_hint” suffix, and styled with the hint class.

As the last display step, MathJax is nudged to render any possible LaTeX or MathML that may be in the hint for that response ID.

 

 89   function renderHint(whichBtn) {
 90     var responseID = whichBtn.data("responseid");
 91
 92     var hint = responseIDHints[responseID];
 93
 94     if ($("#" + responseID + "_hint").length) {
 95         $("#" + responseID + "_hint").html(hint).fadeIn();
 96     } else {
 97         var hintDiv = '<div id="' + responseID + '_hint" class="hint">' + hint + '</div>'
 97         $("#" + responseID).append(hintDiv).fadeIn();
 98     }
 99
100      MathJax.Hub.Queue([
            "Typeset", MathJax.Hub, responseID
         ]);
101    }
102
103    var itemsApp = LearnosityItems.init(<?php echo $signedRequest; ?>, eventOptions);
104  </script>

As mentioned previously, we can now send the completed eventOptions object, along with the signed request object, to initialize the Items API in line 103.

 

Seeing the Hint in Action 

Figure 1, below, shows a Question through all phases of hint interaction. When a student requests the hint, it is displayed in blue at the bottom of the item. Upon entering an answer, the hint is hidden again, and validation is successful.

 

Figure 1

Displaying the Hint (Authoring, Item preview)

Thanks to the public events, you can bind your custom code to the "render:item" event.

Here is an example showing how you can achieve it, assuming you have already initialized Author API:

authorApp.on('render:item', function () {
  const questionsApp = authorApp.questionsApp();
  
  if (!questionsApp) {
    return;
  }
  
  const questions = questionsApp.questions();
  
  Object.keys(questions).forEach(function (responseId) {
    const $question = $('#' + responseId);
    const metadata = questions[responseId].getMetadata();
    const hintsMetadata = metadata ? metadata.hints : null;
    let $button, $hints;
    
    if ($question.length === 0 || !hintsMetadata) {
      return;
    }
    
    $button = createButton($question, function () {
      $hints.toggle();
    });
    $hints = createHint($question, hintsMetadata);
    
    if (window.MathJax) {
      window.MathJax.Hub.Queue([
        'Typeset', window.MathJax.Hub, responseId
      ]);
    }
  });
});

function createButton($question, handleClick) {
  let $button = $question.find('.btn-hints');
  
  if ($button.length === 0) {
    $button = $('<button class="btn btn-default btn-sm btn-hints">Toggle hints</button>')
      .css('margin', '10px 0 0')
      .on('click', handleClick)
      .appendTo($question);
  }
  
  return $button;
}

function createHint($question, text) {
  let $hints = $question.find('.hints');
  
  if ($hints.length === 0) {
    $hints = $('<div class="hints">' + text + '</div>')
      .css({
        display: 'none',
        background: 'rgba(0, 0, 255, .1)',
        margin: '10px 0 0',
        padding: '10px 15px',
        borderRadius: '4px'
      })
      .appendTo($question);
  }
    
  return $hints;
}

 

What you Learned

Building upon the distractor rationale tutorial, you learned how to use Question-level and Author API events and public methods to show hints. Hint data is added to the Question JSON, typically through the Learnosity Author site or your own embedded version of the Question Editor.

 

Was this article helpful?
0 out of 0 found this helpful

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