I have a custom field formatter on an Event node that displays data from a multifield in a simple HTML table (the multifield has a user entity reference field and a text field that contains a number of RSVPs for the event). In order to allow the user to enter a number for the text field, I'm displaying a ctools modal window containing a form with a text field. When the form is submitted, I want to do two things:

  1. Update the multifield in the node with the new data, and
  2. Update the table with the name as a link to remove the data from the node.

I've done something similar before where I update a node edit form from a modal using an ajax link, and I also have this working using an ajaxified link, but I'm having problems getting this to work from a form submit function in a modal window.

Here's the relevant code:

    function cfd_duty_menu() {
      $items = array();
    
      $items['rsvp/%ctools_js/%/%'] = array(
        'page callback' => 'cfd_duty_rsvp_page',
    	'page arguments' => array(1, 2, 3),
    	'access callback' => TRUE,
    	'type' => MENU_CALLBACK,
    );
    
      return $items;
    }
    
    /**
     * Page callback for ctools modal window.
     */
    function cfd_duty_rsvp_page($ajax, $uid, $nid) {
      if ($ajax) {
        //Load the modal library and add the modal javascript.
    	ctools_include('ajax');
    	ctools_include('modal');
    
        $form_state = array(
    	  'ajax' => TRUE,
    	  'title' => t('RSVP Form'),
    	  'uid' => $uid,
    	  'nid' => $nid,
    	);
    
        // Add custom settings for form size.
    	drupal_add_js(array(
    	  'rsvp-modal-style' => array(
    	    'modalSize' => array(
    	      'type' => 'fixed',
    		  'width' => 500,
    		  'height' => 500,
            ),
          ),
        ), 'setting');
    
    	// Use ctools to generate ajax instructions for the browser to create
    	// a form in a modal popup.
    	$output = ctools_modal_form_wrapper('cfd_duty_rsvp_form', $form_state);
    
        // If the form has been submitted, there may be additional instructions
        // such as dismissing the modal popup.
        if (!empty($form_state['ajax_commands'])) {
          $output = $form_state['ajax_commands'];
          }
    
    	// Return the ajax instructions to the browser via ajax_render().
    	print ajax_render($output);
    	drupal_exit();
    	}
        else {
          return drupal_get_form('cfd_duty_rsvp_form', $uid, $nid);
    	}
    }
    
    /**
     * Form function for RSVP modal form.
     *
     * @param $form
     * @param $form_state
     * @param $uid
     * @param $nid
     *
     * @return array
     */
    
    function cfd_duty_rsvp_form($form, $form_state) {
      $form = array();
    
      $user = entity_load('user', array($form_state['uid']));
      $user_name = $user[$form_state['uid']]->name;
    
      $form['name'] = array(
        '#type' => 'markup',
        '#markup' => '<div>' . $user_name . '</div>',
      );
    
      $form['event_nid'] = array(
        '#type' => 'value',
    	'#value' => $form_state['nid'],
      );
    
      $form['user_name'] = array(
        '#type' => 'value',
    	  '#value' => $user_name,
      );
    
      $form['rsvp_num'] = array(
       '#type' => 'textfield',
       '#title' => t('How many?'),
       '#size' => 2,
       '#maxlength' => 2,
      );
    
      $form['submit'] = array(
        '#type' => 'submit',
    	'#value' => t('Submit'),
      );
    
      return $form;
    }
    
    /**
     * Drupal form submit handler for RSVP form.
     */
    function cfd_duty_rsvp_form_submit(&$form, &$form_state) {
      $event_node = entity_load('node', array($form_state['nid']));
      $event_node = $event_node[$form_state['nid']];
      $uid = $form_state['uid'];
      $div_id = 'event-' . $uid;
      $rsvp_num = $form_state['values']['rsvp_num'];
    
      // First, need to check to make sure that the RSVP limit for this event has not been exceeded.
      $rsvp_limit = (int)$event_node->field_max_rsvp[LANGUAGE_NONE][0]['value'];
      if (count($event_node->field_rsvp_slots[LANGUAGE_NONE]) < $rsvp_limit) {
        // Add to field_volunteer.
        // Code to update the node goes here.
    
    	// Build the remove link.
    	$output = '<tr id="' . $div_id . '"><td>' . l(t($form_state['values']['user_name']), 'cfd_duty/signup/event/remove/' . $uid . '/' . $form_state['nid'] . '/nojs/', array(
          'attributes' => array(
    	  'class' => array('use-ajax'),
    	  'title' => t('Remove signup')
    	}
    	)) . '</td><td>' . $form_state['values']['rsvp_num'] . '</td></tr>';
      }
    
      //$form_state['ajax_commands'] = array();
      // Tell the browser to close the modal.
      $form_state['ajax_commands'][] = ctools_modal_command_dismiss();
      // Replace the div on the page.
      $form_state['ajax_commands'][] = ajax_command_replace($div_id, $output);
    }

And here's the HTML table markup (pretty simple).

    <table class="sticky-enabled">
      <caption>RSVPs</caption>
      <thead>
        <tr>
          <th>Name</th>
          <th>Count</th>
          </tr>
      </thead>
      <tbody>
        <tr id="event-13" class="odd">
          <td><a href="/rsvp/nojs/13/35/nojs/" class="use-ajax ajax-processed" title="Sign up">Sign up</a></td>
          <td></td>
        </tr>
      </tbody>
    </table>

When the submit function runs, the node is updated properly, but the content isn't changed. I've tried addig the `#` to the $div_id value, but it doesn't make a difference. If I add

$form_state['ajax_commands'][] = ctools_ajax_command_reload();

it reloads the page, but it's sort of clunky.

What do I need to do to get the markup replaced without having to reload the page?

Thanks.

Comments

MustangGB’s picture

Status: Active » Closed (outdated)