This is my first real-world JavaScript project. Please be kind...
I'm creating a form with required fields. With JavaScript, I am collecting the required fields as objects in an Array, each object having the properties "object" (the HTML objects themselves, from which I can get object.id and object.value) "description" (to display to users) and "error" (the HTML objects beneath each input field where corresponding validation errors appear).
Then I have a function (to be used onBlur, for instant feedback) that checks to see if the value of the field is null, and if so, it displays the validation error beneath the corresponding field.
I'm trying to set the onblur attribute for each input field using a FOR loop that runs through the array of required fields. I have a setAttribute statement that works perfectly if I create an individual statement for each object in the Array, individually. But as soon as I change it to a FOR loop, the onblur event for ANY field pops up the validation error for the FIRST input field, only. This has got to be a freshman mistake, but I've searched high and low and rewritten this thing ten different ways and can't make it work with a loop...
I put my code in a Fiddle so you can see it -- but it doesn't actually work in the fiddle, only in my local dev environment (maybe that indicates another problem?). Here's the code:
//create array with constructor to identify all required fields
var allRequired = [];
function RequiredField(theID, theDescription) {
this.object = document.getElementById(theID);
this.description = theDescription;
this.error = document.getElementById("error-" + theID);
allRequired.push(this);
}
var fieldFname = new RequiredField("fname", "First Name");
var fieldLname = new RequiredField("lname", "Last Name");
var fieldEmail = new RequiredField("email", "Email");
var fieldPhone = new RequiredField("phone", "Phone");
var fieldRole = new RequiredField("role", "Desired Role");
var fieldPortfolio = new RequiredField("portfolio", "Portfolio/Website URL");
function requireField(theDescription, theValue, theError) {
if (theValue === "") {
theError.innerHTML = "<p>" + theDescription + " is required.</p>";
} else {
theError.innerHTML = "";
}
} //end function
for (i = 0; i < allRequired.length; i++) {
allRequired[i].object.setAttribute("onBlur", "requireField(allRequired[i].description, allRequired[i].object.value, allRequired[i].error);");
}
/* THIS WORKS IN MY LOCAL DEV ENVIRONMENT...
allRequired[0].object.setAttribute("onBlur", "requireField(allRequired[0].description, allRequired[0].object.value, allRequired[0].error);");
allRequired[1].object.setAttribute("onBlur", "requireField(allRequired[1].description, allRequired[1].object.value, allRequired[1].error);");
allRequired[2].object.setAttribute("onBlur", "requireField(allRequired[2].description, allRequired[2].object.value, allRequired[2].error);");
allRequired[3].object.setAttribute("onBlur", "requireField(allRequired[3].description, allRequired[3].object.value, allRequired[3].error);");
allRequired[4].object.setAttribute("onBlur", "requireField(allRequired[4].description, allRequired[4].object.value, allRequired[4].error);");
allRequired[5].object.setAttribute("onBlur", "requireField(allRequired[5].description, allRequired[5].object.value, allRequired[5].error);");
*/
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form name="form-careers" id="form-careers" action="form-process.php" enctype="multipart/form-data" onsubmit="return validateForm()" method="post">
<div class="form_labels">
<p>
<label for="fname">First Name:</label>
</p>
</div>
<div class="form_inputs">
<p>
<input type="text" name="fname" id="fname" required />
</p>
<div class="error" id="error-fname"></div>
</div>
<div class="form_labels">
<p>
<label for="lname">Last Name:</label>
</p>
</div>
<div class="form_inputs">
<p>
<input type="text" name="lname" id="lname" required />
</p>
<div class="error" id="error-lname"></div>
</div>
<div class="form_labels">
<p>
<label for="email">Email:</label>
</p>
</div>
<div class="form_inputs">
<p>
<input type="email" name="email" id="email" required />
</p>
<div class="error" id="error-email"></div>
</div>
<div class="form_labels">
<p>
<label for="phone">Phone:</label>
</p>
</div>
<div class="form_inputs">
<p>
<input type="tel" name="phone" id="phone" placeholder="###-###-####" pattern="\d{3}[\-]\d{3}[\-]\d{4}" required />
</p>
<div class="error" id="error-phone"></div>
</div>
<div class="form_labels">
<p>
<label for="role">Desired Role:</label>
</p>
</div>
<div class="form_inputs">
<p>
<input type="text" name="role" id="role" required />
</p>
<div class="error" id="error-role"></div>
</div>
<div class="form_labels">
<p>
<label for="portfolio">Portfolio/Website:</label>
</p>
</div>
<div class="form_inputs">
<p>
<input type="url" name="portfolio" id="portfolio" placeholder="http://" pattern="[a-z0-9.-]+\.[a-z]{2,63}$" required />
</p>
<div class="error" id="error-portfolio"></div>
</div>
<div class="clearboth"></div>
<input type="hidden" name="formtype" id="formtype" value="careers">
<div class="form_labels">
<p> </p>
</div>
<div class="form_inputs">
<a href="#">
<input type="submit" value="Submit" class="btn-red">
</a>
</div>
</form>
If someone would help point me in the right direction I would really appreciate it.
Code
for (i = 0; i < allRequired.length; i++) {
allRequired[i].object.setAttribute("onBlur", "requireField(allRequired[i].description, allRequired[i].object.value, allRequired[i].error);");
}
sets onblur event with value like requireField(allRequired[i].description.
So - what is it - i? No one knows.
Proper code is:
for (i = 0; i < allRequired.length; i++) {
allRequired[i].object.setAttribute("onBlur", "requireField(allRequired[" +i + "].description, allRequired[" + i + "].object.value, allRequired[" + i + "].error);");
}
See? I get real i value for each iteration.
As u_mulder said concat problem.
As for code I suggest to look up factory functions. It's more natural javascript then constructor.
Related
Hello So I want to fill the form this is the html of the website
<div class="vx_form-control" data-label-content="Address line 1">
<div class="vx_form-control">
<input type="text" aria-describedby="country_code_prefix AccountData_addressSuggest_helptext" aria-invalid="true" aria-autocomplete="none" aria-controls="suggestions" aria-activedescendant="0_suggestion" value="" autocomplete="off" name="/AccountData/address/address1" id="AccountData_addressSuggest" style="padding-left: 15px;">
</div>
</div>
I've tried with this one to run on console Chrome
var xxx = document.querySelectorAll('.vx_form-control input[name="/AccountData/address/address1"]')
document.execCommand('insertText', false, 'My address');
But it doesn't work. Am I wrong on select the specific name?
Below snippet shows selector working.
Is there a reason you need to use execCommand? It's considered depricated these days and a bit more complex.
let cool_input = document.querySelector('.vx_form-control > [name="/AccountData/address/address1"]');
cool_input.value = "some address";
<div class="vx_form-control" data-label-content="Address line 1">
<div class="vx_form-control">
<input type="text" aria-describedby="country_code_prefix AccountData_addressSuggest_helptext" aria-invalid="true" aria-autocomplete="none" aria-controls="suggestions" aria-activedescendant="0_suggestion" value="" autocomplete="off" name="/AccountData/address/address1" id="AccountData_addressSuggest" style="padding-left: 15px;">
</div>
</div>
I created an array of all the input elements in a form, then looped through the array and tried to access the DOM element object through the array. But it gives the error "Cannot read property 'addEventListener' of null"
window.addEventListener("DOMContentLoaded", function() {
var paraC = document.querySelectorAll('.form-container p input');
for (var i = 0; i < paraC.length; i++) {
var inputField = document.getElementById(paraC[i].getAttribute('id'));
console.log(inputField); // gives null
inputField.addEventListener('onfocus', helperNote, false);
}
function helperNote() {
var notePlace = document.querySelector('.form-container');
var note = document.createElement('p')
notePlace.appendChild(note);
console.log('event fired');
}
}, false);
The HTML Code
<section>
<h3>Sign-Up Form</h3>
<form method="post">
<div class="form-container">
<p>Fill The Form Below</p>
<p>
<label>Email :</label>
<input type="email" name="email" id="email">
</p>
<p>
<label>Name :</label>
<input type="text" name="Name" id="Name">
</p>
<p>
<label>Age :</label>
<input type="number" name="age" id="age">
</p>
<p>
<input type="submit" name="submit" value="sign-up">
</p>
</div>
</form>
</section>
It would be simpler to just use forEach:
document.querySelectorAll('.form-container p input')
.forEach(function(inputField) {
inputField.addEventListener('onfocus', helperNote, false);
})
Use document.querySelectorAll('.form-container p input:not([type="submit"])') to prevent selecting the submit button (it fails as it does not have the id attribute).
Also write focus instead of onfocus
Using forEach()
forEach() executes the provided callback once for each element present in the array in ascending order. It is not invoked for index properties that have been deleted or are uninitialized (i.e. on sparse arrays).
Other than the use of forEach(), I have included another important fix;
When using addEventListener() to listen for element focus we state the event type as "focus" not "onfocus".
If you don't want a helper note to be shown when the <input type="submit"> button gets focus, we can filter it out using the :not() pseudo-class in our querySelectorAll().
You may want to include some handling to avoid helper notes multiplying in your form; currently, every time one is added, any that were already there remain; it could get quite crowded!
window.addEventListener("DOMContentLoaded", function() {
document.querySelectorAll('.form-container input:not([type=submit])')
.forEach( function( inputField ) {
console.log(inputField);
inputField.addEventListener('focus', helperNote, false);
} );
function helperNote() {
var notePlace = document.querySelector('.form-container');
var note = document.createElement('p');
note.textContent = "Helper Note";
notePlace.appendChild(note);
console.log('event fired');
}
}, false);
<section>
<h3>Sign-Up Form</h3>
<form method="post">
<div class="form-container">
<p>Fill The Form Below</p>
<p>
<label>Email :</label>
<input type="email" name="email" id="email">
</p>
<p>
<label>Name :</label>
<input type="text" name="Name" id="Name">
</p>
<p>
<label>Age :</label>
<input type="number" name="age" id="age">
</p>
<p>
<input type="submit" name="submit" value="sign-up">
</p>
</div>
</form>
</section>
Some pointers regarding your code
// the p is unnecessary
var paraC = document.querySelectorAll( '.form-container p input' );
// for elem at index until length
for (var i = 0; i < paraC.length; i++) {
// the iterated array-like node list already contains references to the elements
// paraC[i] is a reference to one of the elements
// paraC[i].getAttribute('id') could be shortened to paraC[i].id
// getting the id of the element in order to get the element is unnecessary.
var inputField = document.getElementById(paraC[i].getAttribute('id'));
// the submit input has no id but will be the last referenced input
// the paraC[i].getAttribute('id') will return undefined
// document.getElementById(undefined) is clearly not going to work well
console.log(inputField); // gives null
}
first use document.addEventListener instead window.addEventListener the event DOMContentLoaded is applicable to document, after use class in your input, and do a Var to getid of input, your code should be like this :
document.addEventListener("DOMContentLoaded", function() {
var paraC = document.querySelectorAll('.yourclass');
for (var i = 0; i < paraC.length; i++) {
var inputField = paraC[i],
inputFieldId = inputField.getAttribute('id');
console.log(inputFieldId);
inputField.addEventListener('focus', helperNote, false);
}
function helperNote() {
var notePlace = document.querySelector('.form-container');
var note = document.createElement('p')
notePlace.appendChild(note);
console.log('event fired');
}
}, false);
<section>
<h3>Sign-Up Form</h3>
<form method="post">
<div class="form-container">
<p>Fill The Form Below</p>
<p>
<label>Email :</label>
<input class="yourclass" type="email" name="email" id="email">
</p>
<p>
<label>Name :</label>
<input class="yourclass" type="text" name="Name" id="Name">
</p>
<p>
<label>Age :</label>
<input class="yourclass" type="number" name="age" id="age">
</p>
<p>
<input type="submit" name="submit" value="sign-up">
</p>
</div>
</form>
</section>
I have set of input boxes to add names and designaions.and iwant to print those in a <p> tag when user click print button. how to proceed.
<div class="form-group">
<label for="inputRegNo" >Name & Designation<span style="color:#c0392b;padding-left:5px;">*</span></label>
<div class="form-group">
<input required type="text" name="fname[]" class="fname" onkeyUp="document.getElementById('refa5').innerHTML = this.value" placeholder="Name" />
<input required type="text" name="lname[]" placeholder="Designation" />
</div>
</div>
<div class="form-group">
<label for="inputRegNo" ></label>
<div class="form-group">
<input type="text" name="fname[]" placeholder="Name" class="fname" onkeyUp="document.getElementById('refa5').innerHTML = this.value" />
<input type="text" name="lname[]" placeholder="Designation" />
</div>
</div>
print
<div>
<label>Name & Designation</label>
<p id="refa5"> - </p>
</div>
its looks you are new in javascript.. it's simple give the name to all the input field like
<input type="text/checkbox" name="txtName">
and in javascript you can access this field value by
<script type="text/javascript">
var name = document.getElementsByName("txtName");
</script>
if you wish to print the element on button click simply specify their click event on javascript like
function onClick() {
alert("helo from click function");
}
and then on button ..
<input type="button" onclick="onClick()">
w3schools is a great resource for this. Here is some example code on how to do this :
<button onclick="myFunction()">Click me</button>
<input id="inputID"></input>
<p id="demo"></p>
<script>
function myFunction() {
var inputID = document.getElementById("inputID").value;
document.getElementById("demo").innerHTML = inputID;
}
</script>
What the code above does is it takes the value of an input, then it sets the innerHTML of a <p> element to it. You can obviously do this with other things like <h1> elements as well.
I have an HTML form with 4 inputs fields inside it. All these input fields have the same class and ID, the only differences are the "divs" surounding the inputs.
One form is in the header the other one in the content, and inside each of them, one field is a username field to login, and the other one to register.
<div class=theheader>
<h1> The Header</h1>
<div class="fullform">
<div class="container register">
<div class="form_group required">
<input class="input_text" id="username_field" name="username" size="30" value="" type="text">
</div>
</div>
<div class="container login">
<div class="form_group">
<input class="input_text" id="username_field" name="username" size="30" type="text" >
</div>
</div>
</div>
</div>
<div class=thecontent>
<h1> Form Content</h1>
<div class="fullform">
<div class="container register">
<div class="form_group required">
<input class="input_text" id="username_field" name="username" size="30" value="" type="text">
</div>
</div>
<div class="container login">
<div class="form_group">
<input class="input_text" id="username_field" name="username" size="30" type="text" >
</div>
</div>
</div>
</div>
Here is an example of what it looks like : http://jsfiddle.net/M6R7K/78/.
I need to add a placeholder inside each of these fields, but the tricky thing is, I don't have any direct access to this HTML code, because this one is automatically generated by a third party plugin. So I can only add javascript or css, using the existing classes and ids.
So I used the javascript :
document.getElementById("username_field").setAttribute("placeholder", "Username");
And it has indeed add the correct placeholder in the correct field. The problem is, it only add the placeholder in the 1st field found, not all of them. Even if I add several lines of javascript.
So the question : How to fill up all these field with a placeholder without touching the HTML code ? (With javascript or anything else) And at the best possible, having a different placeholder for each field ? (One needs to be "username and email", and the other one "username" only). We should be able to use the classes of the div's, just like we can do in CSS. But I wasn't able to figure it out.
Thanks !
Your code set placeholder one of them. Standard don't define which of them will get the placeholder because standard forces you tou use ID only once per page. You need to set placeholders for all elements with input_text class. You can do it by array with placeholders and iterating fields: In each iteration set i-th placeholder from array by this code
var placeholders = ["Username", "Email", "Phone", "Credit card"]
var elements = document.getElementsByClassName("input_text");
for (var i = 0; i < elements.length; i++) {
elements[i].setAttribute("placeholder", placeholders[i]);
}
Example: http://jsfiddle.net/M6R7K/81/
The best practice is set placeholders normally in HTML.
First of all you cannot use the same id for more then one element.
Second: try to use as input name attribute meaningful values. If you cannot touch the HTML you can always use the index parameter inside the forEach loop, this could be an idea. Another idea could be to look for the root element in order to distinguish the input fields.
I tried to do for you, right to give you an idea on how to solve your problem:
window.onload = function() {
Array.prototype.slice.call(document.getElementsByClassName("input_text")).forEach(function(currentValue, index) {
currentValue.setAttribute("placeholder", currentValue.getAttribute('name'));
});
}
<div class=theheader>
<h1> The Header</h1>
<div class="fullform">
<div class="container register">
<div class="form_group required">
<input class="input_text" id="username_field1" name="username" size="30" value="" type="text">
</div>
</div>
<div class="container login">
<div class="form_group">
<input class="input_text" id="username_field2" name="password" size="30" type="text" >
</div>
</div>
</div>
</div>
<div class=thecontent>
<h1> Form Content</h1>
<div class="fullform">
<div class="container register">
<div class="form_group required">
<input class="input_text" id="username_field3" name="email" size="30" value="" type="text">
</div>
</div>
<div class="container login">
<div class="form_group">
<input class="input_text" id="username_field4" name="other" size="30" type="text" >
</div>
</div>
</div>
</div>
I have been able to find the solution, using the "attr" function, and the Jquery framework.
This is the function that I applied to each of the inputs, in order to create a unique placeholder (example for the 1st field) :
$(".theheader .register input").attr('placeholder', 'Username Header')
This code allows to retrieve the DIV CLASS of each input field, and apply a customized field.
So for my example, it would be this :
$(".theheader .register input").attr('placeholder', 'Username Header')
$(".theheader .login input").attr('placeholder', 'Username or Email Header');
$(".thecontent .register input").attr('placeholder', 'Username Content');
$(".thecontent .login input").attr('placeholder', 'Username or Email Content');
And each field has his customized placeholder !
Here is the result : https://jsfiddle.net/3ddo465n/9/
Thank you all for the contribution !
trying to achieve to get the position of the error tag in DOM. based on the position I need to set the attributes to my code. How to get the generic way of finding the position of the p.error.
Here it is what tried:
Scenario 1:
<div class="col-xs-6">
<label> email </label>
<p class="error">Please enter E-mail</p>
<input type="email" value="">
</div>
<div class="col-xs-6">
<label> password </label>
<p class="error">Please enter password</p>
<input type="password" value="">
</div>
Scenario 2:
<div class="col-xs-6">
<label> email </label>
<input type="email" value="">
<p class="error">Please enter E-mail</p>
</div>
<div class="col-xs-6">
<label> password </label>
<input type="password" value="">
<p class="error">Please enter password</p>
</div>
In the scenario 1, the position of the p.error is on the top of the input. and in the scenario 2 it is below to the input field.
Now what is the generic way to find the position, whether it is below or above.
previous = $("p.error").prev();
next = $("p.error").next();
previous.on('focusin', function(ev) { });
previous.on('keydown',function(ev) {
$(this).prev().attr({
'role': 'xyz',
});
});
next.on('focusin', function(ev) {
$(this).prev().attr({
'role': 'xyz',
});
});
You can check the tagName property of previous and next by doing
previous[0].tagName.toLowerCase() === 'input'; // error is after
next[0].tagName.toLowerCase() === 'input'; // error is before
Another solution would be to use the input tag as selector in the next() method, like this:
$('p.error').next('input').length > 0; // error is before
$('p.error').prev('input').length > 0; // error is after