Create config object with array containing key-value pairs We have a custom module, mymodule, that we want to use to create a config object for so that it can contain an array of key-value pairs. We need to be able to click button Add More on the form that will add more key and value fields that will be mapped together. 

How can we create a form that would not only display existing key-value pairs, but also provide option to add more?

Goals:


On the admin Form, MyModuleForm be able to see existing key-value pairs.
Add more key-value pairs.
Key and value are text fields.
Use the config_object within the mymodule.module file and fetch all the key-value pairs.


Below is what we tried, but got stuck on how to add the Add more functionality and how to properly store customKey and customValue into an array.

MyModuleForm.php

class MyModuleForm extends ConfigFormbase {
  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return [
      'mymodule.settings'
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'mymodule_settings';
  }

  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = $this-&gt;config('mymodule.settings');
    $form['customKey'] = [
      '#title' =&gt; $this-&gt;t('Key value for array.'),
      '#type' =&gt; 'textfield',
      '#default_value' =&gt; $config-&gt;get('customKey'),
      '#maxlength' =&gt; 255,
      '#required' =&gt; TRUE,
    ];
    $form['customValue'] = [
      '#title' =&gt; $this-&gt;t('value for array.'),
      '#type' =&gt; 'textfield',
      '#default_value' =&gt; $config-&gt;get('customValue'),
      '#maxlength' =&gt; 255,
      '#required' =&gt; TRUE,
    ];

    return parent::buildForm($form, $form_state);
  }

  public function submitForm(array &amp;$form, FormStateInterface $form_state) {
    // Retrieve the configuration
    $this-&gt;configFactory-&gt;getEditable('mymodule.settings')
      -&gt;set('customKey', $form_state-&gt;getValue('customKey'))
      -&gt;set('customValue', $form_state-&gt;getValue('customValue'))
      -&gt;save();

    parent::submitForm($form, $form_state);
  }
}
To add an add more button you'll need to create a callback function that will increase the number of fields necessary and rebuild that part of the form based on that information. You can make a new config variable based on some sort of index as you do a loop through all the necessary fields.

I haven't tested this so the syntax might be off but here's the basic idea in an example I wrote. 

public function buildForm(array $form, FormStateInterface $form_state) {
        if (empty($number_of_member_fields)) {
            $number_of_member_fields = $form_state-&gt;set('number_of_member_fields', 1);
        }
        $forms['members_fieldset'] = [
            '#type' =&gt; 'fieldset',
            '#title' =&gt; t('Member types'),
            '#attributes' =&gt; [
                'id' =&gt; 'names-fieldset-wrapper'
            ],
        ];
        for ($i = 0; $i &lt; $number_of_member_fields; $i++) {
            $form['members_fieldset']['memberType'.$i] = [
                '#type'          =&gt; 'textfield',
                '#title'         =&gt; t('Name'),
                '#default_value' =&gt; $config-&gt;get('memberType'.$i),
            ];
        }
        $form['members_fieldset']['actions']['add_name'] = [
            '#type'     =&gt; 'submit',
            '#value'    =&gt; t('Add one more'),
            '#submit'   =&gt; array('::addOne'),
            '#ajax'     =&gt; [
                'callback' =&gt; '::addmoreCallback',
                'wrapper'  =&gt; 'names-fieldset-wrapper',
            ],
        ];
    }
    public function addmoreCallback(array&amp;$form, FormStateInterface $form_state) {
        return $form['members_fieldset'];
    }
    public function addOne(array&amp;$form, FormStateInterface $form_state) {
        $number_of_member_fields = $form_state-&gt;get('number_of_member_fields');
        $number_of_member_fields++;
        $form_state-&gt;set('number_of_member_fields', $number_of_member_fields);
        $form_state-&gt;setRebuild();
    }