1
votes

I am trying to populate the second select box with the all date fields of the first selected content type name in select box. I am using ajax_callback to fetch the selected value by $form_state. I am getting error, which I can't determine why. Can anybody help?

This is the my custom module code.

function mymodule_settings($form, &$form_state){
  $content_type_options = array();
  $result = db_query("SELECT * FROM {node_type}");  
  foreach($result as $record){
    $content_type_options[$record->type]  =  $record->name;  
  }
  $form = array();
  $form['content_type'] = array(
    '#title'  => t('Content Types'),
    '#description'  => t('Select a content type.'),
    '#type' => 'select',
    '#options'  => $content_type_options,
    '#ajax' => array(
      'event' => 'change',
      'wrapper' => 'reg-start-date',
      'callback' => 'mymodule_datefields_ajax_callback',
      'method' => 'replace',
    ),
  );
  $form['checkboxes_fieldset'] = array(
    '#title' => t("Start Date"),
    '#prefix' => '<div id="reg-start-date">',
    '#suffix' => '</div>',
    '#type' => 'select',
    '#description' => t('Select the date field'),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value'  => t('Save'),
  );
  return $form;
}

function mymodule_datefields_ajax_callback($form, $form_state) {
  $fieldname = $form_state['triggering_element']['#value'];

  $field_query = db_query("SELECT fc.field_name FROM {field_config} fc, {field_config_instance} fci
                          WHERE fc.field_name = fci.field_name
                          AND fc.type = 'datetime'
                          AND fci.bundle = '".$fieldname."'");
  $datefield_options = array();
  foreach($field_query as $record){
    $datefield_options = $record;
  }
  return $datefield_options;
  //dpm($form_state, 'AJAX $form_state');
}

Here is the error, which I am getting in popup -

An AJAX HTTP error occurred. HTTP Result Code: 200 Debugging information follows. Path: /module_dev/?q=system/ajax StatusText: OK ResponseText: Fatal error: Cannot use object of type stdClass as array in /var/www/module_dev/includes/common.inc on line 5786

I went through the /var/www/module_dev/includes/common.inc on line 5786, and this is the code I find there.

function drupal_render(&$elements) {
  // Early-return nothing if user does not have access.
  if (empty($elements) || (isset($elements['#access']) && !$elements['#access'])) {
    return;
  }

  // Do not print elements twice.
  if (!empty($elements['#printed'])) {
    return;
  }

  // Try to fetch the element's markup from cache and return.
  if (isset($elements['#cache'])) {
    $cached_output = drupal_render_cache_get($elements);
    if ($cached_output !== FALSE) {
      return $cached_output;
    }
  }

  // If #markup is set, ensure #type is set. This allows to specify just #markup
  // on an element without setting #type.
  if (isset($elements['#markup']) && !isset($elements['#type'])) {
    $elements['#type'] = 'markup';
  }

  // If the default values for this element have not been loaded yet, populate
  // them.
  if (isset($elements['#type']) && empty($elements['#defaults_loaded'])) {
    $elements += element_info($elements['#type']);
  }

  // Make any final changes to the element before it is rendered. This means
  // that the $element or the children can be altered or corrected before the
  // element is rendered into the final text.
  if (isset($elements['#pre_render'])) {
    foreach ($elements['#pre_render'] as $function) {
      if (function_exists($function)) {
        $elements = $function($elements);
      }
    }
  }

  // Allow #pre_render to abort rendering.
  if (!empty($elements['#printed'])) {
    return;
  }

  // Get the children of the element, sorted by weight.
  $children = element_children($elements, TRUE);

  // Initialize this element's #children, unless a #pre_render callback already
  // preset #children.
  if (!isset($elements['#children'])) {
    $elements['#children'] = '';
  }
  // Call the element's #theme function if it is set. Then any children of the
  // element have to be rendered there.
  if (isset($elements['#theme'])) {
    $elements['#children'] = theme($elements['#theme'], $elements);
  }
  // If #theme was not set and the element has children, render them now.
  // This is the same process as drupal_render_children() but is inlined
  // for speed.
  if ($elements['#children'] == '') {
    foreach ($children as $key) {
      $elements['#children'] .= drupal_render($elements[$key]);
    }
  }

  // Let the theme functions in #theme_wrappers add markup around the rendered
  // children.
  if (isset($elements['#theme_wrappers'])) {
    foreach ($elements['#theme_wrappers'] as $theme_wrapper) {
      $elements['#children'] = theme($theme_wrapper, $elements);
    }
  }

  // Filter the outputted content and make any last changes before the
  // content is sent to the browser. The changes are made on $content
  // which allows the output'ed text to be filtered.
  if (isset($elements['#post_render'])) {
    foreach ($elements['#post_render'] as $function) {
      if (function_exists($function)) {
        $elements['#children'] = $function($elements['#children'], $elements);
      }
    }
  }

  // Add any JavaScript state information associated with the element.
  if (!empty($elements['#states'])) {
    drupal_process_states($elements);
  }

  // Add additional libraries, CSS, JavaScript an other custom
  // attached data associated with this element.
  if (!empty($elements['#attached'])) {
    drupal_process_attached($elements);
  }

  $prefix = isset($elements['#prefix']) ? $elements['#prefix'] : '';
  $suffix = isset($elements['#suffix']) ? $elements['#suffix'] : '';
  $output = $prefix . $elements['#children'] . $suffix;

  // Cache the processed element if #cache is set.
  if (isset($elements['#cache'])) {
    drupal_render_cache_set($output, $elements);
  }

  $elements['#printed'] = TRUE;
  return $output;
}
1
Check that line. You are trying to access an object type data as an array data. - Edwin Alex
But this query returns me just the names..hot it can become stdClass ? - RajeevK
Just put the line in which error occurs? - Edwin Alex
Let me edit the question, so that it get more clear - RajeevK

1 Answers

0
votes

What your AJAX callback should return is the rendering array for a form element that replaces the content of the <div> tag whose CSS ID is set as #ajax[wrapper]. What your AJAX callback is returning is an array of objects, which is not what the render API is expecting. (The render API uses arrays.) That is why you get an error saying that a object cannot be used as array.

See ajax_example_simplest() as example of form builder using AJAX; in particular, see its AJAX callback, ajax_example_simplest_callback().

In short, the code of mymodule_datefields_ajax_callback() should be the following one.

function mymodule_datefields_ajax_callback($form, $form_state) {
  return $form['checkboxes_fieldset'];
}

The form builder should use the following code.

function mymodule_settings($form, &$form_state){
  $content_type_options = array();
  $result = db_query("SELECT * FROM {node_type}");  
  foreach ($result as $record) {
    $content_type_options[$record->type]  =  $record->name;  
  }

  // $form is already passed as argument; you don't need to initialize it to an empty array.
  // $form = array();

  $form['content_type'] = array(
    '#title'  => t('Content Types'),
    '#description'  => t('Select a content type.'),
    '#type' => 'select',
    '#options'  => $content_type_options,
    '#ajax' => array(
      'event' => 'change',
      'wrapper' => 'reg-start-date',
      'callback' => 'mymodule_datefields_ajax_callback',
      'method' => 'replace',
    ),
  );

  // An AJAX request call to the form builder function has been done.
  if (!empty($form_state['values']['content_type'])) {
    // Use $form_state['values']['content_type'] to get the option list.
    // Set the value of $date_options with that list.
    $field_query = db_query("query to execute");
    $date_options = array();

    foreach ($field_query as $record) {
      $date_options[$record->field_name] = $record->field_name;
    }
  }
  else {
    $date_options = array();
  }

  $form['checkboxes_fieldset'] = array(
    '#title' => t("Start Date"),
    '#prefix' => '<div id="reg-start-date">',
    '#suffix' => '</div>',
    '#type' => 'select',
    '#options' => $date_options,
    '#description' => t('Select the date'),
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value'  => t('Save'),
  );

  return $form;
}

$date_options is an array with the format value => string_to_show; it's is the same format you used for $content_type_options.