This is a great module, something that's been long overdue.

One query, how do you delete a flexifield item once it's been crated? I assume by deleting the content? Perhaps a delete item would be useful?

Thanks,

Anthony

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

platform8-1’s picture

I agree - this module is sick. Nice job.

effulgentsia’s picture

Title: This is a wonderful module! » Make it easier to delete an item
Assigned: Unassigned » effulgentsia
Category: support » feature

I agree that needing to delete all the content to delete an item is not the best UI, and that a button/checkbox for doing it would be better.

gagarine’s picture

I think is a cck issue http://drupal.org/node/196421 for all multiple value. But perhaps they have a easy way to do this...

Anonymous’s picture

If this is a CCk issue, you should considder ignoring empty flexifields containing mandatory fields. This is related to the issue #390480: Sub-fields of flexifield set as required fail validation on node save., but it's not the same:

In the linked issue, the check fails even for fields that are filled with content.

Here, you should avoid the check for an item, in which all fields are empty, as this is the way, items are deleted in CCK at the moment (again, see #196421: Deleting unwanted multiple values / multiple values delta issues for more information)

stefan81’s picture

I would also love to see a "delete" button.

westbywest’s picture

Here is my kludge to add a delete checkbox to each flexifield on the node edit form, and also to trim away all but one blank flexifield on a node add form. The flexifield CCK field is simply named "field_flex" for legibility.

function foo_form_alter(&$form, &$form_state, $form_id) {
  switch($form_id) {

  case 'foo_node_form':

     if (is_array($form['field_flex'])) {

       //Trim off the blank items that flexifield always wants to add
       //on each form display.
       if (arg(1) == 'add') {
         for ($i = 1 ; $i < count($form['field_flex']) ; $i ++ ) {
           if (isset($form['#field_info']['field_flex']['widget']['default_value'][$i])) {
             unset($form['#field_info']['field_flex']['widget']['default_value'][$i]);
           }
           if (isset($form['field_flex'][$i])) {
             unset($form['field_flex'][$i]);
           }
         }
       }

       elseif (arg(2) == 'edit') {
         $k = count($form['field_flex']);
         for ($i = count($form['#node']->field_flex) ; $i < $k ; $i ++ ) {
           if (isset($form['field_flex'][$i])) {
             unset($form['field_flex'][$i]);
           }
         }
       }

       foreach ($form['field_flex'] as $key => &$flex) {

         //Add a delete checkbox next to each non-blank field
         if (is_array($flex) && isset($flex['#default_value']['item_id'])) {
             $flex['field_flex_delete'] =
               array(
                     '#type' => 'checkbox',
                     '#name' => 'field_flex_delete_'.$flex['#default_value']['item_id'],
                     '#return_value' => '1',
                     '#default_value' => '0',
                     '#prefix' => '<b>Check to Delete</b>:');
         }
       }
     }

   $form['#submit'][] = '_foo_flex_node_form_submit';
   break;

  }
}

/**
 * Delete any field_flex where the delete checkbox is checked
 */
function _foo_flex_node_form_submit(&$form, &$form_state) {

  if (is_array($form['field_flex'])) {
    //loop thru all items in field_flex
    foreach ($form['field_flex'] as $key => &$flex) {

      if (isset($flex['field_flex_delete']['#name'])) {
          $name = $flex['field_flex_delete']['#name'];

          if (isset($form['#post'][$name]) && $form['#post'][$name] == '1' ) {

            //Extract numerical itemId for this flexifield, verify it is a valid positive number
            preg_match('{(\d+)}',$name,$m);
            if (isset($m[1]) && $m[1] ) {
              unset($form_state['values']['field_flex'][$key]);
            }
          }
        }
      }
}
Silhouette’s picture

I made some changes to the above code to make it more generic and I used it within flexifield.module. I haven't tested to see if it works with multiple flexifields

function flexifield_form_alter(&$form, &$form_state, $form_id) {
	if(is_array($form) && is_array($form['#field_info']) ){
	foreach($form['#field_info'] as &$fields) {
		if(is_array($fields) && $fields['type'] == 'flexifield' && is_array($form[$fields['field_name']]))
		{
			$form_field = $form[$fields['field_name']];
		  //Trim off the blank items that flexifield always wants to add
		   //on each form display.
		   if (arg(1) == 'add') {
			 for ($i = 1 ; $i < count($form_field) ; $i ++ ) {
			   if (isset($field['widget']['default_value'][$i])) {
				 unset($field['widget']['default_value'][$i]);
			   }
			   if (isset($form_field[$i])) {
				 unset($form_field[$i]);
			   }
			 }
		   }

		   elseif (arg(2) == 'edit') {
			 $k = count($form_field);
			 for ($i = count($form['#node']->field_flex) ; $i < $k ; $i ++ ) {
			   if (isset($form_field[$i])) {
				 unset($form_field[$i]);
			   }
			 }
		   }

       foreach ($form[$fields['field_name']] as $key => &$flex) {
         //Add a delete checkbox next to each non-blank field
         if (is_array($flex) && isset($flex['#default_value']['item_id'])) {
             $flex['field_flex_delete'] =
               array(
                     '#type' => 'checkbox',
                     '#name' => 'field_flex_delete_'.$flex['#default_value']['item_id'],
                     '#return_value' => '1',
                     '#default_value' => '0',
                     '#prefix' => '<b>Check to Delete</b>:');
         }
       }
		   $form['#submit'][] = '_flexifield_flex_node_form_submit';
		 }
	}
   }
}

/**
* Delete any field_flex where the delete checkbox is checked
*/
function _flexifield_flex_node_form_submit(&$form, &$form_state) {

	foreach($form['#field_info'] as &$fields) {
		if(is_array($fields) && $fields['type'] == 'flexifield')
		{
		  if (is_array($form[$fields['field_name']])) {
			//loop thru all items in field_flex
			foreach ($form[$fields['field_name']] as $key => &$flex) {

			  if (isset($flex['field_flex_delete']['#name'])) {
				  $name = $flex['field_flex_delete']['#name'];

				  if (isset($form['#post'][$name]) && $form['#post'][$name] == '1' ) {

					//Extract numerical itemId for this flexifield, verify it is a valid positive number
					preg_match('{(\d+)}',$name,$m);
					if (isset($m[1]) && $m[1] ) {
					  unset($form_state['values'][$fields['field_name']][$key]);
					}
				  }
				}
			  }
			}
		}
	}
}
ice5nake’s picture

I think a delete button is needed for this module to hit a stable release.

jpklein’s picture

FileSize
1.51 KB

@ice5nake - totally agree. And I think it's awesome that there's a few of us doing parallel development on this.

I tried implementing the code in #6 & #7 on my installation running alpha5, but I had a problem after hitting the "Add Another Item" button below the flexifield (it was set to 'Unlimited' number of values). Ihe issue is that the AHAH callback bound to the button doesn't reload the entire form and bypasses the form_alter hook which inserts the checkbox.

Instead, I moved the code to create this element to flexifield_default_widget_process() in flexifield.module:

   // Checkbox element for removing this item
      $flexiName = $aElement['#name'];
      preg_match('/^(.*)\[(.*)\]$/', $flexiName, $matches);
      $flexiId = str_replace('_', '-', $matches[1]);
      $flexiDelta = $matches[2];
      $aElement['_remove'] = array(
        '#type' => 'checkbox',
        '#default_value' => $aElement['#value']['_remove'],
        '#title' => '<span>Remove item</span>',
        '#weight' => '-50',
      );
      $aElement['_remove']['#attributes']['class'] = 'flexi-remove'; 

Perhaps because I'm developing on top of alpha5 instead of dev, I didn't see the ['#default_value']['item_id'] form value on which @Silhouette's code seems to depend so I worked around that.

I also cleaned-up the form_alter function - sans the extra-item removal routine - to reduce the amount of code loops, and dynamically add jscript to enhance the UI (see attachment):

 /**
 * Implementation of hook_form_alter().
 */
function flexifield_form_alter(&$form, &$form_state, $form_id) {
  // Traverse form array to see if it contains a flexifield.
  $contains_flexi = FALSE;
  if(is_array($form) && is_array($form['#field_info'])) {
    foreach($form['#field_info'] as $fields) {
      if(is_array($fields) && $fields['type'] == 'flexifield' && is_array($form[$fields['field_name']])) {
        $contains_flexi = TRUE;
        break;
      }
    }
  }
  if ($contains_flexi) {
    // Add javascript/css to restyle 'Remove item' checkbox.
    $form[$fields['field_name']]['#after_build'][] = '_flexifield_theme_node_form';
    // Append submit function to remove selected items.
    $form['#submit'][] = '_flexifield_node_form_submit';
  }
}

/**
 * Deletes the form entry for flexifields whose _remove value is set.
 */
function _flexifield_node_form_submit(&$form, &$form_state) {
  if(is_array($form) && is_array($form['#field_info'])) {
    foreach($form['#field_info'] as $fields) {
      if(is_array($fields) && $fields['type'] == 'flexifield' && is_array($form[$fields['field_name']])) {
        $name = $form[$fields['field_name']]['#name'];
        foreach($form['#post'][$name] as $key => &$flexi) {
          if (isset($flexi['_remove']) && $flexi['_remove']) {
            unset($form_state['values'][$fields['field_name']][$key]);
          }
        }
      }
    }
  }
}

/**
 * Add our item-removal-UI script to the form.
 */
function _flexifield_theme_node_form($element) {
  $path = drupal_get_path('module', 'flexifield');
  drupal_add_js($path . '/js/flexifield_remove.js');
  return($element);
} 

The script converts the checkbox into a link and collapses items with a warning message that they will be removed when the form is submitted. Without directly editing tabledrag.js, I had to work around the row objects/elements it creates to display warnings. It seems to be working pretty well, though it doesn't seem to get reloaded if the form gets returned with an error (when the node is missing required fields, for example).

Any ideas/comments greatly encouraged!

jpklein’s picture

FileSize
1.09 KB

Ooops. looks like the last attachment got mangled in translation. Please use this one instead.

jpklein’s picture

Looks like I answered my own question: instead of binding _flexifield_theme_node_form() to an element in the form, instead just append it to the #after_build attribute of the form itself. So in the flexifield_form_alter() above, make the following change:

 ...
  if ($contains_flexi) {
    // Add javascript/css to restyle 'Remove item' checkbox.
    $form['#after_build'][] = '_flexifield_theme_node_form';
    // Append submit function to remove selected items.
... 

hope it helps!

jguffey’s picture

@jpklein Thanks for the hard work! In your comment #9, second block, I'm not sure where you're putting this code so I dropped it into the end of the flexifield module. Made the other changes outlined in comments #10 and #11 and nothing in my flexinode field has changed :( Maybe you can point me in a better direction, or maybe roll you modified alpha 5 for us regular folk!

Thanks a ton for the help, this module solves a lot of my Drupal related gripes.

jguffey’s picture

FileSize
43.37 KB

ohhhh K,

so never mind the problem above, but do note, If you implement these fixes, you will have to recreate your field to get the remove link.

I've attached my version of the module with changes suggested by @jpklein, this variation is based on Alpha 5.

jpklein’s picture

Bump. @effulgentsia, any chance of this being adapted/rolled into a dev release?

Macronomicus’s picture

+ + thanks jguffey!
Works perfectly! I will second that this would be great in the dev at least.

Macronomicus’s picture

jguffey ... could you provide a patch and/or make this on the dev branch?
The dev has a fix for the Add Another bug that your module using the alpha missing.

Cheers!

Boobaa’s picture

Version: 6.x-1.x-dev » 6.x-1.0-alpha5
Status: Active » Needs review
FileSize
6.01 KB

Attached is just #13 in patch format, which should be applied against alpha5.

mparkes’s picture

Any word on this being applied to the dev branch. The dev branch fixes the add another button not working which is a problem in the alpha.

mparkes’s picture

So this doesn't seem to work at all. I'm still seeing entries with empty fields even tho I checked the remove box. What's worse is I changed the number of values to 5. Then I decided to put it back to unlimited. Now I have 5 rows withing the flexifield. I'm using custom price module to calculate the price based on how many entries are entered into the Flexifield. Any idea how to fix this or when it will be fixed?

Todd Zebert’s picture

subscribe

stefan81’s picture

hi, would be cool to roll out a new dev release with both issues (add button / remove button) fixed as mentioned at #18

Todd Zebert’s picture

I'm not a programmer, but I'm trying to create a simple multi-field like node, with required subfields. I successfully used the patch in http://drupal.org/node/390480 to work-around the invalid "Item Description field is required." errors, but then found I couldn't delete records since all the subfields in one "record" couldn't be empty.

I reapply the patch in the #390480 thread to the 6.x-1.x-dev (2010-Jul-11), and then used the patch file from #17 to create the JS file, and manually adjusted the patch file and applied it against the dev version. Looking at the code (as well as I could) it seemed to layout logically with the DEV version.

Running with the dev version with both patches yielded the "add new item"/"remove item" js buttons, BUT removing a "record" and then Saving produced the same result #390480 was supposed to fix: I now get the "... field is required." error again.

mparkes’s picture

Any updates?

tomhung’s picture

++ for adding this patch to DEV.

Greg

geek-merlin’s picture

sub

cmcintosh’s picture

FileSize
846 bytes

I needed to get this working so went through and cleared up some of the cluttered code from the above posts. I have noticed that for some reason when you click add more, the delete checkbox is removed from that perticular flexifield's items. This module works on nodes that have multiple flexifields.

ice5nake’s picture

@cmcintosh, would love to see someone committing to this module again.

cmcintosh’s picture

k so disclaimer. It seems that for some reason when you delete an item it removes the Add More button. Trying to figure out why this happens now. Probably something with ahah_response / how it does its magic.

cmcintosh’s picture

FileSize
2.52 KB

Ok so i was having a bit of issue when I added more items it would remove the items. I figured out a way around this. Around line 626 I added the following:

 $aElement['delete'] = array(
    '#type' => 'checkbox', 
    '#title' => 'Remove Item', 
    '#weight' => 50,
    
  );

How ever at this time I am not doing ahah deletion. I still have not worked this part out as of yet and taking a break.

manasiv’s picture

#13 works fine. It does not use AHAH for remove block. +1 to have this in the module's dev release.

cravecode’s picture

cmcintosh, what version was this written for? I'm using flexifield DEV and nothing happened when i enabled flexifield_delete and recreated by fields.
Thanks!!

ice5nake’s picture

It would be great to get this committed to the actual 6.x-1.x-dev. This module is great but needs continued develpment in my opinion.

cmcintosh’s picture

my code was made for 6.x-1.0-alpha5, sorry for the response delay.