html5 required attribute to fire jquery event - javascript

I am making a form in which I am using required attribute on its elements. Now consider the following situation-
The form is divided in two tabs say General Details and Additional Details. So while submitting the form if I leave the required field blank on the visible tab then user can view the message. But suppose user is on first tab and error comes on second tab then User cannot view the error popup and he is clueless about why the form is not submitting.
Now I am searching for a way a jQuery event can be fired, whenever the required attribute error comes.
So on this event I can program to show the tab on which the error comes.
Please note I know I can use the JS/jQuery based form validation but the main thing is that, this form is being generated by Grails and the required field is auto-applied depending on the database. So I cannot use per form based JS validation.

See how the required field is selected with the :invalid pseudo class:
jQuery(document).ready(function(){
jQuery('button').on('click',function(){
jQuery('input:invalid').css('background-color', '#F00');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="required test">
<input type="text" required="required" />
<button>click</button>
</form>
You could simply check for the fields visibility, and if not given traverse up to the parent tab, give the parent tab a class which marks the tab label as containing something invalid.

One way is to use submit button and call myValidationFunction() method of JavaScript as action. (action="myValidationFunction();").
Other way is to use button and call myValidationFunction() method of JavaScript as on Click event of that button. After that, inside myValidationFunction(), you can use checkValidity() method to check validity of form at once or particular element and run your custom code to shift on particular tab if there is error to show to the user. function myValidationFunction() {
if ( $('#myInput')[0].checkValidity() ) {
// code to move to the particular tab
}
}

Related

Why does calling submit on a form and click on a submit button produce different GET parameters?

I'm trying out a simple CSRF attack and ran into an issue.
If I have a dummy site containing this form:
<form action="somewebsitetoexploit.com/someformpage" method="GET" hidden>
<input type="password" autocomplete="off" name="password_new" value="hacked"><br>
<input type="password" autocomplete="off" name="password_conf" value="hacked">
<input type="submit" value="Change" name="Change">
</form>
My original idea was to have this form "self submitting" by having a script tag call submit on the form on page load to automatically change the user's password when they visit the page:
<script>
window.onload = (_) => {
const form = document.getElementsByTagName("form")[0];
form.submit();
};
</script>
This looked like it worked, but the password failed to change. When looking at the GET parameters, I realized that it was because it didn't include the Change parameter (the submit button itself). It produced:
?password_new=hacked&password_conf=hacked
Instead of:
?password_new=hacked&password_conf=hacked&Change=Change
And I'm guessing this is causing it to fail a validation check on the backend.
It seemed hacky, but I was able to fix it by having it click the submit button instead of submiting the form directly:
<script>
window.onload = (_) => {
const submit = document.getElementsByName("Change")[0];
submit.click();
};
</script>
I looked over the relevant MDN page, and it notes that calling submit has two differences from clicking the submit button:
No submit event is raised. In particular, the form's onsubmit event handler is not run.
Constraint validation is not triggered.
It isn't immediately clear though why the onsubmit not firing would affect what GET parameters are sent, so I'm not sure if that's relevant.
Obviously for forms that use GET as the method, I could just construct the URL with query parameters manually and not worry about having a form. For the sake of learning though (and in case I want to manipulate a form that uses POST in the future), I'd like to understand what's happening here.
The page I'm trying to "attack" is the password change CSRF page of DVWA.
A form can have multiple submit buttons, with different names and/or values.
When you click a submit button and the default submit action takes place, the name and value of the button you clicked are included in the form parameters when the form is submitted.
When you call the submit() method there's no associated button click, so no button name and value will be included in the parameters. If the form has multiple submit buttons, which button would you expect it to send?
This behavior is specified in the HTML standard:
The submit() method, when invoked, must submit the form element from the form element itself, with the submitted from submit() method flag set.
Where submission carries out the many steps described here:
When a form element form is submitted from an element submitter (typically a button), optionally with a submitted from submit() method flag set, the user agent must run the following steps:
...
Let submitterButton be null if submitter is form. Otherwise, let submitterButton be submitter.
...
Let entry list be the result of constructing the entry list with form, submitter, and encoding.
Where the entry list eventually results in a string like ?password_new=hacked&password_conf=hacked.
If you submit the form by pressing the button (either manually or programatically), submitter is set to the button, so the entry list includes the button.
If you submit the form by using .submit(), submitter is set to the form, so submitterButton is set to null, so the entry list does not include it.
The construction of the entry list skips buttons which are not submitter:
For each element field in controls, in tree order:
If any of the following is true:
The field element is a button but it is not submitter.
Then continue.

jQuery input change doesn't work

I'm trying to make something like a shopping cart, but just with an order form.
I am using this pattern to fire input changes, but it doesn't work in my case.
Here what I have first.
<div class="ingrid__table-row">
<div class="ingrid__table-data ingrid__table-item">Lemon</div>
<div class="ingrid__table-data ingrid__table-weight">15g</div>
<div class="ingrid__table-data ingrid__table-price">10</div>
</div>
With jQuery, on click, I take the data from ingrid__table-data and add to the suitable input into .order__container.
Then, on the same click, a number input is appended, which will enable to choose the quantity of the selected products.
$('.order__container').append(`<input class="bul-order-info__input bul-order-info__qnt" type="number" name="Quantity" min="1" value="1">`)
And it appears on a webpage in the order form.
I need to detect the value changes of "number type input" and fire other events.
But the input changes are not detected, although if I create the same input element manually in HTML document, these changes are detected perfectly as it's shown here
How can I achieve this behavior?
My best guess based on the info you provided is that you are trying to attach the on change event to the dynamically created inputs on this way:
$('.bul-order-info__input').change( function () {...} );
But with the code before you are aren't applying those changes to any input because none of them exists when you are creating the event handlers, so you have to bind the events to an existing element like this:
$(document).on('change', '.bul-order-info__input', function() {...});
The element doesn't have to be always document, but I tend to use it, because is the only one that always will be present. However, something like this is also valid:
$('.order__container').on('change', '.bul-order-info__input', function() {...});

Saving form values dependant upon onclick/onchange functions

I have a form that saves user entered values on submit with php.
Some of the fields are in div's that are display:hidden until an onclick or onchange function changes that div to show.
How can I show only the divs containing fields with saved values after the form has been submitted? I have saved the values in the always visible fields but cannot trigger their functions.
I am using very little jquery because I am new to the syntax and would prefer to implement solutions I can understand and adapt. Simple jquery is acceptable if it is a better/quicker/easier solution.
Thanks
Code Example:
<input type="radio" id="customer" name="jobtype" value="customer" onclick="getJobType()" autofocus>Customer
<input type="radio" id="store" name="jobtype" value="store" onclick="getJobType()">Store
<span id="customerjobs" style="display:none">
<select id="customer" name="customer" onchange="createJobsList(this.value)">
*various options*
</select>
<span id="jobslist"><br></span>
</span>
The first span (id=customerjobs) is initially hidden. Upon selection from the radio's, all but the corresponding span is set to display:none and the selected is set to display:block. On submit, the selected radio is saved, but the onclick isn't called to show the span.
The second span (id=jobslist) content is populated by innerHTML using the results of an ajax call to PHP when a selection is made. On submit, the selected option is saved, but the onchange isn't called to fill the span.
So I need to trigger the onclick of a saved radio value to show my content and trigger the onchange of a saved select to populate additional content.
Note: I used onblur with javascript to set the focus initially so any action would trigger the content but it caused an unnecessary pause in filling the form that I didn't want.
Page loads with only a radio selection.
User clicks radio button.
Onclick function changes style of span id=customerjobs to display:block.
The select input inside the span is now visible. The user selects an option.
Onchange function makes an ajax call to request information from the server which is placed in span id=jobslist.
User submits form to same page.
Form saves entered values so they are still selected when page reloads.
Onclick and onchange functions are not triggered by PHP saved values so steps 3 and 5 never occur. Page is left with only the radio buttons unless it is clicked again.
Well, I have a jsfiddle to illustrate my problem using default selections because I cannot use PHP to save entered values.
Imagine the form has just been submitted and the values saved are the checked radio button(customer) and the selection from the drop down(1) which adds the word "customer".
Ideally, the entire form would still be visible (The selected radio, the selected option and the content added to the last span "customer").
Instead, only the selected radio is visible unless it is clicked again to unhide the select drop down. The drop down retains its' value as well, but the content in the last span will only appear onchange.
http://jsfiddle.net/L5H2u/31/
Try it out and advance thanks for any suggestions.
Can you hook a function to onload that checks the radio buttons and simulates the click by calling getJobtype()? That will get the initial case where the radio button is already the way the user wants it. Further clicks will work as you planned.
Edited to add: If I understand you right, all is well the first time the page is loaded because the user has to click something and that runs your getJobType() function. However, when the page is reloaded, the correct radio button is already checked, the user doesn't change anything, and your function doesn't run. If that's correct, running getJobType() from onload should fix it.
You may need something like <input type="hidden" id="firstrun" value="true"> The PHP would set that to false on subsequent loads of the page, and the onload function would only make things happen if "firstrun" was false. Edit: You don't need this because getJobType() has no default action; keep reading.
Edited still more: You have checked="checked' on the Customer radio button, so if the user is a customer, even the initial run doesn't reveal the hidden material.
Remove checked="checked" when the page is initially loaded so that on the initial presentation, neither button is checked.* Then add window.onload=getJobType; to the end of your JavaScript.
On the initial load, getJobType() will do nothing since it checks both buttons and has no default action. When a button is clicked, getJobType() will run and act based on the button that was clicked.
When the page is loaded a subsequent time, one of the buttons will be checked and when onload runs getJobType() it will perform the corresponding action.
The radio buttons, SELECT values, and any other form elements that are preserved and "reflected" by the server-side PHP will be correct when the form is loaded the second (and subsequent) times. Where you need an onload JavaScript function is when one of those values also changes something else, such as making a hidden DIV visible. If there are functions other than getJobType() that manipulate the DOM, it will likely be cleaner to write an init function that sets up the DOM based on the values of the form elements as preserved by the PHP process.
* I normally advocate having some button checked by default so that the user can always get back to the initial state. This case seems to be an exception.

onchange isn't working

I am learning JavaScript through the Head First series book by O'Reilly media, and I just reached a chapter where I have to use the onchange event.
I'm testing using Safari/OS X Lion, Firefox, Chrome, Opera, and IE/Windows, but got the same result.
Given this code:
<html>
<head>
<title>onChange Test</title>
<script type="text/javascript">
function itWorks(){
alert("it works!");
}
</script>
</head>
<body>
<form>
<input type="text" onchange="itWorks();" />
<input type="text" onchange="itWorks();" />
</form>
</body>
<html>
Is it correct to say that the onchange event works whenever we change from one field to another, whether it is activated only by clicking or by using the TAB key?
The onchange event fires when:
Focus leaves the field
if the value has changed since focus was gained
It doesn't matter how focus was lost, and focus doesn't need to move to another field (a link could be focused, or nothing in the document could be, etc).
"we change from one field to another, whether its by clicking or by
using the TAB key" -
Thats onblur.
the event you have coded fires whenever you change the value of the input, then leave the field. EG: Enter something into the field, then press the TAB key.
Your example code works as expected for me.
The behaviors you described is onfocus. onchange executes when the value of the input changes.
If you type something into the field, it should run.
"Just to clarify, the onchange event works whenever we change from one field to another, whether its by clicking or by using the TAB key, right?"
Yes - as long as the value has changed
I'm not sure what the question is tbh - your code works!
I tested it on jsfiddle.net - which is great for learing / testing javascript.
(you should close your html tag btw)...
This is what the HTML5 draft spec says:
The unfocusing steps are as follows:
If the element is an input element, and the change event applies
to the element, and the element does not have a defined activation
behavior, and the user has changed the element's value or its list of
selected files while the control was focused without committing that
change, then fire a simple event that bubbles named change at the
element.
Unfocus the element.
Fire a simple event named blur at the element.
Note that change can fire at other times too. The spec also says:
... any time the user commits a change to the element's value or list of
selected files, the user agent must queue a task to fire a simple
event that bubbles named change at the input element.
And goes on to provide a couple of examples of "committing a change"
An example of a user interface with a commit action would be a File
Upload control that consists of a single button that brings up a file
selection dialog: when the dialog is closed, if that the file
selection changed as a result, then the user has committed a new file
selection.
Another example of a user interface with a commit action would be a
Date control that allows both text-based user input and user selection
from a drop-down calendar: while text input might not have an explicit
commit step, selecting a date from the drop down calendar and then
dismissing the drop down would be a commit action.

How to hide an HTML input field with javascript

I need to hide a text input field with javascript. Changing its type attribute to hidden does not work in IE (security issue).
What would be the best way to do it?
Note: No jQuery or other lib can be assumed.
I assume you have to show and hide the text field dynamically based on changing conditions in the form, otherwise you'd just make it an <input type="hidden"... to begin with.
Keep your code that shows and hides the field as it is, but also catch the onsubmit event.
In the submit handler, get your text field via document.getElementById(...) (or by accessing document.forms[i]) and check to see whether or not it's hidden.
If it is hidden, create a new DOM node for an <input type="hidden" ...> field and add that node to the form, probably via myform.appendChild(...). You'll have to give it the name your server-side code expects. Copy the contents of the hidden text field into the newly created type=hidden field, then return from your submit handler, allowing the standard submit to continue.
You could also just un-hide the text field on submit, but you'd have to move it "off screen" also or the user would see it reappear during submit processing.
Try wrapping it in a div or span and then setting the display style to none when you want to hide it, and then to block (if you used a div) or inline (if you used a span) when you want to show it.
document.myform.myelement.style.display = 'none'
works as expected even in Internet Explorer.
The only way you can change it is before you append it to the DOM. You can make a new element and then replace the current one with it.
Look at replaceChild and createElement since you want to do manual DOM scripting. I assume you know what to do.
EDIT: "Hidden" fields as far as I know are sent. Have you checked whether they are? And you can also just do position:absolute; left:-9999em; to offset them.

Categories

Resources