How to attach submit listener to all forms includi

2019-06-07 05:17发布

问题:

I want to attach an event listener to every form on my site so that when a form is submitted, a confirm box will pop up asking if the user is sure they want to proceed. If the user is not sure, I don't want the form to fire.

So far I have this code:

window.onload = function() {
  for(var i=0; i<document.forms.length; i++){
    document.forms[i].addEventListener("submit",formSubmit,false);
  }
}

function formSubmit(e) {
  if (confirm("Are you sure?")) {
    return true;
  }
  return false;
}

Notes:

  1. I can't use jQuery
  2. I can't use an onDOMReady type function because the iframes may not have loaded yet - so window.onload is my only option (I think?)
  3. This code does not work because when the "Are you sure?" confirm box pops up when I submit a form, whichever button I click, the form still submits.
  4. This code also does not work because it does not pick up forms inside iframes. I need to not only catch forms within iframes, but also forms that may be within iframes that are within iframes...

I've tried this:

var frame = document.getElementById("frameID").contentDocument;
for(var i=0; i<frame.forms.length; i++){
  frame.forms[i].addEventListener("submit",formSubmit,false);
}

But it only works for the first frame, and it doesn't seem to work if I have got to the page via the "Back" button. Is that something to do with the way wondow.onload works?

Thanks for your help in advance!

Update

From the answer given by @Jan Pfeifer I have the following code which solves the problem of the form still submitting even when you choose "Cancel", but it does not add the listener to every form in every frame properly. I'm starting a bounty for this - can anyone make it work for nested iframes in every browser?

function attach(wnd,handler){
  for(var i=0; i<wnd.document.forms.length; i++){
    var form = wnd.document.forms[i];
    form.addEventListener('submit',handler,false);
  }

  for(var i=0; i<wnd.frames.length; i++){
    var iwnd = wnd.frames[i];               
    attach(iwnd,handler);
  }
}

function formSubmit(e){
  if(!confirm('Are you sure?')) {
    e.returnValue = false;
    if(e.preventDefault) e.preventDefault();
    return false;
  }
  return true;
}

window.addEventListener('load',function(){attach(window,formSubmit);},false);

回答1:

You will need recursion. attach function will add handler to every form and call itself on every iframe to do the same with it. Return value is not passed, so you will need to cancel the event manually.

UPDATE Corrected errors

     function attach(wnd,handler){
        for(var i=0; i<wnd.document.forms.length; i++){
            var form = wnd.document.forms[i];
                form.addEventListener('submit', handler,false);
        }

        for(var i=0; i<wnd.frames.length; i++){
            var iwnd = wnd.frames[i];               
            attach(iwnd,handler);
        }
     }

     function formSubmit(e){
        if(!confirm('Are you sure?')) {
       e.returnValue = false;
           if(e.preventDefault) e.preventDefault();
           return false;
           }
           return true;
     }

     window.addEventListener('load', function(){attach(window,formSubmit);},false);


回答2:

So I've managed to solve this myself.

There were two main problems:

  1. wnd.frames[i] was sometimes returning the window of the iframe and sometimes the document depending on the browser - I've changed the method of selecting the iframe to wnd.document.getElementsByTagName("iframe")[i].contentWindow which is more reliable if a bit wordy.
  2. Chrome and IE both stopped execution if the returned window had an undefined document or name so I've added a simple if statement to catch this.

The result is this:

function attach(wnd,handler){
  if (!(wnd.document === undefined)) {
    for(var i=0; i<wnd.document.forms.length; i++){
      var form = wnd.document.forms[i];
      form.addEventListener('submit',handler,false);
      alert("Found form in " + wnd.name);
    }

    for(var i=0; i<wnd.document.getElementsByTagName("iframe").length; i++){
      var iwnd = wnd.document.getElementsByTagName("iframe")[i].contentWindow;
      alert("Found " + iwnd.name + " in " + wnd.name);
      attach(iwnd,handler);
    }
  }
}

function formSubmit(e){
  if(!confirm('Are you sure?')) {
    e.returnValue = false;
    if(e.preventDefault) e.preventDefault();
    return false;
  }
  return true;
}

window.addEventListener('load', function(){
  attach(window,formSubmit);
},false);