I've got a situation where I want to prevent a new field_collection item from being added when an unlimited number of values has been specified.

To be able to remove the item that's added by default, I'm using HOOK_form_alter to remove the relevant items from the $form array and decrement each fields '#max_delta' value by one.

Once implemented the AJAX add button functions - but the delete button doesn't function, and returns the following error in a JS popup.

An AJAX HTTP error occurred.
HTTP Result Code: 500
Debugging information follows.
Path: /field_collection/ajax
StatusText: error
ResponseText: Recoverable fatal error: Argument 2 passed to drupal_array_set_nested_value() must be an array, null given, called in /var/aegir/platforms/drupal-7.0/includes/form.inc on line 2438 and defined in drupal_array_set_nested_value() (line 6384 of /var/aegir/platforms/drupal-7.0/includes/common.inc).

The code I'm using below is

<?php
       $restrict_multiple_fields
=array('field_personnel_ref','field_client_ref','field_milestone_ref','field_notes_ref');
       
// prevent new fields for unlimited types being added by default for certain fields.
       
foreach($restrict_multiple_fields as $field_name)  {
          if (empty(
$form[$field_name])) break;
         
$field_language = $form[$field_name]['#language'];
         
$max_delta = $form[$field_name][$field_language]['#max_delta'];
          unset(
$form[$field_name][$field_language][$max_delta]);
         
$form[$field_name][$field_language]['#max_delta'] = $max_delta-1;
        }
?>

I'm not sure whether this should be classed as a bug report or support request, as I'm not sure whether I should be performing any additional stages to rebuild the $form or $form_state.

Any advice appreciated.

Comments

I'm not using the same method to remove the default item on edit or add, but I've the same problem too. I'm using this http://drupal.org/node/1239946#comment-5660526 and got the same error. Any ideas?

Well I am having the same issue too, and believe it has to do with the use of ajax_get_form as it gets this from the cache. I wonder whether it is being cached BEFORE we unset the variable, and therefore cause the AJAX to call invalid information. I will try and look further into this at some point when I get more time.
http://api.drupal.org/api/drupal/includes!ajax.inc/function/ajax_get_form/7

if you find any solution, please let me know :)

Ok, initial play this evening, and I have something worth playing with a bit. If you look in field_collection.module you will see some code around line 1138 marked:

<?php
    $removed_element
= drupal_array_get_nested_value($form, $removed_element_address);
   
form_set_value($removed_element, NULL, $form_state);
   
drupal_array_set_nested_value($form_state['input'], $removed_element['#parents'], NULL);
?>

The issue appears to be that $removed_element is empty, this is due to use removing the variable. One solution to this is the one I briefly tried, and appears to work. We wrap an isset() around those 3 lines:

<?php
 
if(isset($removed_element)){
   
$removed_element = drupal_array_get_nested_value($form, $removed_element_address);
   
form_set_value($removed_element, NULL, $form_state);
   
drupal_array_set_nested_value($form_state['input'], $removed_element['#parents'], NULL);
  }
?>

Now, it would be much better if we could stop this from outside of this module, but if this doesn't break anything else, I will look into writing a patch and see if it's of use to anyone else.

If anyone else tries it, please let me know of your findings.

Dan

Have created a patch this morning, general testing appears to work fine. This is my first patch in git, so hopefully I have done it right. If there are issues, let me know and I will make amends.

The patch works great for me :). Thx for the quick fix!

This removes the js error message but my field collection item does not get removed. And it breaks another js behavior on my form (term reference tree).

I had this exact same issue while using the same technique to restrict the empty value that appears by default on an unlimited value field collection. I really did not want to touch the field_collection module for this special case.

After a lot of trial and error, I found this to work well:

foreach ($form as $key => $data) {
    // Only act on fields
    if (substr($key, 0, 6) == 'field_') {
      $field_language = node_form_extras_get_language($form, $key);
      if (isset($form[$key][$field_language]['#cardinality'])) {
        // A cardinality of -1 means unlimited, 1 != multi-value.
        $cardinality = $form[$key][$field_language]['#cardinality'];
        if ($cardinality == '-1' || intval($cardinality) > 1) {
          $max_delta = $form[$key][$field_language]['#max_delta'];
          if ($max_delta) {
            $form[$key][$field_language][$max_delta]['#access'] = FALSE;
          }
        }
      }
    }
  }

Note that this code is written to automatically affect all fields on a given form, as opposed to the original solution. The important difference, however, is by calling ['#access'] = FALSE on the field rather than unsetting the #max_delta.

It may not be the purest solution, but I'm not sure the original technique is either. If a better solution is discovered, I'd love to hear about it.

Gus

I guess this works ok, but it still shows the empty handler .. any way to make the form hide it?