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!

1
  • 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
    Commented Aug 31, 2015 at 21:37

2 Answers 2

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.

0

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

1
  • 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
    Commented Aug 8, 2012 at 18:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.