Search code examples
javascriptforms

Is there a modern way to perform a "normal" (non-AJAX) form submission via Javascript?


I have a search form with half a dozen inputs, which performs a GET action to execute the search. Since there are many input fields, but only a handful are likely to be filled by any given search, I don't want the empty fields to be included in the GET args on the search request.

Here's my form (in django template syntax):

  <form id="advanced-search-form" action="{% url 'search:advanced_search' %}" method="GET">
      <div class="left clearfix">
        <div class="input-field">
          <label for="given-name">First Name:</label>
          <input id="given-name" name="givenName" tabindex="1">
        </div>
        <div class="input-field">
          <label for="sn">Last Name:</label>
          <input id="sn" name="sn"tabindex="2">
        </div>
        <div class="input-field">
          <label for="tel-number">Extension:</label>
          <input type="tel" id="tel-number" name="telephoneNumber" tabindex="3">
        </div>
      </div>
      <div class="right clearfix">
        <div class="input-field">
          <label for="category">Category:</label>
          <select id="category" name="personType" tabindex="4">
            <option value="">Choose One:</option>
            {% for slug, type in person_types.items %}
              <option value="{{ slug }}">{{ type }}</option>
            {% endfor %}
          </select>
        </div>
        <div class="input-field">
          <label for="building">Building:</label>
          <input id="building" name="physicalDeliveryOfficeName" tabindex="5">
        </div>
        <div class="input-field">
          <label for="dept">Department:</label>
          <input id="dept" name="department" {{ input_attrs }} tabindex="6">
        </div>
        <div class="submit-button">
          <input type="submit" value="Submit Search" tabindex="7">
        </div>
      </div>
    </form>

My objective is for the URL that this form leads to after submission with just the givenName field filled to look like this:

https://domain/search/advanced_search?givenName=Ben

Instead of looking like this:

https://domain/search/advanced_search?givenName=Ben&sn=&telephoneNumber=&personType=&physicalDeliveryOfficeName=&department=

I've found ancient SO questions which answer this question as "Create a new <form> in Javascript, populate it with <input>s that have the values you want, and then call .submit() on the form". e.g. https://stackoverflow.com/a/13937065/464318

I'm sure that's still viable today, but it seems extremely clunky. Is there not a more modern way to do this, perhaps via the FormData API? I've looked and looked for an answer to this in the MDN docs and all across google, but I think I just don't know the right term for "non-Ajax javascript form submission".

I don't want to use XMLHttpRequest or Fetch, because I actually want the form submission to trigger a normal page load leading the user to the search results page.


Solution

  • I'm assuming the use case here is to address things like:

    • Searches need to be bookmarked/shared, necessitating a GET request
    • Search URLs should be relatively clean when shared, as most users are likely to only use one or two search fields of the many fields offered

    If it's just a GET request then we don't really need a <form> (given the first use case concern above, many users won't be using one anyway). But a <form> is still very useful for quickly serializing the data. Once serialized however, you can use that data to simply build a URL and redirect the user.

    For example:

    const form = document.querySelector('#advanced-search-form');
    
    form.addEventListener('submit', function (e) {
      // prevent form submit
      e.preventDefault();
      
      // serialize form data
      const formData = new FormData(form);
      const params = {};
      
      // filter empty values
      for (const val of formData) {
        if (val[1]) {
          params[val[0]] = val[1];
        }
      }
      
      // redirect instead of console log here
      // window.location.href = `${form.action}?${new URLSearchParams(params).toString()}`;
      console.log(`${form.action}?${new URLSearchParams(params).toString()}`);
    });
    <form id="advanced-search-form" action="/some/url" method="GET">
      <div class="left clearfix">
        <div class="input-field">
          <label for="given-name">First Name:</label>
          <input id="given-name" name="givenName" tabindex="1">
        </div>
        <div class="input-field">
          <label for="sn">Last Name:</label>
          <input id="sn" name="sn"tabindex="2">
        </div>
        <div class="input-field">
          <label for="tel-number">Extension:</label>
          <input type="tel" id="tel-number" name="telephoneNumber" tabindex="3">
        </div>
      </div>
      <div class="right clearfix">
        <div class="input-field">
          <label for="category">Category:</label>
          <select id="category" name="personType" tabindex="4">
            <option value="">Choose One:</option>
            <option value="0">test</option>
          </select>
        </div>
        <div class="input-field">
          <label for="building">Building:</label>
          <input id="building" name="physicalDeliveryOfficeName" tabindex="5">
        </div>
        <div class="input-field">
          <label for="dept">Department:</label>
          <input id="dept" name="department" tabindex="6">
        </div>
        <div class="submit-button">
          <input type="submit" value="Submit Search" tabindex="7">
        </div>
      </div>
    </form>

    Leaving the form in place as-is also allows clients to fall back on the less-ideal-but-still-functional standard <form> action (to include empty values in the URL) when JavaScript is unavailable.