0

I am using a backend where it is ideal that I send an ajax post request rather than using the default action on forms.

With this in mind, I need to extract the final fields that are selected in my form.

I have various text fields, radio buttons, checkboxes, etc.

I've always struggled gaining a good understanding of event delegation and event propagation. I'm not entirely sure if this is the topic I should be worried about with what I am trying to achieve.

I know I can write code that grabs all of the information in my form by placing an ID on each field and a have a function extract each value on the ID such as:

function example(){
  var field0 = $('#field0').val();
  var field1 = $('#field1').parent().hasClass('active')
  // ... and more    

}

I've used this pattern for a while and I don't feel like it is efficient.

I have two pattern idea, but I am still not sure if this is a "common practice"

  1. Since I am not concerned about the data in each field until the form is submitted, I could run a loop on all of my input based fields on my form and extract the contents, instead of assigning an ID to each individual input field.

  2. I can listen to changes on the form (I am not exactly sure how to do this, this is where event delegation/propagation will come into play). Instead of waiting for the submit button to gather all the info in the form, I will have some type of listener that detects a change on the form (not sure if that is possible).

I've been using my current pattern for several months and would like to improve myself, If anyone has any suggestions, links, or criticism about my thoughts on a new approach I'd appreciate it.

HelloWorld
  • 10,529
  • 10
  • 31
  • 50

3 Answers3

1

Pattern #1 (use serializeArray)

$('#formId').on('submit', function(e){
  var allData;
  e.preventDefault();

  allData = $(this).serializeArray();

  // use the allData variable when sending the ajax request
});

Pattern #2 (use the delegated form of $container.on('event', 'selector', ..) and the change event)

$('#formId').on('change', 'input,textarea,select', function(){
 var element = $(this), // element that changed
     value = element.val(); // its new value
 // do what you want ..
});
Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
1

So, you basically propose 3 ways to get all form fields with a value on submit (or a similar event):

  1. hard-code IDs and retrieve their values, e.g.
var field_a = document.getElementById('a')
  , field_b = document.getElementById('b')
  , form = document.getElementById('my_form');

form.addEventListener('submit', function() {
  fetch('//your/api/endpoint', {
    method: 'POST',
    body: JSON.stringify({a: field_a.value, b: field_b.value})
  });
});
  1. loop all and retrieve their values, e.g.
var form = document.getElementById('my_form');

form.addEventListener('submit', function() {
  var values = [].reduce.call(
    form.querySelectorAll('input, textarea, select'),
    function(values, element) {
      values[element.name] = element.value;
      return values;
    },
    {}
  );

  fetch('//your/api/endpoint', {
    method: 'POST',
    body: JSON.stringify(values)
  });
});
  1. watch for changes inside the form, accumulate them
var form = document.getElementById('my_form')
  , state = {};

form.addEventListener('change', function(e) {
  state[e.srcElement.name] = e.value;
});
form.addEventListener('submit', function() {
  fetch('//your/api/endpoint', {
    method: 'POST',
    body: JSON.stringify(state)
  });
});

From a performance perspective, option 1. will be the fastest, followed by 2 followed by 3 (with the last 2 I'm not 100% certain, querySelectorAll can be expensive, but listening for tons of change events might be as well -- depends on how often change events are triggered I'd say).

From development perspective (how long does it take to set up a form), 2 and 3 should not be that different as they are both generic (and you can use my code sample as a start).

"Real" data-binding (like Angular) or "pure state" (like React) pretty much come down to options 2/3 as well (just that the framework will perform the heavy lifting for you).

Regarding option 3 (listening for a change on the whole form): https://stackoverflow.com/a/4616720/1168892 explains quite well how event bubbling in JavaScript happens. To use that you have to make sure that no element inside the form cancels the change event (otherwise it would not bubble to the form itself). To not cancel events is the default behavior, so you would have to explicitly make this wrong (and with that you can just have an eye on it in your implementation).


I didn't use jQuery in my examples as that can all be done by browsers directly now. What I used are Element.querySelectorAll, Array.reduce and window.fetch.

Community
  • 1
  • 1
Dominik Schreiber
  • 2,629
  • 1
  • 23
  • 33
0

Without jquery I once wrote a function that return in an object all input value tie with its name. I think it's better than plain id link, because you don't have to worry about what's inside your form, as long as your giving a name attribute to your inputs.

function getFormData(form) {
   var data = {};
   for (var i = 0; i < form.elements.length; i++) {
      var input = form.elements[i];

      if (input.value && input.type !== 'submit' && input.type !== 'button') {
         data[input.name] = input.value;
      }
   }
   return data;
}

All you need to do is passing your form like this:

var form = document.querySelector('.monFormulaire');
// your form data
var data = getFormData(form);
Gatsbill
  • 1,760
  • 1
  • 12
  • 25