5

I have a form I am trying to submit with HTML and JavaScript. I have attached an event listener to my checkboxes (.checkbox), that waits for a click, and upon a click, launches a function that attempts to submit the form.

I have succeeded with jQuery's .parent() usage, but am now attempting to switch that to vanilla JS.

I have tried this.parentNode.submit();, however it gives back the error message.

this.parentNode.submit is not a function at HTMLInputElement.formSubmit

Is there a possible way I can submit my form by replacing the jQuery $(this).parent().submit() to a vanilla JS equivalent?

HTML:

<form id="theform" action="/phones/search_results" accept-charset="UTF-8" data-remote="true" method="post"><input name="utf8" type="hidden" value="✓">
  <label>
    <input type="checkbox" name="brand_name" id="brand_name" value="Apple" class="Apple brand checkbox" style="height: 30px;">
        Apple

  </label>

$(function() {
  var checkbox = document.querySelectorAll(".checkbox");
  for (var i = 0; i < checkbox.length; i++) {
    checkbox[i].addEventListener("click", formSubmit)
  }

});
function formSubmit(){
  if(this.checked){
    $(this).parent().submit();
    console.log("Form was submitted" + this.parentNode)
  }
}
the12
  • 2,395
  • 5
  • 19
  • 37
  • Why mix DOM and jquery? – epascarello Mar 15 '17 at 01:50
  • Plan on getting rid of `$(function(){})`, so plan on replacing jQuery with JS for a project. – the12 Mar 15 '17 at 01:51
  • 2
    I misread the question.... `this.form.submit()` – epascarello Mar 15 '17 at 01:52
  • I was hoping for a `parent()` JS equivalent, if possible :) – the12 Mar 15 '17 at 01:56
  • 1
    of course since jQuery is JavaScript... http://stackoverflow.com/questions/6856871/getting-the-parent-div-of-element – epascarello Mar 15 '17 at 02:01
  • 1
    Have you tried `this.parentNode.parentNode.submit()`? In your html, the input's parent is the *label* element, not the form, so I don't see how `$(this).parent().submit()` worked either - it wouldn't have given an error, but it would've triggered a submit event on the label. – nnnnnn Mar 15 '17 at 02:17
  • @nnnnnn You're right, that's why my code wasn't working. Having analyzed it, I don't think parentNode and parent() are the same thing. Having run a `console.log("JQuery:" + $(this).parent() + "JavaScript:" + this.parentNode)`. It returns [Object object] for `parent()` and [object HTMLLabelElement] for `parentNode`. I'm not sure if its a Rails thing or a JS thing. Reason why I'm being so particular, is that for some reason jquery method is giving me back desired results (JS AJAX request) vs. `parentNode.parentNode` (HTML request). – the12 Mar 15 '17 at 02:34
  • 1
    `.parent()` returns a jQuery object that wraps the DOM element, but `.parentNode` returns the actual DOM element. They're not supposed to be the same. Regarding the difference in calling `.submit()`, when you call it on the form DOM element it submits the form. When you call it on the jQuery object, it triggers the event handler that you have bound to the form (and presumably your event handler does the Ajax request). If you want to do this in plain JS and use Ajax, just a call your handler directly, don't call `.submit()`. – nnnnnn Mar 15 '17 at 02:43
  • @nnnnnn Oh ok thank you for that piece of advice, did not know that. Would you know of a way to convert `.parent()` to vanilla JS equivalent? – the12 Mar 15 '17 at 02:49
  • 1
    The concept of an equivalent version in vanilla JS doesn't really make sense, because (as I mentioned before) `.parent()` - and most other jQuery methods - will return a jQuery object that is a wrapper around a list of DOM elements. (Sometimes the list is empty or has only one element in it.) This jQuery object wrapper is what lets you call all the other jQuery methods, and chain them, etc., like when you said `$(this).parent()`, or `.parent().submit()`. This is a big part of what makes jQuery easy to use, especially to manipulate multiple elements at once. – nnnnnn Mar 15 '17 at 02:56
  • 1
    (previous comment continued) Of course you can write your own version of wrapper objects that have their own DOM manipulation methods, but if you take that *too* far you might as well just use jQuery. (Or use a light-weight equivalent like [Zepto.js](http://zeptojs.com/).) The native method `document.querySelectorAll()` is a bit like the `$()` method in that it returns a list of zero or more elements that matched a selector, and you can loop over that list (or convert it to an array and use native array methods) to process the whole list. – nnnnnn Mar 15 '17 at 02:58
  • Thank you for all your help @nnnnnn. You clearly know your stuff. I guess I'm going to have to figure out how to make it work with plain JS from the Rails community (get similar, desirable behavior as `parent()` for vanilla JS). Thanks though, definitely learned more about jQuery! – the12 Mar 15 '17 at 03:09
  • Really surprised to see that nobody suggested `element.closest` yet, as it does exactly what you want and cuts out any middle men (and elements). – somethinghere Oct 17 '19 at 10:52

6 Answers6

3

You can select the enclosing form element and submit it as such:

element.closest( 'form' ).submit();

This ignores any nesting and doesn't require you to loop through the form yourself. It functions like querySelector in that it can also return null, so beware of that as it will throw an error if it's not nested in a form.

MDN https://developer.mozilla.org/en-US/docs/Web/API/Element/closest

somethinghere
  • 16,311
  • 2
  • 28
  • 42
2

You could use the parentNode property, but in your case that will point to the label element, so it would become event.target.parentNode.parentNode. It is probably easier to use the even target form property, like this.

function formSubmit(event){
    event.target.form.submit();
    this.parentNode.parentNode.submit(); //Alternatively without event, using parentNode
}

document.getElementById("brand_name").onclick=formSubmit;
visibleman
  • 3,175
  • 1
  • 14
  • 27
  • 1
    In case the nesting isn't as specific you might want to use `this.closest('form').submit()`, which means you can continue nesting as much as you want without ever having to touch it again. – somethinghere Oct 17 '19 at 10:45
  • This is an old question, answer, and comment, but I just browsed back here now. And yes event.target.closest, is a good fit as long as you don't need to support Internet Explorer. – visibleman Jan 20 '20 at 00:20
1

You can trigger a submit event from a child element that will be catched by an enclosing form element like this:

const event = new Event('submit', {bubbles: true, cancelable: true});
childElement.dispatchEvent(event);
Sámal Rasmussen
  • 2,887
  • 35
  • 36
0

Nice job using vanilla js! Here is a great resource if you have any other questions about jquery to vanilla js in the future: http://youmightnotneedjquery.com/

document.getElementById("theform").submit(); will allow you to submit the application

  • Thanks, looking for the direct `parent()` equivalent though. – the12 Mar 15 '17 at 02:14
  • parentNode is the direct equivalent to parent in jquery – NachoSupreme Mar 15 '17 at 02:49
  • According to @nnnnnn, ".parent() returns a jQuery object that wraps the DOM element, but .parentNode returns the actual DOM element" -nnnnnn. `console.log("JQuery:" + $(this).parent() + "JavaScript:" + this.parentNode)` yields [Object object] for `parent()`, and [object HTMLLabelElement] for `parentNode` – the12 Mar 15 '17 at 02:54
0

You could try using Node.parentElement

But accessing the form the way the other answers suggest seems more straightforward to me than retrieving the form indirectly like this.

Euroclydon37
  • 667
  • 7
  • 20
  • I plan on having multiple forms, thus I need to use the keyword this along with its respective parent, as it would be much more efficient than writing the code below out for each form. – the12 Mar 15 '17 at 02:36
  • Ah, that makes perfect sense. – Euroclydon37 Mar 15 '17 at 02:38
-1

document.getElementById("theform").submit();

https://www.w3schools.com/jsref/met_form_submit.asp

Adam
  • 3,142
  • 4
  • 29
  • 48