151

If I have a form like this,

<form action="/Car/Edit/17" id="myForm" method="post" name="myForm"> ... </form>

how can I submit it without redirecting to another view by JavaScript/jQuery?

I read plenty of answers from Stack Overflow, but all of them redirect me to the view returned by the POST function.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Duke Nuke
  • 1,815
  • 3
  • 15
  • 14
  • You want an XHR request (AJAX) – Sterling Archer Sep 22 '14 at 21:47
  • 3
    XHR / AJAX is _one_ way — it submits the post and gets the response behind the scenes, so the browser never leaves the page it's on. Another way is a server-side redirect after processing the post, which depends on what server technology you're using. – Stephen P Sep 22 '14 at 21:49
  • @StephenP I use ASP.NET MVC 5.1. – Duke Nuke Sep 22 '14 at 21:56
  • @Duke, all I'm saying is there is more than one approach (ajax vs. server-redirect) and your choice depends on your needs. Modern sites will most likely want to do ajax. Note also that all these answers are saying you **need** jQuery — jQuery's great but there _are_, in fact, other ways to do ajax... though I would indeed use jQuery myself. – Stephen P Sep 22 '14 at 22:09
  • 1
    My way is simple clean and elegant, and it's only 2 lines of code. It uses no scripts, and works in HTML4 and above, even if JavaScript is turned off. – Issa Chanzi Apr 01 '15 at 00:00

13 Answers13

189

You can achieve that by redirecting the form's action to an invisible <iframe>. It doesn't require any JavaScript or any other type of scripts.

<iframe name="dummyframe" id="dummyframe" style="display: none;"></iframe>

<form action="submitscript.php" target="dummyframe">
    <!-- Form body here -->
</form>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Issa Chanzi
  • 2,254
  • 2
  • 15
  • 21
99

In order to achieve what you want, you need to use jQuery Ajax as below:

$('#myForm').submit(function(e){
    e.preventDefault();
    $.ajax({
        url: '/Car/Edit/17/',
        type: 'post',
        data:$('#myForm').serialize(),
        success:function(){
            // Whatever you want to do after the form is successfully submitted
        }
    });
});

Also try this one:

function SubForm(e){
    e.preventDefault();
    var url = $(this).closest('form').attr('action'),
    data = $(this).closest('form').serialize();
    $.ajax({
        url: url,
        type: 'post',
        data: data,
        success: function(){
           // Whatever you want to do after the form is successfully submitted
       }
   });
}

Final solution

This worked flawlessly. I call this function from Html.ActionLink(...)

