JavaScript Form Validation: understanding function call - javascript

I am a total newbie to JavaScript, trying to find my way on form validation. I have been reading books as well as online tutorials and I found the following code online that is, in my opinion, very elegant and maintainable. Unfortunately, my skills in JavaScript are not good enough to understand everything. I am here to ask your help to understand the different functions defined.
I would like also to call the InstantValidation function on an event (onSubmit event) calling it in an independent .js file (based on event listener), so might you please also help me to call the function appropriately?
Here is the code:
<html>
<body>
<form id="myform" action="#" method="get">
<fieldset>
<legend><strong>Add your comment</strong></legend>
<p>
<label for="author">Name <abbr title="Required">*</abbr></label>
<input name="author" id="author" value=""
required="required" aria-required="true"
pattern="^([- \w\d\u00c0-\u024f]+)$"
title="Your name (no special characters, diacritics are okay)"
type="text" spellcheck="false" size="20" />
</p>
<p>
<label for="email">Email <abbr title="Required">*</abbr></label>
<input name="email" id="email" value=""
required="required" aria-required="true"
pattern="^(([-\w\d]+)(\.[-\w\d]+)*#([-\w\d]+)(\.[-\w\d]+)*(\.([a-zA-Z]{2,5}|[\d]{1,3})){1,2})$"
title="Your email address"
type="email" spellcheck="false" size="30" />
</p>
<p>
<label for="website">Website</label>
<input name="website" id="website" value=""
pattern="^(http[s]?:\/\/)?([-\w\d]+)(\.[-\w\d]+)*(\.([a-zA-Z]{2,5}|[\d]{1,3})){1,2}(\/([-~%\.\(\)\w\d]*\/*)*(#[-\w\d]+)?)?$"
title="Your website address"
type="url" spellcheck="false" size="30" />
</p>
<p>
<label for="text">Comment <abbr title="Required">*</abbr></label>
<textarea name="text" id="text"
required="required" aria-required="true"
title="Your comment"
spellcheck="true" cols="40" rows="10"></textarea>
</p>
</fieldset>
<fieldset>
<button name="preview" type="submit">Preview</button>
<button name="save" type="submit">Submit Comment</button>
</fieldset>
</form>
<script type="text/javascript">
(function()
{
//add event construct for modern browsers or IE
//which fires the callback with a pre-converted target reference
function addEvent(node, type, callback)
{
if(node.addEventListener)
{
node.addEventListener(type, function(e)
{
callback(e, e.target);
}, false);
}
else if(node.attachEvent)
{
node.attachEvent('on' + type, function(e)
{
callback(e, e.srcElement);
});
}
}
//identify whether a field should be validated
//ie. true if the field is neither readonly nor disabled,
//and has either "pattern", "required" or "aria-invalid"
function shouldBeValidated(field)
{
return (
!(field.getAttribute('readonly') || field.readonly)
&&
!(field.getAttribute('disabled') || field.disabled)
&&
(
field.getAttribute('pattern')
||
field.getAttribute('required')
)
);
}
//field testing and validation function
function instantValidation(field)
{
//if the field should be validated
if(shouldBeValidated(field))
{
//the field is invalid if:
//it's required but the value is empty
//it has a pattern but the (non-empty) value doesn't pass
var invalid =
(
(field.getAttribute('required') && !field.value)
||
(
field.getAttribute('pattern')
&&
field.value
&&
!new RegExp(field.getAttribute('pattern')).test(field.value)
)
);
//add or remove the attribute is indicated by
//the invalid flag and the current attribute state
if(!invalid && field.getAttribute('aria-invalid'))
{
field.removeAttribute('aria-invalid');
}
else if(invalid && !field.getAttribute('aria-invalid'))
{
field.setAttribute('aria-invalid', 'true');
}
}
}
//now bind a delegated change event
//== THIS FAILS IN INTERNET EXPLORER <= 8 ==//
//addEvent(document, 'change', function(e, target)
//{
// instantValidation(target);
//});
//now bind a change event to each applicable for field
var fields = [
document.getElementsByTagName('input'),
document.getElementsByTagName('textarea')
];
for(var a = fields.length, i = 0; i < a; i ++)
{
for(var b = fields[i].length, j = 0; j < b; j ++)
{
addEvent(fields[i][j], 'change', function(e, target)
{
instantValidation(target);
});
}
}
})();
</script>
</body>
</html>
In particular, the following code is not toally clear to me:
function addEvent(node, type, callback)
{
if(node.addEventListener)
{
node.addEventListener(type, function(e)
{
callback(e, e.target);
}, false);
}
else if(node.attachEvent)
{
node.attachEvent('on' + type, function(e)
{
callback(e, e.srcElement);
});
}
}
Any help (even a very brief explanation) would be highly appreciated !

