5

I am using FAPI's AJAX property to save nodes asynchronously. When the associated AJAX callback gets called, it gets passed the $form and $form_state parameters respectively. I then simply call drupal_render($form) from the AJAX callback and voilá, the node edit page is refreshed asynchronously. This works well.

The problem that I am having is that I am only replacing the form, but I also want to replace the page title. The page title is not part of the node edit form; so I could change the node title on the edit form, but the page title would remain stale when saving and refreshing the form (note: the edited title does get saved into the db). I cannot target an element sitting higher in the DOM hierarchy because (ie, by changing pointing the wrapper to the body) because the AJAX callback is only aware of the form's contents.

drupal_render($form) works great, but I have the fear that if I where to point the wrapper to the body (or somewhere near it) and render the whole page, that this would have unintended consequences (such as skipping certain rendering steps, resulting in incomplete DOM data). That's why I thought of maybe adding a second AJAX callback to the form submit action: one for handling the form itself, another AJAX callback for handling the page title. Do you know if having more than one callback is possible? Can you think of a way of targeting two separate wrappers using FAPI's AJAX? Do you know if the path (instead of callback) property provides a solution for my problem? If path does work feel free to augment your answer with a short example.

Please limit answers to functionality supported by Drupal core. I am not interested in third-party modules that use their own javascript logic (ie, ctools, etc).

Sample code:

// Add ajaxified save button in hook_form_FORM_ID_alter (foo_form_node_form_alter).
$form['actions']['ajax_save']['#type'] = 'submit';
$form['actions']['ajax_save']['#access'] = TRUE;
$form['actions']['ajax_save']['#value'] = 'Save';
$form['actions']['ajax_save']['#submit'] = array(0 => 'foo_node_form_submit');
$form['actions']['ajax_save']['#weight'] = 9;

$form['actions']['ajax_save']['#ajax'] = array(
  'wrapper' => $form['#node']->type. '-node-form',
  'callback' => 'foo_ajax_callback',
  'method' => 'replace',
    'effect' => 'fade',
);

...    

function foo_ajax_callback(&$form, &$form_state = null) {

  $commands = array('#type' => 'ajax', '#error' => FALSE, '#commands' => array());
  $output = drupal_render($form);
  $commands['#commands'][] = ajax_command_insert(NULL, $output);
  // Prepend status messages to the node form.
  $commands['#commands'][] = ajax_command_prepend(NULL, theme('status_messages'));
  // Update the title on the page.
  $commands['#commands'][] = ajax_command_insert(NULL, $output);


return $commands;
}

1 Answer 1

6

Yes, you can solve it with core Drupal AJAX framework. You are already using $commands, you just need one more custom command.

Javascript code to provide new command:

(function ($) {
  Drupal.ajax.prototype.commands.change_title = function(ajax, response, status) {
    // Update the <head><title> element.
    document.title = response.data;

    // Update the page title.
    response.data = response.prefix + response.data;
    this.insert(ajax, response, status);
  }

})(jQuery);

PHP code to call this command:

  $commands['#commands'][] = array(
    'command' => 'change_title',
    'method' => 'html',
    // Selector targets Drupal 7's default theme <h1> title (Bartik 7.12).
    'selector' => 'div#branding h1.page-title',
    'data' => check_plain($form_state['node']->title),
    'settings' => NULL,
    'prefix' => '<em>Edit '. node_type_get_name($form_state['node']). '</em> ',
  );

Original idea is taken from here.

5
  • You know, I was actually not talking about the page title in <head><title>, but rather the one that is inside 'body (inside the default D7 theme). Your answer however solves another problem that I had not even thought about, while also providing a template to solve my problem! This is great, many thanks. Commented Aug 16, 2012 at 19:07
  • I'm want to accept your answer; but firt I want to extend it with code for the <h1> tag. I'm already working on the modification, let me know if you want me to post my solution as an edit or as my own answer. I think you deserve the edit (along with the accept), but let me know! Commented Aug 16, 2012 at 19:23
  • I think we can create Updated addition. I'll be happy to review.
    – kalabro
    Commented Aug 16, 2012 at 19:58
  • Expanded your answer with my modifications, thanks. Commented Aug 16, 2012 at 20:53
  • No sense to extend javascript class/function inside Drupal.attach. We need behaviors attachment when we call some functions which work with DOM. Here we just extend existing functions.
    – kalabro
    Commented Aug 16, 2012 at 21:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.