Today's Deals (in Amazon.com)

 Question:

forms - Can't change ajax callback
  • Jav

    I've got a confusing ajax issue that I'm not getting past for some reason. My submit callback loads some data and constructs a radio button with some questions. All cool. When the result set has a certain value ($lastquestion = true), then I want to change the submit callback, basically updating a different field in the form.

    Here's the module (I apologize for the extra "fluff"):

    function my_assisted_guide_menu(){
      $items = array();
    
      $items['assisted-guide']= array(
        'title' => 'Assisted Guide',
        'page callback' => 'drupal_get_form',
        'page arguments' => array('my_assisted_guide_form'),
        'access callback' => TRUE,
        'description' => 'My Assisted Guide',
        'access arguments' => array('administer news feeds'),
        'type' => MENU_NORMAL_ITEM,
        'file' => 'my_assisted_guide.inc',
      );
    
      return $items;
    }
    
    
    /* Implementation of hook_form()
    // * This is the main form function
     */
    function my_assisted_guide_form($form, &$form_state){
    
      if(isset($form_state['input']['answer'] )){
        $next_qid = $form_state['input']['answer'];
      }else{
        $next_qid = 0;
      }
    
      $data = _nextquestion($next_qid);
      $questiontype = $data[0];
      $question = $data[1];
      $options = $data[2];
    
      $form['answer'] = array(
        '#type' => 'radios',
        '#title' => t('Answer'),
        '#options' => $options,
        '#size'=>2,
        '#title' => t($question),
        '#description' => 'Select one.',
        '#required' => TRUE,
        '#prefix' => '<div id="questions" class="qna">',
      );  
    
      //Store question type value for later processing in submit function
      $form['question_type'] = array(
        '#type'=> 'hidden',
        '#value' => $questiontype,
        '#suffix' =>'</div>',  
      );
    
      $form_state['redirect'] = false;
    
      $service_providers = "";
    
      if($questiontype < 3){
        $submit_text = "Next Question";
        $callback = 'get_next_question_callback';
        $wrapper = 'questions';
      }else{
        $submit_text = "Next";
        $callback = 'get_recommendations_callback';
        $wrapper = 'recommendations_list';
      }
    
      $form['submit'] = array(
          '#type' => 'submit', 
          '#value' => t($submit_text),
          '#ajax' => array(
              'callback' => $callback,
              'wrapper' => $wrapper,
              'method' => 'replace',
          ),
          '#submit' => array('my_assisted_guide_submit'),
          '#prefix' =>'<div id="q_button">',
          '#suffix' =>'</div>',
          );
    
      if((isset($service_providers)) && (strlen($service_providers)>0) ){
        $form['recommendations_list'] = array(
                                            '#markup' => '<h1>Recommendedations</h1>',
                                            '#prefix' => '<div id="recommendedations">'
                                          );
        $form['service_providers'] = array(
                                           '#markup' => '<div><h3>Service Providers: </h3>'.$service_providers.'</div>',
                                           '#suffix' => '</div>'
                                        );
      }
    
      return $form;
    }
    
    
    //
    function get_next_question_callback($form, $form_state)
    {    
    
      return array(
        '#type' => 'ajax',
        '#commands' => array(
          ajax_command_replace("#questions", render($form['answer'])),
          ajax_command_replace("#q_button", render($form['submit']))
        )
      );
    }
    
    //
    function get_recommendations_callback($form, $form_state)
    {
    
      return $form['recommendations_list'];
    
    }
    
    function my_assisted_guide_submit($form, &$form_state){
      $next_key = $form_state['values']['answer'];
      $data = _nextquestion($next_key );
      $questiontype = $data[0];
      $question = $data[1];
      $options = $data[2];
    
      $form['answer']['#options'] = $options;
      $form['answer']['#title'] = $question;
      $form['question_type']['#value'] = $questiontype;
    
      if($questiontype == 3){
        $form['submit']['#ajax'] = array(
              'callback' => 'get_recommendations_callback',+
              'wrapper' => 'recommendations',
              'method' => 'replace',
          );
        $form['#submit'] = array('my_assisted_guide_submit') ;
      }
    
      $form_state['rebuild'] = TRUE;
    
    }
    
    function _first_question_nid(){
        $query = new EntityFieldQuery();
        $query->entityCondition('entity_type', 'node')
          ->entityCondition('bundle', 'dt_questions')
          ->propertyCondition('status', NODE_PUBLISHED)
          ->propertyOrderBy('created', 'DESC')
          ->fieldCondition('field_dt_questiontype', 'value', 1)
          ;
          $result = $query->execute();
    
        $nodeinfo = array_keys($result['node']);
        $nid = $nodeinfo[0];
    
      return $nid;
    }
    
    //Custom function to get the next question based on $next_qid = the question record's nid
    //$answer_id is the fci of the selected answer, used to get the next question field value andload that node
    function _nextquestion( $answer_id = 0, $question_type = 0 ){
      $next_qid = 0;
    
      if($question_type == 3){
        $data[0] = "0";
        $data[1] = "End of questions";
        $data[2] = array("0" =>"0");
        return $data;
      }
    
      if($answer_id == 0){
        //get first question id 
        $next_qid = _first_question_nid();
        $questiontype = 1;
      }else{
        //get nid of answer where answer_id = $next_qid
        $next_q = db_query("select at.field_dt_answer_value as answer_text, at.entity_id as answer_key, 
          a.entity_id as par_nid, q.field_a_dt_question_target_id nqid, qt.field_dt_questiontype_value as qtype
            from field_data_field_dt_answer at
            LEFT JOIN field_data_field_answer a on at.entity_id = a.field_answer_value
            LEFT JOIN field_data_field_a_dt_question q on at.entity_id = q.entity_id 
            LEFT JOIN field_data_field_dt_questiontype qt on q.field_a_dt_question_target_id = qt.entity_id 
          WHERE at.entity_id = :answerid", array(":answerid" => $answer_id ))->fetchObject(); //fetchAllAssoc('at.entity_id');
        $questiontype = $next_q->qtype;
        $next_qid = $next_q->nqid;
      }
    
      //Load the node
      $node = node_load($next_qid);
    
      $node_wrapper = entity_metadata_wrapper('node', $node);
    
      //$field contains an array of objects the answer and next question 
      $field = $node_wrapper->field_answer->value();
    
      $answer_options_count = count($field);//['field_answer']);
    
      for($x=0; $x<$answer_options_count; $x++){
        //Check for final question
        $option_index =  $node->field_answer['und'][$x]['value'];
        $options[$option_index] = $field[$x]->field_dt_answer['und']['0']['value'];
      }
    
      $question = $node->field_dt_question['und']['0']['value'];  
    
      $data[0] = $questiontype;
      $data[1] = $question;
      $data[2] = $options;
      return $data;
    }
    
  •  Answers:

  • Mołot

    AJAX callback is not meant for making persistent changes. All it can and will do is:

    • Make one-time changes to form array, that are not supposed to last
    • Return proper part of the form for update

    You cannot change your form in any permanent way, and changing callback there would last until next request. At next request it will get reseted, and old callback will be used. You need to modify things like that in form building function itself.