#1 That's an event handler abstraction layer.
That one code section acts as an event handler, but works across various different browsers.
Most browsers use the addEventListener way of adding an event handler.
Some Internet Explorer versions use attachEvent: http://msdn.microsoft.com/en-us/library/ie/ms536343(v=vs.85).aspx
The function allows both ways to be used.
It has you pass in...
... the element you want to add an event to (node)
... what type of event you want to handle (type)
... what code you want executed by an event (callback)
Browser events: http://eloquentjavascript.net/chapter13.html
Abstraction layers: http://en.wikipedia.org/wiki/Abstraction_layer
Browser events are things like a page fulling loading (onload), something being clicked (onclick), an input being changed (onchange), a cursor going over an element (onmouseover), etc...
http://www.w3schools.com/js/js_htmldom_events.asp
#2 How to go about invoking validation onSubmit...
//now bind a change event to each applicable for field
The code below that goes through each input and textarea element and adds validation to each one with the onchange event. But what you want to do is validate onsubmit, which requires something like this, below the other addEvent call:
addEvent("myform","onsubmit", function(){
//de Go field by field and validate.
//de If all the fields pass, return true.
//de If one or more fields fail, return false.
})
If you want, you can even remove the onChange events. That is your choice. The main thing here is that you need to make sure to only validate the fields inside the form itself, which you can look at this answer for more information about: Best Practice: Access form elements by HTML id or name attribute? ... loop through all the elements, and validate each one within the addEvent I mentioned above which must return true or false to either allow the form to be submitted, or stop the submission and show that there were validation errors.
Please remember! As a personal bit of advice... On the server-side you still want to do validation, even if you have client-side validation. Browsers are easy to manipulate, so you might still have bad data sent to the server. Always, always do server-side validation regardless of client-side.

It just looks like a cross-browser function that attaches a handler (instantValidation) to the "change" or "onchange" events of all input and textarea controls.
I say cross-browser because of the presence of two separate event subscription methods. attachEvent is for older IE browsers (5-8) and addEventListener is generally for all modern browsers.
This addEvent function checks for the presence of said functions and uses whatever is available, giving preference to the "modern" way.

This is cross-browser code for attaching event handlers to the events raised by a DOM element. The function (addEvent) has arguments as follows:
node: the DOM node object to which an event will be attached (retrievable via a function like getElementById)
type: The event name, such as change, focus etc.
callback: The function to call when the event is raised.
This line: if(node.addEventListener) checks whether the node has a property called addEventListener. If the property is there, it behaves the same as true and the if block is entered.
The check for addEventListener is done because different browsers implement this event attachment function differently. Namely, IE versions before IE9 use only attachEvent.

Related

Cross browser code to restrict user input using Javascript

I found this code through Stack Overflow to restrict users from putting numbers in a textbox, however it only works in Chrome and IE. Anyone know of any cross browser code to do this?
Note: we've already added the global attribute and it didn't work at all, this was the only one that fully worked in Chrome and IE.
<input type="text" onkeyup="this.value = this.value.replace(/[^a-z]/, '')" />
You want to catch onkeydown that is when the character gets inserted, not on onkeyup. You should also instead of removing the number, just prevent it from getting inserted with event.preventDefault()
<p>
<input type="text" onkeydown="event.key.match(/\d/) && event.preventDefault()" />
</p>
One thing I would recommend is removing the code from the html and putting it in a function so it is reusable like this:
// Wait till the dom is loaded
document.addEventListener('DOMContentLoaded', function(e) {
// Add the event to each input that has `data-type="number"`
document.querySelectorAll('[data-type=number]').forEach(function(input) {
// Add the event to the input
input.addEventListener('keydown', number)
})
})
function number(event) {
event.key.match(/\d/) && event.preventDefault()
}
<p>
<input type="text" data-type="number" />
</p>

setCustomValidity Bootstrap keep error popup

