I have a login form, and when submitted it calls this function
login = (that) ->
header =
"X-CSRFToken": window.csrftoken
$('body').toggleDOM('.loading', true)
fermata.json("/login").post(header, that, (err, data) ->
$('body').toggleDOM('.loading', false)
if !data.success
htAlert.error 'Incorrect username and/or password.'
)
This will add a "loading spinner" while the API is being called, and then it's removed. This works fine the first time you submit the form, because I'm using preventDefault
so the page doesn't reload. However on the 2nd try, the page will reload, and I don't know why it's behaving like that.
My DOM function to add an element to the body:
$.fn.toggleDOM = (domName, b) ->
dom = domName[domName.search(/([\.\#])/)]
newDom = domName.substring(1)
if dom == '#'
if b
document.body.innerHTML += '<div id="' + newDom + '"></div>'
else
document.getElementById(newDom).remove()
else
if b
document.body.innerHTML += '<div class="' + newDom + '"></div>'
else
document.getElementsByClassName(newDom)[0].remove()
The event for form submit:
$ ->
trigger = document.querySelectorAll("[data-trigger]")
trigger.forEach((i) ->
i.addEventListener "submit", (e) ->
e.preventDefault()
# We have to pass the event instead of the element.
switch i.attributes["data-trigger"].nodeValue
when "[form/login]" then login(e)
HTML:
<form data-trigger="[form/login]" class="login">
<input type="hidden" class="uuid hidden">
<input placeholder="Username" class="username">
<input placeholder="Password" type="password" class="password">
<button type="submit">Login</button>
</form>
I need to know why it reloads the page on the 2nd try. If I remove the $('body').toggleDOM('.loading', true)
it does not behave like that and works as intended.
Also, I'm not using jQuery, I'm using this small library: https://github.com/finom/balalaika
The problem lies in how you attach event listeners to your elements. What you're trying to do doesn't work in plain JavaScript.
What you need to utilize is event delegation; it won't change much code wise but it'll change how it works.
By removing your for loop and attaching the handler to the document
instead, you'll get what you're after.
document.addEventListener "submit", (e) ->
e.preventDefault();
switch e.target.attributes["data-trigger"].nodeValue
when "[form/login]" then login(e)
There is a great article that covers the how and why