Cannot set property 'nodeValue' of null - javascript

I'm going through a book and it seems to be right, but the following code keeps giving me the error: Cannot set property 'nodeValue' of null. The code makes sense to me, but I don't understand why it can't clear the text value when clicking the clear button.
var clear = function(){
$("miles").firstChild.nodeValue = "";
$("gallons").firstChild.nodeValue = "";
$("mpg").firstChild.nodeValue = "";
}
window.onload = function () {
$("calculate").onclick = calculateMpg;
$("miles").focus();
$("clear").onclick = clear;
}
Html
<section>
<h1>Calculate Miles Per Gallon</h1>
<label for="miles">Miles Driven:</label>
<input type="text" id="miles"><br>
<label for="gallons">Gallons of Gas Used:</label>
<input type="text" id="gallons"><br>
<label for="mpg">Miles Per Gallon</label>
<input type="text" id="mpg" disabled><br>
<label> </label>
<input type="button" id="calculate" value="Calculate MPG"><br>
<input type="button" id="clear" value="clear"><br>
</section>

I think what you want is this where you use the .value property on the input fields directly:
var clear = function() {
$("miles").value = "";
$("gallons").value = "";
$("mpg").value = "";
}
Here's an explanation of what was going on. Now that we can see your full page and see that $ is document.getElementById(), the issue is that you are some of those nodes don't have a firstChild.
For example the object with an id="miles" is an input tag and it has no children so .firstChild is null.
In this line:
$("miles").firstChild.nodeValue = "";
$("miles") gets you the DOM object.
$("miles").firstChild returns null because there are no children of that DOM object.
$("miles").firstChild.nodeValue = ""; is an error because $("miles").firstChild is null and null doesn't have a property .nodeValue.

Input elements do not have child nodes so firstChild gives you null, further more if you're trying to clear the value of the input fields use the value property.
var clear = function(){
$("miles").value = "";
$("gallons").value = "";
$("mpg").value = "";
}

Looking at the code you posted in the comments, the problem is that $("miles") and the other elements don't have any children.
It seems like you're trying to do something like this:
var clear = function() {
$("miles").value = "";
$("gallons").value = "";
$("mpg").value = "";
}

Related

How to clone or create a nested DOM node and change all its containing id values according to a current id?

