By alexandr.k on
I created a form with ajax buttons to add / remove a person.
namespace Drupal\general\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
class CreditPersonsForm extends ConfigFormBase
{
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames()
{
return array('general.credit_person_form');
}
/**
* {@inheritdoc}
*/
public function getFormId()
{
return 'credit_persons_form';
}
/**
* {@inheritdoc}
*/
public function buildForm($form, FormStateInterface $form_state)
{
$configs = $this->config('general.credit_persons_form');
$num_person = $form_state->get('num_person');
if ($num_person === null)
{
$persons = $form_state->set('num_person', 1);
$num_person = 1;
}
$form['#tree'] = true;
$form['site_credits'] = array(
'#type' => 'fieldset',
'#title' => $this->t('Site managers'),
'#prefix' => '<div id="siteCreditsWrapper">',
'#suffix' => '</div>',
);
for($i = 0; $i < $num_person; $i++) {
$num = $i + 1;
$form['site_credits']["persons{$num}"] = array(
'#type' => 'fieldset',
'#title' => $this->t("Person #{$num}"),
'#prefix' => "<div id=\"person-{$num}\">",
'#suffix' => '</div>',
);
$form['site_credits']["persons{$num}"]['manager_picture'] = array(
'#type' => 'managed_file',
'#title' => $this->t('Manager picture'),
'#description'=> $this->t("Upload file. <br />2MB limit. <br/>Allowed types: png gif jpg jpeg."),
);
$form['site_credits']["persons{$num}"]['first_name'] = array(
'#type' => 'textfield',
'#title' => $this->t('First name'),
);
$form['site_credits']["persons{$num}"]['last_name'] = array(
'#type' => 'textfield',
'#title' => $this->t('Last name'),
);
$form['site_credits']["persons{$num}"]['position'] = array(
'#type' => 'textfield',
'#title' => $this->t('Position'),
);
$form['site_credits']["persons{$num}"]['profile_url'] = array(
'#type' => 'textfield',
'#title' => $this->t('Link to Linkedin profile'),
);
$form['site_credits']["persons{$num}"]['actions'] = array(
'#type' => 'actions',
);
if ($num_person > 1)
{
$form['site_credits']["persons{$num}"]['actions']['remove_person'] = array(
'#type' => 'submit',
'#value' => $this->t("Remove person"),
'#submit' => ['::removeCallback'],
'#ajax' => array(
'callback' => '::addmoreCallback',
'wrapper' => 'siteCreditsWrapper',
),
);
}
}
$form['site_credits']['actions'] = array(
'#type' => 'actions',
);
$form['site_credits']['actions']['add_person'] = array(
'#type' => 'submit',
'#value' => $this->t('Add one more'),
'#submit' => ['::addOne'],
'#ajax' => array(
'callback' => '::addmoreCallback',
'wrapper' => 'siteCreditsWrapper',
),
'#button_type' => 'default'
);
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Save'),
'#button_type' => 'primary',
);
return $form;
}
/**
*
*/
public function addmoreCallback(array &$form, FormStateInterface $form_state) {
return $form['site_credits'];
}
/**
* {@inheritdoc}
*/
public function addOne(array &$form, FormStateInterface $form_state)
{
$persons = $form_state->get('num_person');
$add_person = $persons + 1;
$form_state->set('num_person', $add_person);
$form_state->setRebuild();
}
/**
* {@inheritdoc}
*/
public function removeCallback(array &$form, FormStateInterface $form_state)
{
$persons = $form_state->get('num_person');
if ( $persons > 1 )
{
$remove_person = $persons - 1;
$form_state->set('num_person', $remove_person);
}
$form_state->setRebuild();
}But the "remove" button only reduces the value and starts the rebuild process of the form, respectively, the last element of the form is permanently deleted.
Tell me, please, how to implement the "remove" button that will delete the necessary block of fields, and not reduce the number of blocks for their rebuilding? That is, if it is necessary to remove the second block of the three, it is not the third block that will be removed, but the second one.
Comments
You need to know "persons{
You need to know "persons{$name}" key of a item you want to delete.
You can do this with calling:
$form_state->getTriggeringElement()
After that, you be able to remove this item from the array:
unset($form['site_credits']['KEY_TO_REMOVE']).
Take a look this example:
https://gist.github.com/alexdesignworks/94bac012e7d679051bc0#gistcomment...
I want to remove selected field in custom form
Please help
This is a possible solution
I have found a solution. I don't know if it's the best but it will do it for me. I modified the example code from the example module. I use form state vars for each new row (1 for active row, 0 for removed row).
I use $form_state->getTriggeringElement()['#name'] to know which remove buttons is clicked. The name of the button is equal to the row count. So after the button is clicked the corresponding var is set to 0 and when the form is rebuilt it will not display the removed text field.
See the attached code.
Hope that this helps someone.
Thanks
Hi Ivel,
This solution helped me a lot. I applied similar conditions as you used. Thanks for the idea......