6

I am injecting JS from an iOS app to a web app. I control code for both. I am trying to write javascript that takes input from a barcode scanner and then puts it in a web form and then submits the form. I use the jQuery.form plugin to make all the forms ajax. I use ajaxForm.

I want to make the code as generic as possible in case I change the front-end code down the road (For example removing ajaxForm). My goal is to simply have a set of ids and when it matches an id to changes the value of the input and then submits the form. This form could be ajax or a regular form; but the iOS app should NOT know the implementation details. Is there a way to do this in vanilla js?

var scan_ids = ['item','search'];

for(var k=0;k<scan_ids.length;k++)
{
    var scan_id = scan_ids[k];

    if (document.getElementById(scan_id))
    {
        document.getElementById(scan_id).value = "[SCAN]";

        if (scan_id == "item")
        {
             /*I don't want to do this as I am bound to ajaxSubmit; 
I would rather trigger a form submit and have it use ajaxForm
 that is bound to it. If I do .submit() it ignores the ajaxForm */

            $('#add_item_form').ajaxSubmit({target: "#register_container", beforeSubmit: salesBeforeSubmit, success:itemScannedSuccess});


        $('#add_item_form').submit(); //(WORKS and submits via ajax)
        document.getElementById('add_item_form').submit(); //(SUBMITS; DOES NOT AJAX)
        }

        break;
    }
}
Chris Muench
  • 17,444
  • 70
  • 209
  • 362
  • What exactly is your question? Are you asking whether you can submit a form in vanilla JS without using a library/framework? – shennan Oct 08 '15 at 17:23
  • Correct. But I am trying to do it without even knowing the form or use jQuery. Just an id (if possible). See the last do lines in if (scan_id == 'item') – Chris Muench Oct 08 '15 at 17:25
  • Apologies, I didn't understand before. Okay, so you want to submit a form in plain JS, but via AJAX? – shennan Oct 08 '15 at 17:30
  • I want it i work exactly like `$('#add_item_form').submit();` in jQuery the form is actually using ajaxForm but I didn't need to know that for it to work. is there a way in vanilla js to work JUST like that? – Chris Muench Oct 08 '15 at 17:39
  • 1
    Can I ask why you'd like to use vanilla JS to do this? You will essentially be re-writing a module that already works. – shennan Oct 08 '15 at 17:42
  • I guess your right. I will stick with the simple jQuery solution. – Chris Muench Oct 08 '15 at 17:50

1 Answers1

9

In order to submit a form using vanilla/plain JS, simply call the submit method on the form:

document.getElementById('formId').submit();

However, it sound like you want to make an AJAX request. These are different from standard HTTP requests. They are called XMLHttp Requests.

When you submit a form using a plain HTTP request (what happens when you use form.submit()), the browser populates the POST/GET variables that get sent to the server by using the information inside the <form> that is being sent.

When sending an XMLHttp Request, that work is not done for you. You must do it yourself.

As far as I can tell, this is the bulk of what jQuery.form is doing. It is collecting the information in your form, populating an XMLHttp Request, and then submitting the form to the server using so-called AJAX technology.

You may find this answer useful; someone has written a plain Javascript method for submitting a form via AJAX. Here is the method from that answer:

/**
 * Takes a form node and sends it over AJAX.
 * @param {HTMLFormElement} form - Form node to send
 * @param {function} callback - Function to handle onload. 
 *                              this variable will be bound correctly.
 */

function ajaxPost (form, callback) {
    var url = form.action,
        xhr = new XMLHttpRequest();

    //This is a bit tricky, [].fn.call(form.elements, ...) allows us to call .fn
    //on the form's elements, even though it's not an array. Effectively
    //Filtering all of the fields on the form
    var params = [].filter.call(form.elements, function(el) {
        //Allow only elements that don't have the 'checked' property
        //Or those who have it, and it's checked for them.
        return typeof(el.checked) === 'undefined' || el.checked;
        //Practically, filter out checkboxes/radios which aren't checekd.
    })
    .filter(function(el) { return !!el.name; }) //Nameless elements die.
    .filter(function(el) { return !el.disabled; }) //Disabled elements die.
    .map(function(el) {
        //Map each field into a name=value string, make sure to properly escape!
        return encodeURIComponent(el.name) + '=' + encodeURIComponent(el.value);
    }).join('&'); //Then join all the strings by &

    xhr.open("POST", url);
    xhr.setRequestHeader("Content-type", "application/x-form-urlencoded");

    //.bind ensures that this inside of the function is the XHR object.
    xhr.onload = callback.bind(xhr); 

    //All preperations are clear, send the request!
    xhr.send(params);
}

It's probably worth noting that the original poster of this code is using methods that won't work on some older browsers. Notably browsers that do not support the ECMAScript 5 implementation.

My advice would be to stick to using the plugin you already have. I can't see a reason to re-invent the wheel. Rest assured that your jQuery library is using vanilla Javascript under the hood.

shennan
  • 10,798
  • 5
  • 44
  • 79
  • 1
    I tested this in Chrome Version 53.0.2785.116 (64-bit) and for input fields el.checked equals false. So I included this `|| el.type !== 'checkbox' || el.type !== 'radio'` to that line. I didn't want to edit this post without making this comment first. Would you say that with this, checking for `typeof(el.checked) === 'undefined'` is necessary? – Martin Schaer Sep 26 '16 at 15:32
  • Appears those `.filter(function(el) {...})` methods need closing parentheses. Lines 21,22. Thanks for the answer! – Daniel Fowler May 17 '17 at 15:56
  • @danfo well spotted. Thanks – shennan May 17 '17 at 15:57
  • 1
    `!el.disabled` in the filter. – David Karlsson Dec 27 '18 at 15:19