7.x ajax.inc ajax_command_replace($selector, $html, $settings = NULL)

Creates a Drupal Ajax 'insert/replaceWith' command.

The 'insert/replaceWith' command instructs the client to use jQuery's replaceWith() method to replace each element matched matched by the given selector with the given HTML.

This command is implemented by Drupal.ajax.prototype.commands.insert() defined in misc/ajax.js.

jQuery replaceWith command

Parameters

$selector: A jQuery selector string. If the command is a response to a request from an #ajax form element then this value can be NULL.

$html: The data to use with the jQuery replaceWith() method.

$settings: An optional array of settings that will be used for this command only.

Return value

An array suitable for use with the ajax_render() function.

See

Related topics

1 call to ajax_command_replace()
file_ajax_upload in modules/file/file.module
Menu callback; Shared Ajax callback for file uploads and deletions.

File

includes/ajax.inc, line 901
Functions for use with Drupal's Ajax framework.

Code

function ajax_command_replace($selector, $html, $settings = NULL) {
  return array(
    'command' => 'insert',
    'method' => 'replaceWith',
    'selector' => $selector,
    'data' => $html,
    'settings' => $settings,
  );
}

Comments

liupascal’s picture

Hey

The current behavior of Replace is to replace the content with a "fadeIn" effect. Is it possible to customize this effect ?

On the other hand, what is the $settings argument ?

Thanks !

Les Lim’s picture

http://api.drupal.org/api/drupal/includes!ajax.inc/function/ajax_command_append/7#comment-39488

Also, the Drupal.ajax.element_settings.effect default value is "none", not "fade". If you're seeing a fadeIn, it's probably been set somewhere.

michaelfavia’s picture

If you find your replaced content being encapsulated in a new div and you dont want it consider placing all of your new html under one parent tag and jquery wont have to make a container div for you.

jh8313’s picture

Hii,

I am trying to add a html div tag with a specific id with ajax_command_replace function. By default this is a simple div tag with no id. Maybe I should use settings options?

My callback function :

ajax_command_replace('#divtable', render(theme('table',$table))),

So I would like to have an id='div_name' in my replacing table.

Thk.

tea.time’s picture

I was having the same issue as michaelfavia above: my new markup got wrapped in a <div> when it got inserted into the page. The markup already had a single top-level element, so that wasn't the issue.

The problem turned out to be that the content was coming from a theme() call pulling in a template file, and once I removed all the extra newlines in the template, jQuery no longer created the div wrapper.

Addendum: in my case, I realized that an easy way to remove newlines is rather than having to make sure there are none in the tpl file itself, just strip them out after you've grabbed your theme()d markup:

$new_markup = str_replace(array("\r", "\n"), "", $new_markup);

Then you needn't mess with clear formatting in the template. :)

Johann Wagner’s picture

Thank you, I confirm this. Replacing a selector with content starting with a newline will produce a wrapping div

// This will give you an extra wrapping div around #some_div.
$rendered =  "\n" . '
'; // So consider stripping all new lines from rendered and themed content. $rendered = str_replace(array("\r", "\n"), '', render($render_array));
reptilex’s picture

I confirm this too. I was going nuts about this. You made my day.

loze’s picture

Having an HTML comment before or after the markup also inserts a wrapping div.

moonray’s picture

A simpler fix was to simply trim the whitespace around my rendered markup.

$new_markup = trim($new_markup);

firewaller’s picture

This works! Thank you.

meaton’s picture

I also experience the extra line in my template file causing a wrapping div. Thank you for pointing this out!

Cameron Tod’s picture

If you're trying to use a general selector to replace several elements at once, you'll find that only one is replaced. Instead, you need a command for each element you want to replace.

For example:

<span class='option' id="option-1">This</span>
<span class='option' id="option-2">That</span>

This won't work:

// Using a class to select two elements.
$selector = ".option";
$commands[] = ajax_command_replace($selector, 'something new');

This will:

// Using two calls to ajax_command_replace, each with a selector that selects one element.
$commands[] = ajax_command_replace('#option-1', 'something new');
$commands[] = ajax_command_replace('#option-2', 'something new');
hbricha’s picture

#cam8001: Did you find solution for this. i want to call ajax_command_replace on every call....

NigelCunningham’s picture

I came across this too - it's a jquery bug:

https://github.com/jquery/jquery/pull/920

mpark’s picture

Hello, I'm trying to turn enabled a field that was previously disabled. its line item field (Drupal commerce) in my Ad to cart form here: http://www.opojisteni.eu/airport-taxi

If user click to Return in Journey type option, I would like to enabled fieldset "Pick-up time for your return journey".

This is my custom code with hook_form_alter:

<?php
if ($form_id == $form_airport_taxi) {
  .......................................
    $form['line_item_fields']['field_pick_up_time_return']['#disabled'] = TRUE;
    $form['line_item_fields']['field_pick_up_time_return']['#prefix'] = '<div id="field-pickup-return">';
    $form['line_item_fields']['field_pick_up_time_return']['#suffix'] = '</div>';
  }
  return $form;
}

