Hi there,

I'm trying to use AJAX to dynamically update the default value of a dependency-driven form inside of a CTools/Panels custom content type (Apologies if this is more of a Panels issue) and am just failing to get anywhere.

In order to troubleshoot this, I've essentially removed all my code in hook_content_type_edit_form() and replaced it with the basic form API AJAX example code at http://drupal.org/node/752056

I've also posted a question on drupal.SE -- http://drupal.stackexchange.com/questions/39818/ajax-calls-in-ctools-con...

It seems that the callbacks are just refusing to fire -- I've put a watchdog call in my callback and nothing's in dblog.

I've been working with no less than two other people who are having difficulty with this and it seems there's not a lot of documentation about using AJAX in a Panels custom content type. We're almost at a point where we don't think CTools content type edit forms can do AJAX -- but surely this isn't the case?

If it is -- any suggestions how to use form dependencies to set default values? My code drops in a pane that lets the user choose one of three different link types in the edit form, which show/hide different options based on which is selected (a la dependencies). One of these options is the link target -- it'd be great to be able to set _blank as the default select option for external links and _self for internal.

Any help you can give on this would be most appreciated -- we're all kinda losing hair and sleep over here about this.

Thanks!

Comments

anandkp’s picture

Hey there aendrew!

I've been stuck on the exact same problem for the last two days and can't figure out for the life of me how to get past this roadblock. I actually stumbled upon your thread on SE yesterday while looking for a solution. I see that one of the answers mentions the use of hook_menu() and providing a path to call... which I've experimented with but can't get past.

The last comment on your SE thread is sorta the same with what I'm left wondering - after declaring a path to for $form['select_item']['#ajax]['path'], I'm stumped as to what I should do in the page callback.

I've missed the tiny little part of your question which is about the return value: return $form['link_target']['#default_value']; which is your trying to return a drupal form to a html/javascript context. That will not work. Have you seen similar thing what you want in the panels UI? (I myself disable JavaScript now and then with views UI just to see the non js workflow) (edited this comment a zillion times ... awkward) – Clemens Tolboom Oct 10 at 6:50

The following is a snippet of the code I'm working on:

/**
 * @file MODULE_NAME/MODULE_NAME.module
 */
 
/**
 * Implementation of hook_menu()
 */
function MODULE_NAME_menu() {
  $items = array(
    'MODULE_NAME_test_ajax_path' => array(
      'title' => 'Testing an CTools Form Ajax callback.',
      'page callback' => 'MODULE_NAME_content_type_edit_form_ajax_callback',
	  // do I need to use the 'file' key below to include something?
	  // 'file' => drupal_get_path('module', 'MODULE_NAME'),
      'access callback' => TRUE,
      'type' => MENU_CALLBACK,
    ),
  );

  return $items;
}

/**
 * Implements hook_ctools_plugin_directory().
 */
function MODULE_NAME_ctools_plugin_directory($module, $plugin) {
  if (($module == 'page_manager' || $module == 'panels' || $module == 'ctools') && $plugin == 'styles' || $plugin == 'content_types') {
    return "plugins/{$plugin}";
  }
}
/**
 * @file MODULE_NAME/plugins/content_types/test_ajax_path.inc
 */
 $plugin = array(
  'title' => t('Testing Ajax on CTools content_type form.'),
  'category' => t('Custom'),
  'single' => TRUE,
  'edit form' => 'MODULE_NAME_content_type_edit_form',
  'render callback' => 'MODULE_NAME_content_type_render',
  'top level' => TRUE,
);
 
/**
 * Form specified in plugin infor array above.
 */
function MODULE_NAME_content_type_edit_form($form, &$form_state){
  $form['test_ajax_callback_select'] = array(
    '#title' => t('Testing Ajax Callback'),
    '#type' => 'select',
    '#options' => array('opt_1' => 'Option 1', 'opt_2' => 'Option 2', 'opt_3' => 'Option 3'),
    '#default_value' => $conf['test_ajax_callback_select'],
    '#ajax' => array(
	  // D7 FAPI says that a callback func can be provided here and that 
	  // it should return the portion of the form that needs to be updated.
	  // When the markup is returned/retrieved, it will replace an HTML element with
	  // the ID provided in the 'wrapper' key. In this 
	  // case it would be <div id="test_ajax_callback_text">.
	  // This isn't working for this form. The 'path' key defaults to 
	  // 'system/ajax' which doesn't know anything about this form - which 
	  // was part of one of the answers provided on the StockExchange thread.
	  // 'calback' => 'MODULE_NAME_content_type_edit_form_ajax_callback',
      'path' => 'MODULE_NAME_test_ajax_path',
      'wrapper' => 'test_ajax_callback_text'
    ),
  );
  $form['test_ajax_callback_text'] = array(
    '#title' => t('Testing Ajax Callback'),
    '#type' => 'textfield',
    '#prefix' => '<div id="test_ajax_callback_text">',
    '#suffix' => '</div',
  );

  return $form;
}

