Drupal - How do I add a "Add more" button?

It works !! Try this

<?php
  
namespace Drupal\fapi_example\Form;
   
use Drupal\Core\Form\FormStateInterface;
  
class AjaxAddMore extends FormBase {
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['description'] = array(
      '#markup' => '<div>'. $this->t('This example shows an add-more and a remove-last button.').'</div>',
    );

    $i = 0;
    $name_field = $form_state->get('num_names');
    $form['#tree'] = TRUE;
    $form['names_fieldset'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('People coming to picnic'),
      '#prefix' => '<div id="names-fieldset-wrapper">',
      '#suffix' => '</div>',
    ];
    if (empty($name_field)) {
      $name_field = $form_state->set('num_names', 1);
    }
    for ($i = 0; $i < $name_field; $i++) {
      $form['names_fieldset']['name'][$i] = [
      '#type' => 'textfield',
      '#title' => $this->t('Name'),
      ];
    }
    $form['actions'] = [
      '#type' => 'actions',
    ];
    $form['names_fieldset']['actions']['add_name'] = [
      '#type' => 'submit',
      '#value' => $this->t('Add one more'),
      '#submit' => array('::addOne'),
      '#ajax' => [
      'callback' => '::addmoreCallback',
      'wrapper' => 'names-fieldset-wrapper',
      ],
    ];
    if ($name_field > 1) {
      $form['names_fieldset']['actions']['remove_name'] = [
      '#type' => 'submit',
      '#value' => $this->t('Remove one'),
      '#submit' => array('::removeCallback'),
       '#ajax' => [
        'callback' => '::addmoreCallback',
        'wrapper' => 'names-fieldset-wrapper',
      ]
      ];
    }
    $form_state->setCached(FALSE);
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    ];
  
    return $form;
  }
  
  public function getFormId() {
    return 'fapi_example_ajax_addmore';
  }

  public function addOne(array &$form, FormStateInterface $form_state) {
    $name_field = $form_state->get('num_names');
    $add_button = $name_field + 1;
    $form_state->set('num_names', $add_button);
    $form_state->setRebuild();
  }

  public function addmoreCallback(array &$form, FormStateInterface $form_state) {
    $name_field = $form_state->get('num_names');
    return $form['names_fieldset'];
  }

  public function removeCallback(array &$form, FormStateInterface $form_state) {
    $name_field = $form_state->get('num_names');
    if ($name_field > 1) {
      $remove_button = $name_field - 1;
      $form_state->set('num_names', $remove_button);
    }
    $form_state->setRebuild();
  }
  
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValue(array('names_fieldset', 'name'));
  
    $output = t('These people are coming to the picnic: @names', array(
      '@names' => implode(', ', $values),
      )
    );
    drupal_set_message($output);
  }
}

If reporting error is turned on then the code Shreya Shetty returns error - might be related to changes in Drupal 8 ... but it is related to objects not being able to be used as ints... the amended version would be:

namespace Drupal\dynamic_forms\Form;


 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;

  class test3 extends FormBase {

public function buildForm(array $form, FormStateInterface $form_state) {
    $form['description'] = array(
        '#markup' => '<div>'. t('This example shows an add-more and a remove-last button.').'</div>',
    );
    $i = 0;
    $name_field = $form_state->get('num_names');
    $form['#tree'] = TRUE;
    $form['names_fieldset'] = [
        '#type' => 'fieldset',
        '#title' => $this->t('People coming to picnic'),
        '#prefix' => '<div id="names-fieldset-wrapper">',
        '#suffix' => '</div>',
    ];
    if (empty($name_field)) {
        $name_field = $form_state->set('num_names', 1);
    }

    if ($form_state->get('num_names')>0) {
        $value = $form_state->get('num_names');
    }
    else {
        $value=1;
    }
        for ($i = 0; $i < $value; $i++) {
            $form['names_fieldset']['name'][$i] = [
                '#type' => 'textfield',
                '#title' => t('Name'),
            ];
        }

    $form['actions'] = [
        '#type' => 'actions',
    ];
    $form['names_fieldset']['actions']['add_name'] = [
        '#type' => 'submit',
        '#value' => t('Add one more'),
        '#submit' => array('::addOne'),
        '#ajax' => [
            'callback' => '::addmoreCallback',
            'wrapper' => 'names-fieldset-wrapper',
        ],
    ];
    //        if ($name_field > 1) {
    if ($value > 1) {
        $form['names_fieldset']['actions']['remove_name'] = [
            '#type' => 'submit',
            '#value' => t('Remove one'),
            '#submit' => array('::removeCallback'),
            '#ajax' => [
                'callback' => '::addmoreCallback',
                'wrapper' => 'names-fieldset-wrapper',
            ]
        ];
    }
    $form_state->setCached(FALSE);
    $form['actions']['submit'] = [
        '#type' => 'submit',
        '#value' => $this->t('Submit'),
    ];

    return $form;
}

public function getFormId() {
    return 'fapi_example_ajax_addmore';
}

public function addOne(array &$form, FormStateInterface $form_state) {
    $name_field = $form_state->get('num_names');
    $add_button = $name_field + 1;
    $form_state->set('num_names', $add_button);
    $form_state->setRebuild();
}

public function addmoreCallback(array &$form, FormStateInterface $form_state) {
    $name_field = $form_state->get('num_names');
    return $form['names_fieldset'];
}

public function removeCallback(array &$form, FormStateInterface $form_state) {
    $name_field = $form_state->get('num_names');
    if ($name_field > 1) {
        $remove_button = $name_field - 1;
        $form_state->set('num_names', $remove_button);
    }
    $form_state->setRebuild();
}

public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValue(array('names_fieldset', 'name'));

    $output = t('These people are coming to the picnic: @names', array(
            '@names' => implode(', ', $values),
        )
    );
    drupal_set_message($output);
}

}

Thought the amended version might help someone, especially newcomers... don't forget to say thanks to Shreya for original solution.

Tags:

Forms

Ajax

8