function readonlyfield_commerce_cart_attributes_refresh_alter(&$commands, $form, $form_state) {
  // cant use classic #ajax => 'name_of_callback' because field Journe type has own callback function commerce_cart_attributes_refresh

  if($form_state['values']['attributes']['field_journey_type'] == "One") {
      $form['line_item_fields']['field_pick_up_time_return']['#disabled'] = TRUE;
    }
    else if ($form_state['values']['attributes']['field_journey_type'] == "Return") {
      $form['line_item_fields']['field_pick_up_time_return']['#disabled'] = FALSE;
    }
  // $commands[] = ajax_command_alert(render($form['line_item_fields']['field_pick_up_time_return']['#disabled']));
  $commands[] = ajax_command_replace('#field-pickup-return', render($form['line_item_fields']['field_pick_up_time_return']));
  return array('#type' => 'ajax', '#commands' => $commands);
}
?>

If I run this code, nothing change in my form. Only one thing is interesting:
I can see the changes in form code:
Before calling ajax (select Return option)

<?php
<div id="field-pickup-return">
<div class="field-type-datestamp field-name-field-pick-up-time-return field-widget-date-select form-wrapper" id="edit-line-item-fields-field-pick-up-time-return">
<div id="line-item-fields-field-pick-up-time-return-add-more-wrapper">
<fieldset class="form-wrapper">
<legend><span class="fieldset-legend">Pick-up time for your return journey </span></legend>
<div class="fieldset-wrapper">
<div  class="date-no-float container-inline-date">
<div class="form-item form-type-date-select form-item-line-item-fields-field-pick-up-time-return-und-0-value form-disabled">
....................
?>

and after

<?php
<div id="field-pickup-return">
<div class="field-type-datestamp field-name-field-pick-up-time-return field-widget-date-select form-wrapper" id="edit-line-item-fields-field-pick-up-time-return--2"> // --2???

// its new, the same line, its twice!
<div class="field-type-datestamp field-name-field-pick-up-time-return field-widget-date-select form-wrapper" id="edit-line-item-fields-field-pick-up-time-return--2">

<div id="line-item-fields-field-pick-up-time-return-add-more-wrapper--2">
<fieldset class="form-wrapper date-processed">
<legend><span class="fieldset-legend">Pick-up time for your return journey </span></legend>
<div class="fieldset-wrapper">
<div class="date-no-float container-inline-date"><div class="form-item form-type-date-select form-item-line-item-fields-field-pick-up-time-return-und-0-value form-disabled">
................
?>

How can I solve this problem? Thank you very much,
Mark

velocis’s picture

I had a similar issue with drupal Paragraphs module when creating new content and neither the primary node record or any of the embedded Paragraphs that have just been added are saved either.
So using ajax I was allowing the user to replace a textbox with the return of an ajax call. But each time I added another paragraph, those existing textbox's id's would change --2. --3 etc etc

I found the part that adds these --# to controls, its part of function drupal_html_id($id) {} in common.inc

I was able to create a variant of that code in a function of my module to get the current highest numbered instance of a said field. Please notice change of the default value in the else statement to 0 from 1 in the original code.

// This functionality is taken from common.inc line 4000

function _MYMODULE_get_current_drupal_html_id($replace_field_base_id) {
  $ajax_html_ids = $_POST['ajax_html_ids'];
  
  foreach ($ajax_html_ids as $seen_id) {
    // We rely on '--' being used solely for separating a base id from the
    // counter, which this function ensures when returning an id.
    $parts = explode('--', $seen_id, 2);
    if (!empty($parts[1]) && is_numeric($parts[1])) {
      list($seen_id, $i) = $parts;
    }
    else {
      $i = 0; // Changed this to 0 from original code in drupal_html_id()
    }
    if (!isset($seen_ids_init[$seen_id]) || ($i > $seen_ids_init[$seen_id])) {
      $seen_ids_init[$seen_id] = $i;
    }
  }

  if (!is_null($replace_field_base_id)){
    return $seen_ids_init[$replace_field_base_id];
  }

  return null;

}

I was using this in coordination with hook_field_widget_form_alter to add a button to a paragraph once the user uploaded an image, this button then needed to target the textbox on the same paragraph.
I am interested if there is an easier way to get this information for Paragraph items that are not yet saved...

valthebald’s picture

remember to use correct syntax to return results of this (and other ajax_command_* functions:

$commands[] = ajax_command_replace(...);
return array('#type' => 'ajax', '#commands' => $commands);
gusantor’s picture

documentation says "$selector: A jQuery selector string"

I tried

$commands[] = ajax_command_replace("$('#my-div')", $text);

but no luck, instead use css selector

$commands[] = ajax_command_replace("#my-div", $text);