Wysiwyg button with form #4

Print

Welcome to the second article in my tutorial about building a wysiwyg button for drupal 7 which enables use to inserting tokens.

This will be a four step tutorial

This next part will cover how to expand the form to use ajax for dynamic adding and removing fields.

I followed this exellent article about how to implement det dynamic adding and removing fields, but since we are using jquery ajax to load our for we don't have the luxury of drupals ajax to ensure ajax handling for our form and we need to add this in.

but first we need to exend our for to include ajax processing.

  1. /**
  2.  * Insert token form
  3.  */
  4. function example_insert_form($form, &$form_state) {
  5.   drupal_add_library('system', 'ui.dialog');
  6.   $form['#tree'] = TRUE;
  7.   if (empty($form_state['num_objects'])) {
  8.     $form_state['num_objects'] = 1;
  9.   }
  10.   $ids = null;
  11.   $args = $form_state['build_info']['args'];
  12.   if(isset($args[0])) {
  13.     $ids = explode(',', $args[0]);
  14.     if($form_state['num_objects'] == 1) {
  15.       $form_state['num_objects'] = count($ids);
  16.     }
  17.   }
  18.   $form['objects'] = array(
  19.     '#type' => 'fieldset',
  20.     '#title' => t('Objects'),
  21.     '#prefix' => '<div id="example-fieldset-wrapper">',
  22.     '#suffix' => '</div>',
  23.   );
  24.  
  25.   for($i = 0; $i < $form_state['num_objects']; $i++) {
  26.     $form['objects'][$i]['object'] = array(
  27.       '#type' => 'textfield',
  28.       '#title' => t('Entity id'),
  29.       '#prefix' => '<div class="col1">',
  30.       '#suffix' => '</div>',
  31.       '#default_value' => isset($form_state['values'][$i]) ? $form_state['values'][$i]['object'] : '',
  32.     );
  33.     if(isset($ids[$i])) {
  34.       $form['objects'][$i]['object']['#default_value'] = $ids[$i];
  35.     }
  36.   }
  37.  
  38.   $form['objects']['add_item'] = array(
  39.     '#type' => 'submit',
  40.     '#value' => t('Add another'),
  41.     '#submit' => array('example_add_more_add_one'),
  42.     // See the examples in ajax_example.module for more details on the
  43.     // properties of #ajax.
  44.     '#ajax' => array(
  45.       'callback' => 'example_add_more_callback',
  46.       'wrapper' => 'example-fieldset-wrapper',
  47.       'method' => 'replace',
  48.       'effect' => 'fade',
  49.     ),
  50.   );
  51.   if ($form_state['num_objects'] > 1) {
  52.     $form['objects']['remove_item'] = array(
  53.       '#type' => 'submit',
  54.       '#value' => t('Remove one'),
  55.       '#submit' => array('example_add_more_remove_one'),
  56.       '#ajax' => array(
  57.         'callback' => 'example_add_more_callback',
  58.         'wrapper' => 'example-fieldset-wrapper',
  59.         'method' => 'replace',
  60.         'effect' => 'fade',
  61.       ),
  62.     );
  63.   }
  64.   $form['submit'] = array(
  65.     '#type' => 'submit',
  66.     '#value' => t('Submit'),
  67.     '#attributes' => array(
  68.       'class' => array('form-save-ids'),
  69.     ),
  70.   );
  71.  
  72.   return $form;
  73. }
  74.  
  75. /**
  76.  * Callback for both ajax-enabled buttons.
  77.  *
  78.  * Selects and returns the fieldset with the names in it.
  79.  */
  80. function example_add_more_callback($form, $form_state) {
  81.   return $form['objects'];
  82. }
  83.  
  84. /**
  85.  * Submit handler for the "add-one-more" button.
  86.  *
  87.  * Increments the max counter and causes a rebuild.
  88.  */
  89. function example_add_more_add_one($form, &$form_state) {
  90.   $form_state['num_objects']++;
  91.   $form_state['rebuild'] = TRUE;
  92. }
  93.  
  94. /**
  95.  * Submit handler for the "remove one" button.
  96.  *
  97.  * Decrements the max counter and causes a form rebuild.
  98.  */
  99. function example_add_more_remove_one($form, &$form_state) {
  100.   if ($form_state['num_objects'] > 1) {
  101.     $form_state['num_objects']--;
  102.   }
  103.   $form_state['rebuild'] = TRUE;
  104. }

As you can see we are using a simple count setting to increase or decrease the number of text fields in the form. This works fine for our simple form and we just need to add a few changes to the js in order to forward this change from the client to the backend. So make the following change to the insert_form function:

  1.   insert_form: function (data, settings, instanceId) {
  2.     // Location, where to fetch the dialog.
  3.     var aurl = Drupal.settings.basePath + 'example/insert/ajax';
  4.     if(settings.ids) {
  5.       aurl += '/' + settings.ids.join();
  6.     }
  7.     var dialogdiv = $('<div id="example-insert-dialog"></div>');
  8.     dialogdiv.load(aurl, function(){
  9.       var dialogClose = function () {
  10.         try {
  11.           dialogdiv.dialog('destroy').remove();
  12.         } catch (e) {};
  13.       };

Now that we have this in place we need to expand our menu so we can send the id variables to the form.

  1. /**
  2.  * implements hook_menu
  3.  */
  4. function example_menu() {
  5.   $items = array();
  6.   $items['example/insert/nojs'] = array(
  7.     'page callback' => 'example_get_insert_form',
  8.     'page arguments' => array(2),
  9.     'access callback' => TRUE,
  10.     'type' => MENU_CALLBACK,
  11.   );
  12.   $items['example/insert/ajax'] = array(
  13.     'delivery callback' => 'ajax_deliver'
  14.   ) + $items['example/insert/nojs'];
  15.  
  16.   $items['example/insert/nojs/%'] = array(
  17.     'page callback' => 'example_get_insert_form',
  18.     'page arguments' => array(2, 3),
  19.     'access callback' => TRUE,
  20.     'type' => MENU_CALLBACK,
  21.   );
  22.   $items['example/insert/ajax/%'] = array(
  23.     'delivery callback' => 'ajax_deliver'
  24.   ) + $items['example/insert/nojs/%'];
  25.   return $items;
  26. }

If you implement this, you will find that the ajax callbacks aren't exactly using ajax yet. This is because as I said we don't have the luxury of drupals ajax handing when we are using the jquery ajax load function. In order to fix this we need to make a few changed to the ajax get form function so we compile the scripts and add then to the data being returned.

  1. /**
  2.  * Retrive the insert form.
  3.  */
  4. function example_get_insert_form($ajax, $ids = '') {
  5.   $is_ajax = $ajax === 'ajax';
  6.   $form = drupal_get_form('example_insert_form', $ids);
  7.   if ($is_ajax) {
  8.     $form = drupal_render($form);
  9.     // Generate the settings:
  10.     $settings = '';
  11.     $javascript = drupal_add_js();
  12.     if(isset($javascript['settings'], $javascript['settings']['data'])) {
  13.       $settings = '<script type="text/javascript">jQuery.extend(Drupal.settings, ';
  14.       $settings .= drupal_json_encode(call_user_func_array('array_merge_recursive', $javascript['settings']['data']));
  15.       $settings .=  ');</script>';
  16.     }
  17.     die($form . $settings);
  18.   }
  19.   else {
  20.     return $form;
  21.   }
  22. }

Now that this is done, the form uses ajax to add or remove fields to the form and it keeps the already entered data while doing to.

I hope this helps and if you have any questions let me now. For a working version of this see ting_object

Category: 

Add new comment

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.