Pete
Pete

Reputation: 7579

Get data for form input array using specific key

So, let's say I have an HTML form like this:

<form id="myForm">
    <input type="text" name="dummy">
    <input type="text" name="people[0][first_name]" value="John">
    <input type="text" name="people[0][last_name]" value="Doe">
    <input type="text" name="people[1][first_name]" value="Jane">
    <input type="text" name="people[1][last_name]" value="Smith">
</form>

And I want to get a JavaScript array that matches the values of real. For example:

// If there was a sweet function for this...
var people = getFormDataByInputName( 'people' );

// Value of `people` is...
// [
//    {
//        'first_name' : 'John',
//        'last_name'  : 'Doe'
//    },
//    {
//        'first_name' : 'Jane',
//        'last_name'  : 'Smith'
//    }
// ]

Is there any easy way of doing that for just a specific form item (in this case, people)? Or would I have to serialize the entire form an then just extract the element I want?

I also thought of potentially using the following approach:

var formData = new FormData( document.querySelector( '#myForm' ) );
var people = formData.get( 'people' );

But that doesn't appear to work; people is just null after that.

Upvotes: 2

Views: 3471

Answers (4)

AamirR
AamirR

Reputation: 12208

Use CSS attribute prefix selector, such as

form.querySelectorAll('[name^="people[]"]')

Example

const form = document.querySelector('#myForm');
const MAX_PEOPLES = 2;
const list = [];
for (i = 0; i <= MAX_PEOPLES; i++) {
  const eles = form.querySelectorAll(`[name^="people[${i}]`);
  if (eles.length < 2)
    continue;

  list.push({
    first_name: eles[0].value,
    last_name: eles[1].value
  });
}

console.log(list)
<form id="myForm">
  <input type="text" name="dummy">
  <input type="text" name="people[0][first_name]" value="John">
  <input type="text" name="people[0][last_name]" value="Doe">
  <input type="text" name="people[1][first_name]" value="Jane">
  <input type="text" name="people[1][last_name]" value="Smith">
</form>

Upvotes: 0

CodeBoy
CodeBoy

Reputation: 3300

Your code won't work because to HTML/JS name is just a string that it sends to the server when the form is submitted (the name in the name/value pairs). You might think it is arrays, but HTML/JS doesn't.

So no one-liner to get the job done. Try this: In your HTML, add <div class="name"> ...

(UPDATE: thanks for the idea, @Nenad, I've never tried one of these snippets)

var people = [];
$('.name').each(function() {
    people.push({
        first_name: $('input:nth-child(1)', this).val(),
        last_name: $('input:nth-child(2)', this).val()
    });
});
console.log(people);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<form id="myForm">
  <input type="text" name="dummy">
  <div class="name">
    <input type="text" value="John">
    <input type="text" value="Doe">
  </div>
  <div class="name">
    <input type="text" value="Jane">
    <input type="text" value="Smith">
  </div>
</form>

Upvotes: 0

fyasir
fyasir

Reputation: 2970

function getObject(name, key) {
  if(key.includes(name)) {
    var splitStr = key.split(/\[|\]/g);
    return {
      index: splitStr[1],
      key: splitStr[3],
    }
  }
  return null;
}

function getFormDataByInputName(name) {
 var formData = new FormData( document.querySelector('#myForm'));
 var results = [];
 for (var key of formData.keys()) {
   var obj = getObject(name, key);
   if (obj) {
      if (results[obj.index]) results[obj.index][obj.key] = formData.get(key);
      else results[obj.index] = { [obj.key]: formData.get(key) };
   }
 }
 return results;
}


var people = getFormDataByInputName('people');

console.log(people);
<form id="myForm">
    <input type="text" name="dummy">
    <input type="text" name="people[0][first_name]" value="John">
    <input type="text" name="people[0][last_name]" value="Doe">
    <input type="text" name="people[1][first_name]" value="Jane">
    <input type="text" name="people[1][last_name]" value="Smith">
</form>

Upvotes: 0

Nenad Vracar
Nenad Vracar

Reputation: 122077

You could do this with plain js using reduce method and return each person is one object.

const form = document.querySelectorAll('#myForm input');
const data = [...form].reduce(function(r, e) {
  const [i, prop] = e.name.split(/\[(.*?)\]/g).slice(1).filter(Boolean)
  if (!r[i]) r[i] = {}
  r[i][prop] = e.value
  return r;
}, [])

console.log(data)
<form id="myForm">
  <input type="text" name="dummy">
  <input type="text" name="people[0][first_name]" value="John">
  <input type="text" name="people[0][last_name]" value="Doe">
  <input type="text" name="people[1][first_name]" value="Jane">
  <input type="text" name="people[1][last_name]" value="Smith">
</form>

Upvotes: 2

Related Questions