function SubForm (){
    $.ajax({
        url: '/Person/Edit/@Model.Id/',
        type: 'post',
        data: $('#myForm').serialize(),
        success: function(){
            alert("worked");
        }
    });
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Amin Jafari
  • 7,157
  • 2
  • 18
  • 43
  • This worked great the problem is that I don't want it to be automatically(always) submited this way. I would like to have a function with a name to do this stuff you posted in your answer. So I can invoke it manually when I want to, to make it post the form. Like below I can give the name of the function to invoke. `@Html.ActionLink("Add a Report", "Create", "Reports", new { carId = Model.Id }, new { onclick = "FUNCTION_WHICH_SUBMITES_FORM()" })` – Duke Nuke Sep 22 '14 at 22:30
  • This worked: `function SubForm (){ alert("1"); //e.preventDefault(); $.ajax({ url:'/Car/Edit/@Model.Id/', type:'post', data:$('#myForm').serialize(), success:function(){ alert("fasf"); } }); }` – Duke Nuke Sep 22 '14 at 22:43
  • For some reason your second solution did not work, but the one I posted in last comment did. I will add my solution to your post cause only because of you I could achieve this. – Duke Nuke Sep 22 '14 at 22:58
  • 1
    the second one must work as well, there might be something else to it, but if you found the solution we don't need to go down that road right now! glad it helped ;) – Amin Jafari Sep 22 '14 at 23:01
  • Thanks [this](https://stackoverflow.com/a/7336591/1526703) answer also helped me put a custom text in place of the form after submission – Anupam Aug 03 '17 at 13:14
  • we should start new stack overflow without jquery answers – VityaSchel Oct 23 '21 at 09:55
55

Since all current answers use jQuery or tricks with iframe, figured there is no harm to add method with just plain JavaScript:

function formSubmit(event) {
  var url = "/post/url/here";
  var request = new XMLHttpRequest();
  request.open('POST', url, true);
  request.onload = function() { // request successful
  // we can use server response to our request now
    console.log(request.responseText);
  };

  request.onerror = function() {
    // request failed
  };

  request.send(new FormData(event.target)); // create FormData from form that triggered event
  event.preventDefault();
}

// and you can attach form submit event like this for example
function attachFormSubmitEvent(formId){
  document.getElementById(formId).addEventListener("submit", formSubmit);
}
Esuil
  • 671
  • 5
  • 5
  • 2
    I tip my hat to you. I've spent hours trying to figure out how to get jquery to send a form to an nginx backend with the contentType=false parameter and always get a 415 as a result. This was the only solution I found that solved my particular problem. – user12066 Jun 13 '20 at 15:52
34

Place a hidden iFrame at the bottom of your page and target it in your form:

<iframe name="hiddenFrame" width="0" height="0" border="0" style="display: none;"></iframe>

<form action="/Car/Edit/17" id="myForm" method="post" name="myForm" target="hiddenFrame"> ... </form>

Quick and easy. Keep in mind that while the target attribute is still widely supported (and supported in HTML5), it was deprecated in HTML 4.01.

So you really should be using Ajax to future-proof.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Steven Black
  • 360
  • 1
  • 4
  • 6
13

Okay, I'm not going to tell you a magical way of doing it because there isn't. If you have an action attribute set for a form element, it will redirect.

If you don't want it to redirect simply don't set any action and set onsubmit="someFunction();"

In your someFunction() you do whatever you want, (with AJAX or not) and in the ending, you add return false; to tell the browser not to submit the form...

Anshu Dwibhashi
  • 4,617
  • 3
  • 28
  • 59
  • 1
    There is a magical way of doing it. Set a target attribute so the form redirects to somewhere other than the current frame. If you add an invisible iframe for things like this in your pages. It's pretty simple. – Issa Chanzi Apr 01 '15 at 00:06
6

One-liner solution as of 2020, if your data is not meant to be sent as multipart/form-data or application/x-www-form-urlencoded:

<form onsubmit='return false'>
    <!-- ... -->           
</form>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alexandre Daubricourt
  • 3,323
  • 1
  • 34
  • 33
  • 5
    If you combine this with the OP's `action="..."`, this effectively prevents the page switch, but also prevents data being submitted across the network. – Kev Mar 27 '20 at 14:40
  • @Kev I personally send my data via JS XHR, that's why I don't want page redirection, cause it's a JS app – Alexandre Daubricourt Mar 28 '20 at 07:21
5

You need Ajax to make it happen. Something like this:

$(document).ready(function(){
    $("#myform").on('submit', function(){
        var name = $("#name").val();
        var email = $("#email").val();
        var password = $("#password").val();
        var contact = $("#contact").val();

        var dataString = 'name1=' + name + '&email1=' + email + '&password1=' + password + '&contact1=' + contact;
        if(name=='' || email=='' || password=='' || contact=='')
        {
            alert("Please fill in all fields");
        }
        else
        {
            // Ajax code to submit form.
            $.ajax({
                type: "POST",
                url: "ajaxsubmit.php",
                data: dataString,
                cache: false,
                success: function(result){
                    alert(result);
                }
           });
        }
        return false;
    });
});
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bojan Petkovski
  • 6,835
  • 1
  • 25
  • 34
  • 6
    Is there any particular reason why you don't indent this source code? It looks like code from the sixties before C was invented. I thought we were over this for a long time. – Alfe Aug 10 '16 at 13:27
2

See jQuery's post function.

I would create a button, and set an onClickListener ($('#button').on('click', function(){});), and send the data in the function.

Also, see the preventDefault function, of jQuery!

Nagy Vilmos
  • 1,878
  • 22
  • 46
1

The desired effect can also be achieved by moving the submit button outside of the form as described here:

Prevent page reload and redirect on form submit ajax/jquery

Like this:

<form id="getPatientsForm">
    Enter URL for patient server
    <br/><br/>
    <input name="forwardToUrl" type="hidden" value="/WEB-INF/jsp/patient/patientList.jsp" />
    <input name="patientRootUrl" size="100"></input>
    <br/><br/>
</form>

<button onclick="javascript:postGetPatientsForm();">Connect to Server</button>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
John
  • 3,458
  • 4
  • 33
  • 54
1

Using this snippet, you can submit the form and avoid redirection. Instead you can pass the success function as argument and do whatever you want.

function submitForm(form, successFn){
    if (form.getAttribute("id") != '' || form.getAttribute("id") != null){
        var id = form.getAttribute("id");
    } else {
        console.log("Form id attribute was not set; the form cannot be serialized");
    }

    $.ajax({
        type: form.method,
        url: form.action,
        data: $(id).serializeArray(),
        dataType: "json",
        success: successFn,
        //error: errorFn(data)
    });
}

And then just do:

var formElement = document.getElementById("yourForm");
submitForm(formElement, function() {
    console.log("Form submitted");
});
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
julianm
  • 2,393
  • 1
  • 23
  • 24
0

Fire and forget vanilla js + svelte

function handleSubmit(e) {
    const request = new Request(`/products/${item.ItemCode}?_method=PUT`, { 
        method: 'POST', 
        body: new FormData(e.target),
    });
    fetch(request)
}

Used in Svelte:

<form method="post" on:submit|preventDefault={handleSubmit}>
myleftshoe
  • 55
  • 1
  • 7
0

Using web components you can create an easily reusable form component that handles this nicely.

function urlencodeFormData(fd: FormData) {
  let s = '';
  function encode(s: string) {
    return encodeURIComponent(s).replace(/%20/g, '+');
  }
  const formData: [string, string][] = [];
  fd.forEach((value, key) => {
    if (value instanceof File) {
      formData.push([key, value.name]);
    } else {
      formData.push([key, value]);
    }
  });
  for (const [key, value] of formData) {
    s += (s ? '&' : '') + encode(key) + '=' + encode(value);
  }
  return s;
}

const xhrOnSubmit = (event: SubmitEvent) => {
  console.log('Form submitted');
  const form: HTMLFormElement | null =
    event.target instanceof HTMLFormElement ? event.target : null;
  if (form == null) {
    console.error('Event target of form listener is not a form!');
    return;
  }
  let baseUrl = form.action;
  if (baseUrl == null || baseUrl === '') {
    baseUrl = window.location.href;
  }

  const requestUrl = new URL(baseUrl, window.location.href);
  
const shouldClear = form.getAttribute('data-clear-form') === 'true';

  // Decide on encoding
  const formenctype =
    event.submitter?.getAttribute('formenctype') ??
    event.submitter?.getAttribute('formencoding');
  const enctype =
    formenctype ??
    form.getAttribute('enctype') ??
    form.getAttribute('encoding') ??
    'application/x-www-form-urlencoded';

  // Decide on method
  let formMethod =
    event.submitter?.getAttribute('formmethod') ??
    form.getAttribute('method')?.toLowerCase() ??
    'get';

  const formData = new FormData(form);

  // Encode body
  let body: BodyInit | null = null;
  if (formMethod === 'get') {
    requestUrl.search = new URLSearchParams(
      urlencodeFormData(formData)
    ).toString();
  } else if (formMethod === 'post') {
    if (enctype === 'application/x-www-form-urlencoded') {
      body = urlencodeFormData(formData);
    } else if (enctype === 'multipart/form-data') {
      body = formData;
    } else if (enctype === 'text/plain') {
      let text = '';
      // @ts-ignore - FormData.entries() is not in the TS definition
      for (const element of formData.keys()) {
        text += `${element}=${JSON.stringify(formData.get(element))}\n`;
      }
    } else {
      throw new Error(`Illegal enctype: ${enctype}`);
    }
  } else if (formMethod === 'dialog') {
    // Allow default behavior
    return;
  } else {
    throw new Error(`Illegal form method: ${formMethod}`);
  }

  // Send request
  const requestOptions: RequestInit = {
    method: formMethod,
    headers: {
      'Content-Type': enctype,
    },
  };
  if (body != null && formMethod === 'post') {
    requestOptions.body = body;
  }
  const response = fetch(baseUrl, requestOptions).then((response) => {
    if (shouldClear) {
      form.reset();
    }
    if (response.ok) {
      form.dispatchEvent(
        new CustomEvent('xhr-form-success', {
          detail: response,
        })
      );
    } else {
      form.dispatchEvent(
        new CustomEvent('xhr-form-failure', {
          detail: response,
        })
      );
    }
    return response;
  });

  event.preventDefault();
};

customElements.define(
  'xhr-form',
  class extends HTMLFormElement {
    constructor() {
      console.log('Form constructed');
      super();
    }

    connectedCallback() {
      this.addEventListener('submit', xhrOnSubmit);
    }

    disconnectedCallback() {
      this.removeEventListener('submit', xhrOnSubmit);
    }
  },
  { extends: 'form' }
);

An example of use (everything to do with the events is optional):

<form action="/printer" method="post" id="xhr-form" is="xhr-form">
  <h2>XHR POST Test</h2>
  <input type="text" name="name" placeholder="Name">
  <input type="number" name="age" placeholder="Age">
  <input type="submit" value="Submit">
</form>

<script>
  const xhrForm = document.getElementById('xhr-form');

  xhrForm.addEventListener('xhr-form-success', (event) => {
    console.log('XHR Form Success', event.detail);
  });

  xhrForm.addEventListener('xhr-form-failure', (event) => {
    console.log('XHR Form Failure', event.detail);
  });
</script>
Tag Howard
  • 194
  • 1
  • 11
-2

If you control the back end, then use something like response.redirect instead of response.send.

You can create custom HTML pages for this or just redirect to something you already have.

In Express.js:

const handler = (req, res) => {
  const { body } = req
  handleResponse(body)
  .then(data => {
    console.log(data)
    res.redirect('https://yoursite.com/ok.html')
  })
  .catch(err => {
    console.log(err)
    res.redirect('https://yoursite.com/err.html')
  })
}
...
app.post('/endpoint', handler)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sucasa
  • 373
  • 1
  • 8
  • 19