Как преобразовать массив полей формы в массив объектов с помощью JavaScript?

Как можно изменить процесс обработки данных из формы с использованием <b>FormData</b>, чтобы объект <b>data</b> включал все значения с нумерованными ключами? В текущей реализации при добавлении значений в объект <b>data</b> при одинаковых ключах сохраняется только последнее значение. Как добиться аналогии с PHP, где можно получить значения по индексированным ключам, например, <code class="php">$_GET[list][label][0]</code> и <code class="php">$_GET[list][label][1]</code>?
  • 17 января 2025 г. 8:33
Ответы на вопрос 2
Чтобы преобразовать массив полей формы в массив объектов с использованием JavaScript и `FormData`, можно воспользоваться методом `Array.from()` или `spread operator` для получения массива пар ключ-значение из объекта `FormData`. Затем вам нужно будет обработать эти пары и собрать данные в нужном вам формате.

Вот как это можно сделать:

```javascript
function formDataToObject(formData) {
    const data = {};

    // Используем FormData для получения массива пар [ключ, значение]
    for (const [key, value] of formData.entries()) {
        // Проверяем, если ключ уже существует в объекте data
        if (data[key]) {
            // Если существует, проверяем, является ли это массивом
            if (Array.isArray(data[key])) {
                // Если это массив, добавляем новое значение
                data[key].push(value);
            } else {
                // Если нет, создаем массив и добавляем существующее значение и новое
                data[key] = [data[key], value];
            }
        } else {
            // Если ключ не существует, просто присваиваем значение
            data[key] = value;
        }
    }

    return data;
}

// Пример использования
const form = document.querySelector('form');
form.addEventListener('submit', function(event) {
    event.preventDefault(); // Остановить стандартное поведение формы

    const formData = new FormData(form);
    const data = formDataToObject(formData);
    
    console.log(data);
});
```

### Объяснение решения:

1. **Использование `FormData`**: Создается объект `FormData` из формы, который автоматически собирает все поля формы и их значения.

2. **Цикл `for...of`**: Итерируемся по записям (парам ключ-значение) в объекте `FormData`.

3. **Проверка наличия ключа**: Если ключ уже присутствует в `data`, мы проверяем его тип:
   - Если это массив — добавляем новое значение.
   - Если это не массив — создаем массив, в который помещаем существующее значение и новое.
   
4. **Присвоение значения**: Если ключ отсутствует, просто присваиваем значение.

### Пример формы:

Добавим форму, которую можно использовать для тестирования:

```html
<form>
    <input type="text" name="list[label]">
    <input type="text" name="list[label]">
    <button type="submit">Submit</button>
</form>
```

### Пример вывода:

Если пользователь введет в оба поля формы "Test1" и "Test2", `data` будет выглядеть следующим образом:

```javascript
{
    "list[label]": ["Test1", "Test2"]
}
```

Таким образом, вы сможете получить значения с индексированными ключами, аналогичными тому, как это делается в PHP.
<pre><code class="javascript">const getFormData = form =&gt;
  Array.prototype.reduce.call(
    form.elements,
    (acc, { name, type, value, checked }) =&gt; {
      const isCheckbox = type === 'checkbox';
      const isRadio = type === 'radio';
      const keys = Array.from(name.matchAll(/\w+|\[(\w*)\]/g), n =&gt; n[1] ?? n[0]);
      const key = keys.pop();
      const isArr = !key;
      const values = keys.reduce((p, c, i, a) =&gt; {
        return p[c] ??= (-~i === a.length &amp;&amp; isArr ? [] : {});
      }, acc);

      if (!isCheckbox || !isArr || checked) {
        values[isArr ? values.length : key] ??=
          (isCheckbox &amp;&amp; !isArr  ) ? checked :
          (isRadio    &amp;&amp; !checked) ?    null :
                                       value;
      }

      return acc;
    },
    {}
  );</code></pre> <br/> <a href="https://jsfiddle.net/a9bctor5/2/" rel="nofollow">https://jsfiddle.net/a9bctor5/2/</a>
Похожие вопросы