function MODULE_NAME_content_type_edit_form_ajax_callback(){
  // I have no idea what to do here and what is available for use in this callback func.
  // Just returning a string doesn't do anything.
  // What would the next step be?
  // I've seen the use of ctools_include('ajax') and similar calls elsewhere 
  // but am unsure as to what they do and what else is needed.
}

Any help you could give would be so very, very much appreciated!

I wish that there was more documentation on #ajax for ctools forms or better yet, that ctools implemented form ajax in a way that simply using Drupal 7 native $form['select_item']['#ajax]['callback'] would work as expected...

Thanks in advance!

rafalenden’s picture

aendra’s picture

@rafal.enden -- I'm a bit confused; mind expanding on that? I don't see how that allows arbitrary JavaScript to be used with Panels content types (Though it does look interesting, might check it out in a bit).

rafalenden’s picture

I'm a bit confused; mind expanding on that?

Author of Contextual Entity list module created menu callback to execute AJAX call through pane edit form.

hefox’s picture

I think I got something similair working in latest patch in #2017159: Panopoly Magic: render preview outside of pane configuration form

alcroito’s picture

I've had a similar problem, where I wanted to include a Media element type into a CTools content type plugin, that also uses ajax for selecting an image.

It uses it's own ajax 'path' setting, instead of the 'callback' setting, but when selecting an image, the form was rebuilt without the media element entirely.

I traced this to the fact that drupal_rebuild_form couldn't find neither the CTools form wrapper function, nor the actual settings form function. So I fixed it by adding these lines of code to the ctools settings form:

    function custom_module_my_content_plugin_content_type_edit_form($form, &$form_state) {

    $background_image = isset($conf['background_image']) ? $conf['background_image'] : array();
      $form['background_image'] = array(
        '#title' => t('Background image'),
        '#default_value' => $background_image,
        '#type' => 'media',
        '#input' => TRUE,
        '#extended' => TRUE,
        '#tree' => TRUE,
        '#media_options' => array(),
      );

      // The two function calls below are necessary if we want to use a media
      // element type, because it causes ajax requests, which in turn call
      // drupal_form_rebuild(), and without the below includes, Drupal will
      // not be able to rebuild the form.

      // Include the CTools content type plugin file, because it provides
      // the ctools_content_configure_form_defaults() function, which is needed
      // when rebuilding the form, because of an ajax action, like selecting
      // a media element.
      ctools_form_include($form_state, 'content');

      // Include this plugin file as well, so that when the form is rebuilt, it
      // can successfully retrieve the settings form.
      ctools_form_include($form_state, 'my_content_plugin', 'custom_module', 'plugins/content_types/my_content_plugin');

    }

Maybe I'm missing something obvious why the include files are not loaded, but including them manually fixed the issue for me.

hamrant’s picture

Thank you, Placinta, #6 helped me a lot.
In my form I put:

      ctools_form_include($form_state, 'my_content_plugin', 'custom_module', 'plugins/content_types/my_content_plugin');

And this fixed ajax error.

capynet’s picture

#6 Fixed my need: Use ajax dependent fapi element on the ctool content_type settings form.

function section_header_edit_form($form, &$form_state) {
  ctools_form_include($form_state, 'content');
  ctools_form_include($form_state, 'section_header', 'my_custom_module', 'plugins/content_types');

  $form['text'] = array(
    '#title' => t('Text'),
    '#type' => 'text_format',
    '#format' => 'html',
    '#rows' => 8,
    '#default_value' => $conf['subtitle'],
    '#description' => t('Write an introduction here.'),
  );

  $form['background_image'] = array(
    '#title' => t('Background image'),
    '#type' => 'media',
    '#extended' => TRUE
  );

  return $form;
}
tom_ek’s picture

Just wanted to confirm that #6 fixes the issue. Indeed using ajax calls inside of the Custom Panes causes the form to be rendered without any custom-defined fields.

mustanggb’s picture

Status: Active » Closed (outdated)