This is a very frustrating and recurring problem for me because it seems to come and go at random, one minute it is working beautifully, the next moment I make a change and it breaks. Even if I change everything back the way it was and clear the cache again it is still broken.

I have a form, in the form is a table that allows users to enter ingredients into the form. There is a "More ingredients" button. Once clicked an AJAX call is made and the form is rebuilt and a new row is appended to the table. For some reason This "More ingredients" button has been broken. On click, it adds one ingredient, then on the second click, nothing. The button will not even trigger the receding animation as it does other buttons, it is as if the button has just disapeared...

Here is the code.

relevant form function

 if (isset($form_state['add_ingredients'])) {

//reset add ingredients under form_state

//Get number of added ingredient for proper naming below.  Allows us to use row theme instead of table theme for loading only an ingredient.
$ing_number = count($node->recipe_ingredients['ing']);

//Be sure ajax returns proper row number.
$form_state['ing_number'] = $ing_number;

//Add ingredient to our ingredients array.
array_push($node->recipe_ingredients['ing'], array('ri_id' => NULL, 'name' => '', 'quantity' => '', 'unit_key' => '',  'note' => '', 'weight' => $max_weight + 1));

//Theme this row only, uses $ing_number to designate it will only be themed by row theme function, not table.
$form['recipe_ingredients']['ing'][$ing_number] = array(
    '#theme' => 'ingredients_row',
    '#row_number' => $ing_number

. . .

$form['recipe_ingredients']['recipe_more_ingredients'] = array(
'#type' => 'submit',
'#name' => 'ingredientadd',
'#value' => t('More ingredients'),
'#description' => t("If the amount of boxes above isn't enough, click here to add more ingredients."),
'#weight' => 1,
'#submit' => array('recipe_more_ingredients_submit'),
'#limit_validation_errors' => array(),
'#ajax' => array(
  'callback' => 'recipe_more_ingredients_js',
  'wrapper' => 'ingredient-list',
  'effect' => 'fade',
  'method' => 'append'


function recipe_more_ingredients_submit($form, &$form_state) {
//Set Drupal's form rebuild option to true...  not sure if this is really needed...
$form_state['rebuild'] = TRUE;

// If they clicked the more ingredients button, flag it in form_state['add_ingredients']
  if ($form_state['values']['recipe_ingredients']['recipe_more_ingredients']) {
   $form_state['add_ingredients'] = TRUE;


Ajax Callback

function recipe_more_ingredients_js($form, &$form_state) {

return $form['recipe_ingredients']['ing'][$form_state['ing_number']];


Row theming function

function theme_ingredients_row($variables) {

$form = $variables['form'];

$row_number = $form['#row_number'];

// Build the table row.
$row = array(
    'data' => array(
    drupal_render($form['ri_id']) . drupal_render($form['quantity']),
  $row['data'][] = drupal_render($form['unit_key']);
  $row['data'][] = drupal_render($form['name']);
  $row['data'][] = drupal_render($form['note']);
  $row['data'][] =  '<button class="ing-remove" type="button">Remove</button>';

//Start HTML of row  
$output = '<tr ' . ' id="' . 'ing-' . $row_number . '"' . '>';

//Wrap each cell in proper HTML tags
foreach ($row['data'] as $key => $value) {

    $output .= '<td>' . $value . '</td>';


$output .= '</tr>';

watchdog('ROW', $output, null, $severity = WATCHDOG_NOTICE);

return $output;

  • If I am reading this right (this method is a little strange to me) it may just be that you are not returning the changed form element in your callback. You should return your wrapper element $form['ingredient-list']. That element should be wrapping your recipe ingredients. – sareed Jul 24 '15 at 21:19

Sadly that still doesn't work... The problem is not that php, it calls the website only the first time. The second time the button is broken. It does not click, call Drupal or anything. Also any buttons added to page with ajax do not work either, even though their pre-loaded counterparts work perfectly fine with jquery.

  • I ran into this problem and got around it by allowing the form to build the buttons and then I hid them with javascript. This allowed Drupal to build the plumbing for the buttons so subsequent Ajax calls could put them back in and they would work. – zkent Dec 2 '15 at 20:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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