2

I try to add dynamically some field on a form when I click on a button "Add a sponsee". I search on internet how to do that with the form API but unfortunatly whitout succes. Here is my form class :

/**
 * {@inheritdoc}
 */
public function buildForm(array $form, FormStateInterface $form_state) {

    $form['#tree'] = true; //Make the form fields a hierachical array*

    $form['#prefix'] = '<div id="sponsorship-form-wrapper">';
    $form['#suffix'] = '</div>';

    $form['sponsor'] = [
        '#type' => 'fieldset',
        '#title' => $this->t('You (sponsor)'),
    ];
    $form['sponsor']['civility'] = [
        '#type' => 'select',
        '#title' => $this->t('Civility'),
        '#options' => array('Miss' => $this->t('Miss'), 'Mister' => $this->t('Mister')),
        '#size' => 1,
    /* .......... */
    $form['sponsor']['submit'] = [
        '#type' => 'submit',
        '#value' => t('Send'),
    ];


    $form['sponsee'] = [
        '#type' => 'fieldset',
        '#title' => $this->t('Your sponsee'),
        '#prefix' => '<div id="sponsees-fieldset-wrapper">',
        '#suffix' => '</div>',
    ];

    //Default value of nb_sponsees to 1
    if ($form_state->getValue('nb_sponsee') == null) {
        $form_state->setValue('nb_sponsee', 1);
    }

    for ($i = 0; $i < $form_state->getValue('nb_sponsee'); $i++) {
        $form['sponsee'][$i]['civility'] = [
            '#type' => 'select',
            '#title' => $this->t('Civility'),
            '#options' => array('Miss' => $this->t('Miss'), 'Mister' => $this->t('Mister')),
            '#size' => 1,
        ];
        $form['sponsee'][$i]['firstname'] = [
            '#type' => 'textfield',
            '#title' => $this->t('Firstname'),
            '#maxlength' => 64,
            '#size' => 64,
        ];
        $form['sponsee'][$i]['name'] = [
            '#type' => 'textfield',
            '#title' => $this->t('Name'),
            '#maxlength' => 64,
            '#size' => 64,
        ];
        $form['sponsee'][$i]['phone'] = [
            '#type' => 'textfield',
            '#title' => $this->t('Phone'),
            '#maxlength' => 64,
            '#size' => 64,
        ];
        $form['sponsee'][$i]['e_mail'] = [
            '#type' => 'email',
            '#title' => $this->t('E-mail'),
        ];
    }

    //If less of 3 sponsee we add the button
    if ($form_state->getValue('nb_sponsee') < 3) {
        $form['sponsee']['add_sponsee'] = [
            '#type' => 'submit',
            '#name' => 'add_sponsee',
            '#submit' => [$this, 'ajaxHandleSponseesSubmit'],
            '#value' => t('Add a sponsee'),
            '#ajax' => array(
                'callback' => [$this, 'ajaxHandleSponseesCallback'],
                'wrapper' => 'sponsees-fieldset-wrapper',
                'event' => 'click',
                'effect' => 'fade',
                'progress' => array('message' => '', 'type' => 'throbber'),
            ),
        ];
    }

    return $form;
}

/**
 * {@inheritdoc}
 */
public function validateForm(array &$form, FormStateInterface $form_state) {
    parent::validateForm($form, $form_state);
}

/**
 * {@inheritdoc}
 */
public function submitForm(array &$form, FormStateInterface $form_state) {
    // Display result.
    foreach ($form_state->getValues() as $key => $value) {
        drupal_set_message($key . ': ' . $value);
    }
}

/*
 * Custom Submit to increment nb_sponsees
 */
function ajaxHandleSponseesSubmit(array &$form, FormStateInterface &$form_state) {
    $form_state->setValue('nb_sponsee', $form_state->getValue('nb_sponsee') + 1);
    $form_state->setRebuild(true);
}

/**
 * Ajax submit handler that will return the form structure
 */
public function ajaxHandleSponseesCallback(array &$form, FormStateInterface &$form_state) {
    return $form['sponsee'];
}

As you can see, when I clic on $form['sponsee']['add_sponsee'], I increment the nb_sponsees in the $form_state and rebuild the form. Then, in my AJAX callback, I return the fieldset part of the form. I've turn this in many way without success. This way seams to work with lot of situation, but not in mine. Am I missing something ?


Here's my form working with the help of examples modules :

/**
 * {@inheritdoc}
 */
public function buildForm(array $form, FormStateInterface $form_state) {

    $form['#theme'] = 'sponsorship_form';
    $form['#tree'] = true; //Make the form fields a hierachical array*

    $form['#prefix'] = '<div id="sponsorship-form-wrapper">';
    $form['#suffix'] = '</div>';

    $form['sponsor'] = [
        '#type' => 'fieldset',
        '#title' => $this->t('You (sponsor)'),
        '#prefix' => '<div class="quick-contact__form col-xs-12 col-md-6">',
        '#suffix' => '</div>',
    ];

    / ** Some fields... */

    $form['sponsor']['submit'] = [
        '#type' => 'submit',
        '#value' => t('Send'),
        '#attributes' => [
            'class' => ['btn btn-full']
        ],
        '#ajax' => array(
            'wrapper' => 'sponsorship-form-wrapper',
            'callback' => '::ajaxRebuildForm',
            'effect' => 'fade',
            'progress' => array('message' => '', 'type' => 'throbber'),
        ),
    ];


    $nb_sponsee = $form_state->get('nb_sponsee');
    $form['sponsees'] = [
        '#type' => 'container',
        '#prefix' => '<div id="sponsees-fieldset-wrapper" class="quick-contact__form col-xs-12 col-md-6">',
        '#suffix' => '</div>',
    ];

    if (empty($nb_sponsee)) {
        $nb_sponsee = 1;
        $form_state->set('nb_sponsee', $nb_sponsee);
    }

    for ($i = 0; $i < $nb_sponsee; $i++) {

        $form['sponsees'][$i]['sponsee'] = [
            '#type' => 'fieldset',
            '#title' => $this->t('Your sponsee'),
        ];

        $form['sponsees'][$i]['sponsee']['civility'] = [
            '#prefix' => '<div class="formdetails-containHead">',
            '#type' => 'select',
            '#title' => $this->t('Civility'),
            '#options' => array(1 => $this->t('Mr'), 2 => $this->t('Miss')),
            '#size' => 1,
            '#title_display' => 'invisible',
            '#attributes' => [
                'class' => ['formDetails--civility']
            ]
        ];
        $form['sponsees'][$i]['sponsee']['firstname'] = [
            '#suffix' => '</div>',
            '#type' => 'textfield',
            '#title' => $this->t('Firstname'),
            '#placeholder' => $this->t('Firstname'),
            '#maxlength' => 64,
            '#size' => 64,
            '#title_display' => 'invisible',
        ];
        $form['sponsees'][$i]['sponsee']['name'] = [
            '#type' => 'textfield',
            '#title' => $this->t('Name'),
            '#placeholder' => $this->t('Name'),
            '#maxlength' => 64,
            '#size' => 64,
            '#title_display' => 'invisible',
        ];
        $form['sponsees'][$i]['sponsee']['phone'] = [
            '#type' => 'textfield',
            '#title' => $this->t('Phone'),
            '#placeholder' => $this->t('Phone'),
            '#maxlength' => 64,
            '#size' => 64,
            '#title_display' => 'invisible',
        ];
        $form['sponsees'][$i]['sponsee']['e_mail'] = [
            '#type' => 'email',
            '#title' => $this->t('E-mail'),
            '#placeholder' => $this->t('E-mail'),
            '#title_display' => 'invisible',
        ];
    }

    //If less of 3 sponsee we add the button
    if ($nb_sponsee < 3) {
        $form['sponsees']['add_sponsee'] = [
            '#type' => 'submit',
            '#prefix' => '<span class="containPlus">+</span>',
            '#attributes' => [
                'class' => ['btn-add-sponsee']
            ],
            '#value' => t('Add a sponsee'),
            '#submit' => array('::addSponcee'),
            '#ajax' => [
                'callback' => '::addSponceeCallback',
                'wrapper' => 'sponsees-fieldset-wrapper',
            ],
        ];
    }

    return $form;
}

/**
 * {@inheritdoc}
 */
public function validateForm(array &$form, FormStateInterface $form_state) {
    parent::validateForm($form, $form_state);
}

/**
 * {@inheritdoc}
 */
public function submitForm(array &$form, FormStateInterface $form_state) {
    $form_state->set('nb_sponsee', 1);
    // Display result.
    foreach ($form_state->getValues() as $key => $value) {
        drupal_set_message($key . ': ' . $value);
    }
}

/**
 * Ajax submit handler that will return the whole form structure.
 *  = callback of the complete submit of the form
 *
 * @param array $form
 *   An associative array containing the structure of the form.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The current state of the form.
 *
 * @return array
 *   The form structure.
 */
public function ajaxRebuildForm(array &$form, FormStateInterface $form_state) {
    return $form;
}

/**
 * Callback for both ajax-enabled buttons.
 *
 * Selects and returns the fieldset with the names in it.
 */
public function addSponceeCallback(array &$form, FormStateInterface $form_state) {
    return $form['sponsees'];
}

/**
 * Submit handler for the "add-one-more" button.
 *
 * Increments the max counter and causes a rebuild.
 */
public function addSponcee(array &$form, FormStateInterface $form_state) {
    $form_state->set('nb_sponsee', $form_state->get('nb_sponsee') + 1);
    $form_state->setRebuild();
}
2
  • 2
    hi please refer drupal.org/project/examples module . you can find the example of add more .. i find its seimilar to what you are finding Commented Sep 27, 2016 at 12:58
  • I took the example from fapi_example/src/Form/AjaxAddMore.php. It works now ! Thank you. Maybe you can post an answer mentioning this, I will accept it as answer ;-)
    – Gaius
    Commented Sep 27, 2016 at 13:21

2 Answers 2

6

You can make use of examples module where you can find many ajax examples. One of the ajax example is of add and remove button which can help you . I feel the add and remove button example i find is relevant to the problem you are asking solution for .

1
  • 5
    You can find the demo form controller at examples/fapi_example/src/Form/AjaxAddMore.php.
    – milkovsky
    Commented Sep 14, 2017 at 10:09
1

Try to change like :

'#ajax' => array(
    'callback' => '::ajaxHandleSponseesCallback',
)



function ajaxHandleSponseesCallback($form, FormStateInterface $form_state) {
$value = $form_state->getValue('nb_sponsee') + 1;
$form['sponsee']['#value'] = $value;
$form['sponsee']['#default_value'] = $value;
return $form['sponsee'];
}

You have more examples:

http://www.drupal8.ovh/en/tutoriels/26/ajax-form

http://www.drupal8.ovh/en/tutoriels/139/add-remove-fields-dynamically-using-form-api-and-ajax

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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