not able to access DOM object property - javascript

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>

Related

Disable and enable button in js

i want to make a form with inputs and "submit" button. Idea is to disable button as long as inputs are empty or value of input not correctly (email validation).
I have my js code, but the problem is that, button starts at the beggining as disabled, but when i write something in first input it start to be not disabled, even if rest of inputs have not correct value.
My function:
document.getElementById("my-button").disabled = true
function inputValidator() {
var $element = $(this);
// for all input fields
if ($element.val()) {
$element.closest('.my-form__item').removeClass('error');
document.getElementById("my-button").disabled = false;
} else {
$element.closest('.my-form__item').addClass('error');
document.getElementById("my-button").disabled = true;
}
// for email field
if ($element.attr('id') === 'email' && $element.val()) {
if (!reg.test($element.val())) {
$element.closest('.my-form__item').addClass('error');
document.getElementById("my-button").disabled = true;
} else {
$element.closest('.my-form__item').removeClass('error');
document.getElementById("my-button").disabled = false;
}
}
Does anyone knows how to solve it?
Iterate over each element inside the form and check if one elements value length is zero. Note: Also the submit button needs a value in this implementation. A more native way would be to simply add the required tag to each input which also gives a good user experience.
JS approach
function validateForm() {
let inputs = document.forms["example"].elements;
let status = true;
[...inputs].forEach((input) => {
if(input.value.length == 0) status = false;
});
document.getElementById('submit').disabled = !status;
}
<form id="example">
<p>
<label>First name</label><br>
<input type="text" name="first_name" onKeyup="validateForm()">
</p>
<p>
<label>Last name</label><br>
<input type="text" name="last_name" onKeyup="validateForm()">
</p>
<p>
<label>Email</label><br>
<input type="email" name="email" onKeyup="validateForm()">
</p>
<p>
<button disabled=true id="submit" value="submit">Submit</button>
</p>
</form>
Pure HTML Approach
<form id="example">
<p>
<label>First name</label><br>
<input type="text" name="first_name" required>
</p>
<p>
<label>Last name</label><br>
<input type="text" name="last_name" required>
</p>
<p>
<label>Email</label><br>
<input type="email" name="email" required>
</p>
<p>
<input type="submit" value="Submit">
</p>
</form>

Prevent input to get cleared when the parend is modified

Can I have some inputs on this ?
Issue
When a form or a parent element of a form is modified, the text that was typed inside the inputs of the form get cleared. As this snipper show :
function modifyParent() {
document.getElementById("parent").innerHTML += "<br>a line get added";
}
<div id="parent">
<form>
<input type="text" id="child">
</form>
<button type="button" onclick="modifyParent()">click</button>
</div>
Hello everyone,
Solution 1
I found a first esay way to prevent it if I know where the parent is modified. As this snipper show
function modifyParent() {
var child = document.getElementById("child");
child.setAttribute("value", child.value)
document.getElementById("parent").innerHTML += "<br>a line get added";
}
<div id="parent">
<form>
<input type="text" id="child" value="">
</form>
<button type="button" onclick="modifyParent()">click</button>
</div>
This solution look great, but only if i know where ans when the parent is modified. Also if i have a multiple inputs i need to loop on document.getElementsByTagName("input").
Solution 2
Since i dont know how many buttons i have and how many inputs, this is my best solution so far :
function modifyParent() {
setInputValues();
document.getElementById("parent").innerHTML += "<br>a line get added";
}
function setInputValues() {
for (var c of document.getElementsByTagName("input"))
c.setAttribute("value", c.value);
}
<div id="parent">
<form>
<input type="text" value="">
<input type="text" value="">
<input type="text" value="">
<input type="text" value="">
</form>
<button type="button" onclick="modifyParent()">click</button>
</div>
It work well for multiple inputs but i have to call the setInputValues() function before i modify any parent everytime. I started to consider to add setInterval on this function but I stop here because i'm starting to go a bit far and it's very likely that their is a better way.
Any help will be apreciated
A cleaner solution is to use a new element for the messages. This way you can set the messages inside a container without messing with the inputs.
const messageBox = document.querySelector(".messages");
function modifyParent() {
messageBox.innerHTML += "<br>a line get added";
}
<div id="parent">
<form>
<input type="text" value="">
<input type="text" value="">
<input type="text" value="">
<input type="text" value="">
</form>
<button type="button" onclick="modifyParent()">click</button>
<div class="messages"></div>
</div>
Another quick notice, innerHTML is vulnerable for XSS attacks Try using createElement and appendChild if possible.
const parent = document.getElementById("parent");
function modifyParent() {
const br = document.createElement("br");
const text = document.createTextNode("a line get added");
parent.appendChild(br);
parent.appendChild(text);
}
<div id="parent">
<form>
<input type="text" value="">
<input type="text" value="">
<input type="text" value="">
<input type="text" value="">
</form>
<button type="button" onclick="modifyParent()">click</button>
<div class="messages"></div>
</div>

Why is my function not defined and not loading

I have a function that's called with a submit button and another that is based on key entry enter. When I run my code I keep getting an error saying myFunction() is not defined why is this?
js code: The validate function is suppose to add in user input elements based on how many volunteers need and invitation for the website. the myFunction() code is supposed to save fields of the form to variable (more code variables are in here but you guys don't need to see that)
html: it is a basic form the user is supposed to enter how many guests and the JavaScript is supposed to create a field for each recipient name. I am then supposed to save the names to and array which I will be working on later but I can get past the myFunction is not defined error.
var wage = document.getElementById("howMany");
window.onload = wage.addEventListener("keydown", function(e) {
if (e.keyCode === 13) {
validate(e);
}
});
function validate(e) {
var num = document.getElementById("howMany").value;
for (i = 1; i < num; i++) {
//loop set to repeat to the amount of guests inputed by user
container.appendChild(document.createTextNode("Recipient " + (i + 1) + ":"));
//creates a text for the user to read which recipient each input is for
var x = document.createElement("input");
//creates the input element
x.setAttribute("id", "empInput" + i);
x.setAttribute("type", "text");
//sets the type and attribute
container.appendChild(x);
//places the input element in the container
//values.push(x);
}
}
window.onload = function myFunction() {
//loads the function on page load to change variables for user
var urlParams = new URLSearchParams(location.search);
//sets var for the URL information the users inputed information on submit
//var num = urlParams.get("howMany");
//sets the var for the amount of guests attending
var container = document.getElementById("container");
//sets a variable to reference the container in the form to place the input elements
var values = new Array();
}
<section id="pageForm">
<form name=myForm action="#">
<div>
<label for="howMany">How Many Guests:
<br />(max. 10) <br />
</label>
<input type="number" id="howMany" value="" placeholder="0" />
</div>
<div>
<label for="recipientName">Recipient name:
</label>
<input type="text" name="recipientName" placeholder="Enter your Recipient Name" />
</div>
<div id="container">
</div>
<label for="organizationName">Organization name:
</label>
<input type="text" name="organizationName" placeholder="Enter your Organization Name" />
<label for="eventDate">Event Date:
</label>
<input type="text" name="eventDate" placeholder="Enter your Event Date" />
<label for="websiteURL">URL:
</label>
<input type="text" name="websiteURL" placeholder="Enter your Website URL" />
<label for="hostName">Host name:
</label>
<input type="text" name="hostName" placeholder="Host Name" />
<input type="submit" value="Submit" onclick="myFunction()">
</form>
</section>
That's definitely not intuitive, but the name "myFunction" as you had it is basically ignored. Try this instead.
function myFunction() {
//loads the function on page load to change variables for user
//etc. as before
}
window.onload = myFunction;

JavaScript - set form input attribute in 'for' loop

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.

how execute function onto different input tags?

Javascript code
<script>
function disableBtn() {
document.getElementsByTagName("INPUT")[1].removeAttribute("disabled");
}
</script>
html code
<form>
<p>
<label for="uname">* User Name :</label>
<br>
<input type="text" name="txtuname" id="uname" onclick="disableBtn()" value="">
</p>
<div style="text-align:center">
<p>
<input name="username" type="submit" id="submit" value="Change Username" disabled="disable">
</p>
</div>
<p>
<label for="fullname">* Full Name :</label>
<br>
<input type="text" name="txtfullname" id="fullname" value="">
</p>
<div style="text-align:center">
<p>
<input name="fullname" type="submit" id="submit" value="Change Fullname" disabled="disable">
</p>
</div>
<p>
<label for="address">* Address :</label>
<br>
<input type="text" name="txtaddress" id="address" value="">
</p>
<div style="text-align:center">
<p>
<input name="address" type="submit" id="submit" value="Change Address" disabled="disable">
</p>
</div>
</form>
I want to add an onclick event in each input tag which executes the function disableBtn, but I want this code to work on any input I click. I do not want to have to give a number like this :
document.getElementsByTagName("INPUT")[1].removeAttribute("disabled");
for every input element.
I think I should use this but I don't know where to put it.
You want to loop over every input element and add an event? document.getElementsByTagName("input") returns an array, so you can use a loop to go over it.
JavaScript:
// This is a function which disables an input element
// Notice I used "this" instead of document.getElementsByTagName("input")[some number]
// "this" refers to the input element that was clicked
function disableBtn() {
this.parentNode.nextElementSibling.querySelector('input[type="button"]').disabled = false;
}
// Get every single input element
var inputs = document.getElementsByTagName("input");
for (var i = 0; i < inputs.length; ++i) {
// Loop through the input elements, and add a "click" event
var input = inputs[i];
input.addEventListener("click", disableBtn, false);
}
Code:
Change your function to this:
function disableBtn(el) {
el.parentNode.nextElementSibling.querySelector("input").disabled = false;
}
And the handler to this:
onclick="disableBtn(this)"
DEMO: http://jsfiddle.net/dcg8gzqt/
Explanation:
So now the handler passes the current element that was clicked to the disableBtn function.
That function then...
takes the clicked element and traverses up to its .parentNode
moves ahead to the .nextElementSibling, which is the next div,
then searches inside that div using .querySelector() for the first input it finds.
sets the .disabled property of the input to false

Categories

Resources