I need to display some numbers, strings from a class named Student, but i can't figure it out how i can change the id from children element. I have to use JavaScript.
what i tried to do:
class Student{
static count = 0;
constructor(nume, prenume, data_nasterii, foaie_matricola){
this.IdClasa = ++Student.count;
//definirea atributelor
this.nume = nume;
this.prenume = prenume;
this.data_nasterii = data_nasterii;
this.foaie_matricola = foaie_matricola;
}
afiseazaVarsta(){
}
afiseazaNotele(){
}
calculeazaMedia(){
}
adaugaNota(nota_noua){
}
}
var Stud = [new Student("Name", "Name1", "2000.01.01", "0123123"),
new Student("Green", "Blue", "2022/12.12", "321321")];
function afisareStudenti(){
let i = 0; let bol = false;
for(let x=1; x<=Student.count; x++) {
console.log(document.getElementById("AfisareStudenti"+x)==null);
if(document.getElementById("AfisareStudenti"+x)==null)
{
i = x;
bol = true;
break;
} else {
bol = false;
}
}
if((i<=Student.count)&&(bol==true)){
for(i; i<=Student.count; i++) {
console.log("i="+i);
var div = document.querySelector('#AfisareStudenti1');
var divClone = div.cloneNode(true);
console.log(divClone);
divClone.id = 'AfisareStudenti'+(i);
div.after(divClone);
var NumeStud = document.getElementById("NumeStudent"+(i-1));
var PrenumeStud = document.getElementById("PrenumeStudent"+(i-1));
var dataNastStud = document.getElementById("intData"+(i-1));
var FoaiaMatStud = document.getElementById("FoaiaMatStud"+(i-1));
NumeStud.id = "NumeStudent"+(i);
PrenumeStud.id = "PrenumeStud"+(i);
dataNastStud.id = "intData"+(i);
FoaiaMatStud.id = "FoaiaMatStud"+(i);
}
}
}
and this is the html file(the div that i want to clone):
<!--AFISARE-->
<div id="AfisareStudenti1">
<h2> Afisare Student 1</h2>
<label>Ce student doriti sa modificati? </label>
<form>
<label>Nume:</label><br>
<input type="text" id="NumeStudent1"><br>
<label>Prenume:</label><br>
<input type="text" id="PrenumeStudent1"><br>
<label>Data Nasterii:</label><br>
<input type="date" id="intData1"><br>
<label>Foaie matricola:</label><br>
<input type="text" id="FoaiaMatStud1"><br><br>
<input class="butoane" type="submit" value="Afisare"
onclick="afisareMeniuAfisStudenti()">
</form>
</div>
the class is saved in a dynamic array (could be n object of the class) so i have to make somehow to display the information dynamic. My version changes the id from all elements with the same id (every incrementation of i, the idnumber from id is incremented also). I tried to create that div with document.createElement but is impossible(at least for me) xD . I started coding in javascript 2 days ago, so please take it slow on me :(
I think i found the problem, but it doesn't solve it. (i need to put (i-1) when calling for getting the ids). (Newbie mistake)
Having commented ...
"I have the feeling that if provided with the broader picture the audience could be of much more help since the OP could be provided back with leaner/cleaner and better maintainable approaches."
... I nevertheless hereby lately provide a template-based approach which, besides supporting the OP's id based querying of student-items, is also easier to read and to maintain.
The code provided within the example-code's main function does not just implement the usage of the template-based node-creation via template literals and DOMParser.parseFromString but also prevents the default behavior of each student-form's submit-button by making use of event-delegation.
function createStudentElement(studentId) {
const markup =
`<div class="student-item" id="AfisareStudenti${ studentId }">
<h2> Afisare Student ${ studentId }</h2>
<label>Ce student doriti sa modificati? </label>
<form>
<label>Nume:</label><br>
<input type="text" id="NumeStudent${ studentId }"><br>
<label>Prenume:</label><br>
<input type="text" id="PrenumeStudent${ studentId }"><br>
<label>Data Nasterii:</label><br>
<input type="date" id="intData${ studentId }"><br>
<label>Foaie matricola:</label><br>
<input type="text" id="FoaiaMatStud${ studentId }"><br><br>
<input
class="butoane" type="submit" value="Afisare"
onclick="afisareMeniuAfisStudenti(${ studentId })"
>
</form>
</div>`;
const doc = (new DOMParser).parseFromString(markup, 'text/html');
return doc.body.removeChild(doc.body.firstElementChild);
}
// the button click handler.
function afisareMeniuAfisStudenti(studentId) {
console.log({ studentId })
}
function main() {
const itemsRoot = document.querySelector('.student-items');
// - prevent any form-submit by making use of event-delegation.
itemsRoot.addEventListener('submit', evt => evt.preventDefault());
// - just for demonstration purpose ...
// ... create student-items from a list of student IDs.
[1, 2, 3, 4, 5].forEach(studentId =>
itemsRoot.appendChild(
createStudentElement(studentId)
)
);
}
main();
.as-console-wrapper { left: auto!important; width: 50%; min-height: 100%; }
<div class="student-items"></div>
Tom's answer above is what you want for the element id problem that you asked about.
For your code in particular, you are going to have a couple other problems:
Because the final input is type="submit", its going to reload the page by default when it is clicked. The name of the "onclick" function also needs to match the function you defined (afisareStudenti).
You have:
<input class="butoane" type="submit" value="Afisare" onclick="afisareMeniuAfisStudenti()">
Change this to:
<input class="butoane" type="submit" value="Afisare" onclick="afisareStudenti(event)">
Now, when you click that button, it will call the afisareStudenti function and pass in the "event". So if you change:
function afisareStudenti(){
let i = 0; let bol = false;
to:
function afisareStudenti(event){
event.preventDefault()
let i = 0; let bol = false;
This will correctly call your function, and prevent the "default" action of that submit button from reloading the page.
To change the id attribute of children elements, you could use Element.querySelector() on divClone.
Because if you use Document.querySelector() or Document.getElementById() you will get the first element that matches your selector (i.e.children of div#AfisareStudenti1).
let i = 2;
var div = document.querySelector('#AfisareStudenti1');
var divClone = div.cloneNode(true);
divClone.id = 'AfisareStudenti'+(i);
divClone.querySelector("h2").innerText = "Afisare Student " + i;
var NumeStud = divClone.querySelector("#NumeStudent1");
var PrenumeStud = divClone.querySelector("#PrenumeStudent1");
var dataNastStud = divClone.querySelector("#intData1");
var FoaiaMatStud = divClone.querySelector("#FoaiaMatStud1");
NumeStud.id = "NumeStudent"+(i);
PrenumeStud.id = "PrenumeStud"+(i);
dataNastStud.id = "intData"+(i);
FoaiaMatStud.id = "FoaiaMatStud"+(i);
div.after(divClone);
<div id="AfisareStudenti1">
<h2> Afisare Student 1</h2>
<label>Ce student doriti sa modificati? </label>
<form>
<label>Nume:</label><br>
<input type="text" id="NumeStudent1" /><br>
<label>Prenume:</label><br>
<input type="text" id="PrenumeStudent1" /><br>
<label>Data Nasterii:</label><br>
<input type="date" id="intData1" /><br>
<label>Foaie matricola:</label><br>
<input type="text" id="FoaiaMatStud1" /><br><br>
<input class="butoane" type="submit" value="Afisare" onclick="afisareMeniuAfisStudenti()" />
</form>
</div>

How to make a text appear with a desired innerHTML using javascript/jquery

There is a button and a h2 tag. the h2 tag has its visibilty=hidden.
When the button is clicked, I want to call a function that calculates the cost and changes the innerHTML of h2 accordingly and then changes its visibility=visible.
HTML:
<main class="form-signin">
<form>
<div class="card">
<label for="inputAdult">Enter number of adults</label><input type="number" id="inputAdult" class="form-control" placeholder="No. of adults" required>
<label for="inputChildren">Enter number of children (4-12yo)</label><input type="number" id="inputChildren" class="form-control" placeholder="No. of children" required>
<button type="button" onclick="showCost()" id="btn3">Calculate my cost</button>
<h2 class="changeCost">Your total cost: $0</h2>
</div>
</form>
</main>
JavaScript / jQuery :
$("h2").css("visibility","hidden");
function calculateCost(){
var a = $("#inputAdult").val();
var c = $("#inputchildren").val();
if (((a+c)%3==0)||((a+c)%3==1)) {
var rooms = (a+c)/3;
}
else {
var rooms = ((a+c)/3)+1;
}
var cost = rooms*300;
return cost;
}
function showCost() {
var display = "Your total cost is: $" + calculateCost();
var x = $("h2");
x.value = display;
$("h2").css("visibility","visible");
}
Try x.text(display) instead of setting value. That changes the innerText of the element. If you'd like to set its HTML content, use x.html(display).
The value accessor is used for plain HTMLElement objects, not for jQuery-wrapped objects.
Apart from this, you should never access a tag solely by its tag name. Always give it some kind of class name or ID. You already gave it the changeCost class, so you could do $("h2.changeCost") rather than $("h2").
To avoid getting NaN do the following:
Javascript is case sensitive so replace line
var c = $("#inputchildren").val();
with
var c = $("#inputChildren").val();
I would also consider declaring rooms variable from if and else scope so it is accessible on calculations: see full function bellow:
function calculateCost(){
var a = $("#inputAdult").val();
var c = $("#inputChildren").val();
var rooms = 0;
if (((a+c)%3==0)||((a+c)%3==1)) {
rooms = (a+c)/3;
}
else {
rooms = ((a+c)/3)+1;
}
var cost = rooms*300;
return cost;
}

Why can't get input value checkbox in array?

In the code described below, the value of the input should be taken from everyone in the array and a new div with the input value in innerHtml should be created. I don't know why get an error that length.value not defined?
<input type="checkbox" class="checkboxnewdivs" id="checkboxnewdivs" name="checkboxnewdivs" value="divsone">
<input type="checkbox" class="checkboxnewdivs" id="checkboxnewdivs" name="checkboxnewdivs" value="divstwo">
<input type="checkbox" class="checkboxnewdivs" id="checkboxnewdivs" name="checkboxnewdivs" value="divsthree">
<button onclick="myFunction()">Click me</button>
<div id="container"></div>
function myFunction() {
let array = [];
var checkboxnewdivs = document.querySelectorAll('input[name="checkboxnewdivs"]:checked');
for (var i = 0; i < checkboxnewdivs.length; i++) {
var iddivs = array.push(checkboxnewdivs[i].value);
var div_new = document.createElement("DIV");
div_new.innerHTML = "ID div:"+iddivs ;
document.getElementById("container").appendChild(div_new);
}
}
var checkboxnewdivs = document.querySelectorAll('input[name="checkboxnewdivs"]:checked').value;
Should be
var checkboxnewdivs = document.querySelectorAll('input[name="checkboxnewdivs"]:checked');
The first one is trying to get a value property from a node collection, which will obviously be undefined.
You also had some typos (double 's') and don't define array anywhere. Define that where you defined checkboxnewdivs.
Working demo: https://jsfiddle.net/mitya33/m9L2dvz5/1/

Hide previoussibling in Javascript

HTML:
<label>First Name</label>
<input type="text" value="" id="FNAME">
JS:
var FNAME = document.getElementById('FNAME');
FNAME.addEventListener('input', function() {
if (FNAME.value !== ''){
alert('Field not empty! Value: '+ FNAME.value);
document.getElementById('FNAME').previousSibling.style.visibility = "hidden";
}
});
... gives an error:
TypeError: undefined is not an object (evaluating 'FNAME.previousSibling.style')
What am I doing wrong?
Append previousSibling to previousSibling again. It should correctly target the label now.
var FNAME = document.getElementById('FNAME');
if (FNAME.value !== ''){
var label = FNAME.previousSibling.previousSibling.style.visibility = "hidden";
}
To answer your question regarding the error you get, previousSibling of your input is a text node (the white space between the label and input). And text nodes do not have a style property.
Now, as far as I understand your question, you want to hide the label under certain conditions.
I would change your html a bit and use some more modern js api to access the elements.
<label for="FNAME">First Name</label>
<input type="text" value="" id="FNAME">
here I added the for property to the label.
var FNAME = document.querySelector("#FNAME");
var label = document.querySelector("label[for='FNAME']")
FNAME.addEventListener('input', function() {
if (FNAME.value !== ''){
alert('Field not empty! Value: '+ FNAME.value);
label.style.visibility = "hidden";
}
});
hope this help.
The previous sibling of your input element is it's text node.
So, you should call FNAME.previousSibling.previousSibling to access the label.
This question would give you more info.

why are names not being added to the list?

I found this fiddle and I am trying to get it to work...I can not figure out why the names are not being added to the list, for some reason Add button is acting like a submit button and I can not tell why...It should add all the numbers to a list so when I click submit, then it should send the numbers in an array..
JavaScript:
function bindName() {
var inputNames = document.getElementById("names").getElementsByTagName("inputNames");
for (i = 0; i < inputNames.length; i++) {
inputNames[i].onkeydown = function() {
if (this.value == "") {
setTimeout(deletename(this), 1000);
}
}
}
}
document.getElementById("addName").onclick = function() {
var num1 = document.getElementById("name");
var myRegEx = /^[0-9]{10}$/;
var myRegEx = /^[0-9]{10}$/;
var itemsToTest = num1.value;
if (myRegEx.test(itemsToTest)) {
var form1 = document.getElementById("names");
var nameOfnames = form1.getElementsByTagName("inputNames").length;
var newGuy1 = document.createElement("inputNames");
newGuy1.setAttribute("id", nameOfnames);
newGuy1.setAttribute("type", "text");
newGuy1.setAttribute("value", num1.value);
form1.appendChild(newGuy1);
num1.value = "";
bindName();
}
else {
alert('error');
}
};
HTML:
<h1>Enter Name</h1>
<div id="mainName">
<h2>name</h2>
<label for="name">Add Names: </label>
<input id="name" type="text">
<button id="addName">Add</button>
<form>
<div id="names">
</div>
<input METHOD="POST" action="text.php" type="submit" value="Submit">
</form>
</div>
I've seen
document.createElement("inputNames");
Shouldn't be
document.createElement("input");
?
Because this /^[0-9]{10}$/; will accept only 10 numbers and only that, try entering 1234567890 and you will see no error.
I'm not sure why your "name" field is restricted to 10 digit numbers, but I've got the thing to work.
http://jsfiddle.net/y8Uju/4/
I think the problem was that you were trying to create an element with the tag name inputNames, but that's not a valid tag. Instead I changed it to create inputs, and set the class to inputNames.

Categories