WeBWorK Problems

Storing persistent information accessible through Javascript

Storing persistent information accessible through Javascript

by Jason Siefken -
Number of replies: 4
I am trying to create a webwork problem where the answer is created/checked and verified with Javascript. The issue I'm running into is how to store persistent state.

If I use NAMED_HIDDEN_ANS_RULE the state will be persistent, but it will still show up in an answer "preview" (it will be very confusing for students if a block of JSON shows up in the preview when they didn't enter any JSON themselves). I used the code linked to from here.

I have tried to figure out how to use RECORD_FORM_LABEL, which is referenced at the link above, but I have no idea how to use it properly.

My question for is: could someone provide a minimal example of a webwork problem with two textboxes: one is checkable as an "answer", the other with persistent state but doesn't get checked, and both of whose values can be read and written from Javascript?
In reply to Jason Siefken

Re: Storing persistent information accessible through Javascript

by Davide Cervone -
The RECORD_FORM_LABEL() macro takes the name of a hidden input element (that you must create yourself) and stores its data along with other student answers, but the data isn't used in any answer checkers by default and doesn't appear in the results table.

For example, you could use

    TEXT(qq!<input type="hidden" name="_myData" id="_myData" value="$myData" />!);
    RECORD_FORM_LABEL("_myData");
This stores the value of the variable $myData in a hidden input element with ID _myData that will be saved a part of the student data. (Here I assume that $myData doesn't include any quotation marks; if it does, you need to convert them to &quot; entities).

To access the data stored there, use $inputs_ref->{_myData} to get the value from the previous submission.

While I understand the desire to have in-browser content checking, you should be aware that this opens you up to potential cheating by students. For example, enterprising students can access the data stored in the hidden field, and even change it before submitting their answers. Moreover, they have complete access to your javascript code and could potentially figure out the solution to the problems based on that, or could determine what needs to be sent to WeBWorK to record full credit without ever doing the problem.

For example, if the hidden field is used to store a true/false value about whether the student's answer is correct, they could simply use the browser console to set the value of the hidden field and submit the answer without ever working the problem.

Since the answer checking is being done in the browser, and they control the browser (and all the javascript running in it), they can simply insert themselves into the process in order to send back to WeBWorK whatever result they would like it to get. You can make it harder by obfuscating your javascript code or encoding the stored values, but you can't prevent it entirely.

This is one reason that WeBWorK problems are graded on the server. Neither the solution algorithm nor the correct answer is sent to the students browser before she answers the question. In your case, both would be available to the student before they even begin the problem.

Personally, I expect that I would avoid using such problems.

In reply to Davide Cervone

Re: Storing persistent information accessible through Javascript

by Jason Siefken -
Thank you! I got persistent data to work with the following code

 $myData = $inputs_ref->{_myData}; TEXT(qq!<input type="hidden" name="_myData" id="_myData" value="$myData" />!); RECORD_FORM_LABEL("_myData"); 
I understand the risks of client-side answer checking, but for my purposes (non-testing environment) it is fine. However, there is another issue with client side checking: the answer preview.

If I fill an answer box dynamically with "correct" or "incorrect", previewing the answer will show that text. Is there a way to disable the answer preview, or to have the answer come from a source other than an answer box?
In reply to Jason Siefken

Re: Storing persistent information accessible through Javascript

by Davide Cervone -
Well, you could do a nasty hack to disable the preview button:
TEXT(MODES(HTML => "<style>#previewAnswers_id {display:none}</style>"));
but I'm not sure if the id for the answer button is consistent across themes, or whether it might change in the future. Also, the student could re-enable it (though I doubt anyone would think to do so).

Alternatively, you could use a post-filter to clear the answer values that will be printed in the results table when the preview button is pressed:

ANS($answer->cmp->withPostFilter(sub {
  my $ans = shift;
  if ($ans->{isPreview}) {
    $ans->{student_ans} = $ans->{preview_text_string} = "&nbsp;";
    $ans->{preview_latex_string} = "\space";
  }
  return $ans;
}));
One of these might do the trick for you.
In reply to Davide Cervone

Re: Storing persistent information accessible through Javascript

by Jason Siefken -
I think your second solution will work quite well!

I have two followups:
  1. Is it possible to create an ANS without an ans_box? At the moment I have a very hacky solution: I have NAMED_ANS("_answer", String("x")->cmp->withPostFilter(...)). I use the values stored from $input_ref's to make a custom answer checker, and I use JavaScript to autofill the "_answer" input with "x" so it always passes the parse test. Ideally, there would be no parse test and the <input id="_answer"> would be empty, or it would not exist at all.
  2. How can I tell webwork inside of withPostFilter that a particular answer should not deduct from a student's number of attempts. Is this possible?