I've implement localization in my application, all this stuff is saved inside a php file. So I can easy do this:
<input class="form-control" type="text" required="" placeholder="username" oninvalid="this.setCustomValidity('<?php echo $this->lang->line('field_required'); ?>')"></input>
Now if I doesn't enter any text I can see the custom message, but if I fill the input I see again the popup as the form can't get the text inside.
It's a bug of Bootstrap?
EXAMPLE
https://jsfiddle.net/DTcHh/23662/
Using the onvalid won't work in some browsers like Safari or IE below 10. Use a custom event notifier for attaching the function.
Note: As you mentioned in the comment you can print the message from the data-invalid-message attribute from php and catch it using jQuery by .data('invalidMessage').
SEE WORKING EXAMPLE:
var myobj = jQuery('input.form-control');
myobj.on('keyup keypress blur change input', function() {
var messg = ($(this).data('invalidMessage'));
if (this.validity.typeMismatch) {
this.setCustomValidity(messg);
} else {
this.setCustomValidity('');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<form>
<input class="form-control" type="email" required placeholder="username" data-invalid-message="custom message from php here">
<button type="submit">
go
</button>
</form>
a workaround that I've found is:
onkeyup="this.setCustomValidity('');
the bug will be gone now.
TL&DR
Check element.validity.typeMismatch and then element.setCustomValidity('custom error msg') or element.setCustomValidity('') if there's no mismatch. You should listen on both keyup and blur events.
Explanation in Mozilla Developer documentation about setCustomValidity: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Forms/Data_form_validation#Customized_error_messages.
But just keyup won't work properly if focus is not inside the input box we're modyfing.
Our previous example won't transfer the current state of the input box
if the user mouses away and clicks elsewhere on the page. We update
the component's values property only when the user presses Enter while
the focus is inside the input box.
Let's fix that by listening to the input box's blur event as well.
Above is from Angular 2 docs: User Input, paragraph "On blur" https://angular.io/docs/ts/latest/guide/user-input.html.
Simplified example
Below is example from Mozilla documentation with added blur keyEvent listener. Yup, refactoring needed, but mine version in Angular 2 looks vastly different and so probably will yours.
<form>
<label for="mail">I would like you to provide me an e-mail</label>
<input type="email" id="mail" name="mail">
<button>Submit</button>
</form>
And then
var email = document.getElementById("mail");
email.addEventListener("keyup", function (event) {
if (email.validity.typeMismatch) {
email.setCustomValidity("I expect an e-mail, darling!");
} else {
email.setCustomValidity("");
}
});
email.addEventListener("blur", function (event) {
if (email.validity.typeMismatch) {
email.setCustomValidity("I expect an e-mail, darling!");
} else {
email.setCustomValidity("");
}
});

Check validity of as required marked fields in javascript

I do not want to perform a submit action when pressing the "submit" button on my form but rather perform some data manipulation and then submit the form using javascript form.submit - as such I do not use the <input type="submit"> element in my form:
<form action="process.php" method="post" name="myForm">
<input type="text" name="entry" id="entry" required />
<input type="button" value="Submit" onclick="manipulate_and_submit(this.form, this.form.entry);" />
</form>
With the script being something like:
function manipulate_and_submit(form, entry) {
var val = entry.value;
var hidden = document.createElement("input");
form.appendChild(hidden);
hidden.type = "hidden";
hidden.name = "m";
hidden.value = generate_other_value(val);
entry.value = "";
form.submit();
}
But before submitting I want to validate the entry and other elements of the form - I can do that manually ofc. but HTML5 gives us the required and so many other attributes - how can I simply integrate them? Is there something like form.isValid() ? Googling "validate javascript html form" just gives me examples that deal with the manual validation in javascript from "ye olde times" ...
You can use checkValidity, which is a method provided by HTMLFormElement. In your example, it would be something like if ( !form.checkValidity() ) { code here }. From MDN:
[checkValidity] Returns true if all controls that are subject to constraint validation satisfy their constraints, or false if some controls do not satisfy their constraints. Fires an event named invalid at any control that does not satisfy its constraints; such controls are considered invalid if the event is not canceled.
Source
As that says, it also fires an invalid event at every invalid form item. Then you can just make your own handler to show invalidity, like something described in this answer.

Incorrect Javascript Functions?

I am completely brand new to Javascript. In fact, I'm just an Objective-C programmer looking to implement just a little Javascript into one of my apps. So, the problem is for whatever reason when I call my first function, nothing happens there I don't get the alert. When I call my second function I only get the alert, the button isn't actually clicked.
Code:
function myFunction(username, password) {
alert("Data will be entered");
document.getElementById('ctl00_plnMain_txtLogin').value = username;
document.getElementById('ctl00_plnMain_txtPassword').value = password;
}
function click() {
alert("The button was clicked");
document.getElementById("ctl00_plnMain_Submit1").click();
}
I can seem to run just a regular alert fine, but nothing else??? Is there something wrong in my function?
If it helps, on the website here is the "username" box:
<input name="ctl00$plnMain$txtLogin" type="text" maxlength="50" id="ctl00_plnMain_txtLogin" tabindex="1">
"password" box:
<input name="ctl00$plnMain$txtPassword" type="password" maxlength="255" id="ctl00_plnMain_txtPassword" tabindex="2">
the button:
<input onclick="if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate(''); " name="ctl00$plnMain$Submit1" type="submit" id="ctl00_plnMain_Submit1" tabindex="3" value="Log In" title="Log in">
-- EDIT
Also, I am starting the functions through my objective C code. I grab a js file, then I am able to use its functions on a webpage.
I would recommend using a DOM abstraction library like jQuery
jQuery provides an 'on' method, it's used to bind events to DOM elements:
$('#ctl00_plnMain_Submit1').on('click', function (event) {
alert("The button was clicked");
}
It also provides a nice abstraction for collecting input values:
var userName = $('#ctl00_plnMain_txtLogin').val();
You can also use it to set the value of an input:
$('#ctl00_plnMain_txtLogin').val('New Value for This Input');
Populating inputs with a function:
function populateInputs (username, password) {
$('#ctl00_plnMain_txtLogin').val(username);
$('#ctl00_plnMain_txtPassword').val(password);
}
I am guessing you want the click function to be called when the button is clicked
You need to specify that then
<input onclick="click()" ....

Why is my HTML form being submitted?

I have this form with 1 field. I want that when the user clicks or hits enter it should call a JavaScript function that will do validation and either display an error message or submit the form.
However, when hitting enter it submits the form regardless. (So far in my JavaScript validation function I only have alert ("Hello World"))
<form action="add-another-number-to-dnc.cshtml" method="post" id="addDNCform">
<h4>Enter 10-digit phone number without dashes, dots or parenthesis</h4>
<input type="text" name="pn" required placeholder="phone number"
title="Phone Number to Add to Do-Not-Call List"
onkeypress="if (event.keyCode == 13) document.getElementById('btnVldt').click()"/> <!-- all this is to treat [Enter] as a click -->
<input id="btnVldt" type="button" value="Add Number to Do Not Call list" onclick="submitDNC()"/>
</form>
I added all the page code in jsFiddle where you can test and verify that:
when clicking on the button, it correctly doesn't submit the form
when hitting enter it gives you an Error 404 which must mean, it's trying to load the page.
Added this:
Actually, if I use submit instead of button, it doesn't work also when clicking. However, in jsFiddle it seems to work.
Expanding on Praveen's answer here, I'm going to write the JavaScript "unobtrusively" to further separate function, presentation, and content:
HTML
<form action="add-another-number-to-dnc.cshtml" method="post" id="addDNCform">
<h4>Enter 10-digit phone number without dashes, dots or parenthesis</h4>
<input type="text" name="pn" required placeholder="phone number" title="Phone Number to Add to Do-Not-Call List" />
<button type='submit'>Add Number to Do Not Call list"</button>
</form>
(X)HTML5
Assuming that you want a 10-digit number in the box (numeric characters only), we can also use the pattern attribute on the <input> element in HTML5 as a form of validation for newer browsers (Firefox, Chrome, IE10, Opera):
<form action="add-another-number-to-dnc.cshtml" method="post" id="addDNCform">
<h4>Enter 10-digit phone number without dashes, dots or parenthesis</h4>
<input type="text" name="pn" required placeholder="phone number" title="Phone Number to Add to Do-Not-Call List" pattern="[0-9]{10}" />
<button type='submit'>Add Number to Do Not Call list"</button>
</form>
JavaScript (place inside <script> tags somewhere on the page)
function submitDNC(event) {
var valid = false;
alert('Hello world');
// your validation logic goes here, sets valid to TRUE if it's valid
if(!valid) {
event.preventDefault();
}
}
document.getElementById('addDNCform').addEventListener( 'submit', submitDNC, false );
No need to do any synthetic button clicking if all you're trying to do is validate upon form submission. Pretty soon with HTML5 we might not even need JavaScript for this, depending on what your validation logic is.
In your submitDNC() function, give a return false;.
function submitDNC()
{
alert("Hello World!");
return false;
}
Another thing is, change your input type from button to submit. Use:
<input id="btnVldt" type="submit"
value="Add Number to Do Not Call list" onclick="return submitDNC();" />
Explanation
The return value of an event handler determines whether or not the default browser behaviour should take place as well. In the case of clicking on links, this would be following the link, but the difference is most noticeable in form submit handlers, where you can cancel a form submission if the user has made a mistake entering the information.
Another Option
As Rink says, return false; is overkill for something that can and should be handled by preventDefault(). So, you can do this way, by using unobtrusive JavaScript.
function submitDNC()
{
alert("Hello World!");
var e = window.event;
e.preventDefault();
}
To prevent submit when pressing ENTER, use this piece of code:
function checkEnter(e){
e = e || event;
var txtArea = /textarea/i.test((e.target || e.srcElement).tagName);
return txtArea || (e.keyCode || e.which || e.charCode || 0) !== 13;
}
then, add the handler to the form:
document.querySelector('form').onkeypress = checkEnter;
I would change the to a Submit, although this isn't what's getting you in trouble here. For some odd reason browser programmers thought it was a good idea to code so that browsers assume buttons within forms submit them. You'll want to change onkeypress to call a function. In that function do something like this:
function keyPressPhone() {
if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
document.getElementById("addDNCform").submit();
return true;
}
else {
return false; // somehow prevents the form from being submitted
}
}

Categories

Resources