0

Requirements:

  1. User navigates to path "new-problem" and is presented with a math problem and multiple choice answers, one of which is correct.
  2. There is one submit button per choice
  3. If the user clicks a wrong choice, we record that to the database and the same problem is shown again (user gets another chance)
  4. If the user clicks the right choice, we record that to the database and a new problem is shown.

I haven't been able to coax Drupal to accomplish this thus far. I'm sure the problem involves how the form is/isn't rebuilt. I believe this to be related to Submitting a form rebuilds (expensive) page upon submit

I tried using a validation function and form_set_error() when the user chose a wrong choice, but the form kept being rebuilt from scratch with a new problem (instead of the same problem). I tried setting $form_state['rebuild'] = TRUE to no avail.

The code below works except for the first time. When a user navigates to "new-problem", he is shown the form. Upon clicking an incorrect choice's submit button, the "incorrect" status message is shown, but a new problem is shown. Thereafter, clicking an incorrect choice correctly shows the"incorrect" status message and the problem he got wrong.

hook_menu()

function dfm_menu() {
  $items['new-problem'] = array(
    'page callback' => 'dfm_new_problem_page',
    'access callback' => TRUE,
  );

  return $items;
}

menu callback

function dfm_new_problem_page() {
  $node = dfm_get_new_problem(); // Returns a "problem" node

  return drupal_get_form('dfm_problem_form', $node);
}

form builder

function dfm_problem_form($form, &$form_state, $node) {
  $form['#nid'] = $node->nid;
  $form['#correct_choice'] = $node->field_correct_choice[LANGUAGE_NONE][0]['value'];

  $problem = $node->field_problem_mathml[LANGUAGE_NONE][0];

  $form['problem'] = array(
    '#prefix' => '<div class="problem-mathml">',
    '#markup' => check_markup($problem['value'], $problem['format']),
    '#suffix' => '</div>',
  );

  $i = 0;

  // One submit button per choice
  foreach ($node->field_choice_mathml[LANGUAGE_NONE] as $choice) {
    $correct = ($i == $form['#correct_choice']); // TRUE if this choice is the correct choice

    $form['choices'][$i] = array(
      'button' => array(
        '#type' => 'submit',
        '#value' => t('This one!'),
        '#submit' => $correct ? array('dfm_problem_form_submit_correct') : array('dfm_problem_form_submit_incorrect'),
      ),
      'mathml' => array(
        '#markup' => check_markup($choice['value'], $choice['format']),
      ),
    );

    $i++;
  }

  return $form;
}

incorrect submission handler

function dfm_problem_form_submit_incorrect($form, &$form_state) {
  // Create a new answer node to record the incorrect answer
  dfm_record_answer($form['#nid'], $form['#correct_choice']);

  drupal_set_message(t('Incorrect'), 'error');
  $form_state['rebuild'] = TRUE;
}

correct submission handler

function dfm_problem_form_submit_correct($form, &$form_state) {
  // Create a new answer node to record the correct answer
  dfm_record_answer($form['#nid'], $form['#correct_choice']);

  drupal_set_message(t('You got the last problem right!'));
}

Thanks for your time!

  • I vaguely remember once managing a similar requirement with multiple view modes. After submit I might have forced the node to reload in another view mode. And in hook_node_view() I may have checked the view mode and depending on what view mode I had I may have another form got rendered inside a markup element I added to $node->content. – leymannx Aug 31 '15 at 21:37
1

I recommend using one of these two modules and adjusting them according to your needs.

https://www.drupal.org/project/quiz

https://www.drupal.org/project/field_quiz

The Field Quiz module provides a simple field that can be used as a simple quiz or multiple choice questions. It provides a field with a textfield and an checkbox combined. If added to a content type the editor of the node can enter multiple answers in the textfields and determine which answers are correct.

| improve this answer | |
0

you can check if $form_state['values']['choices'][$i] is set then $form['choices'][$i]['#disabled'] = true;'

| improve this answer | |
  • I'm not trying to disable anything; the form is displaying fine. The problem is with the validation/submission/rebuilding of the form when the user selects an incorrect choice, which is resulting in a new problem (the first time) instead of the same problem. – JD Leonard Aug 8 '12 at 18:56

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.