Node.appendChild: Argument 1 does not implement interface Node in pure JS - javascript

I'm trying to create a form with a list. The button is responsible for adding a new element to the list in the form. HTML:
<form id="newBrand">
<fieldset>
<ul id="formCars">
<li>
<legend>Car 1</legend>
<label>Name
<input type="text" name="carName1" />
</label>
</li>
</ul>
</fieldset>
<button type="button" id="addCar">+</button>
</form>
And there is my JS code:
const form = document.getElementById('newBrand');
const formCars = document.getElementById('formCars');
const addCarBtn = document.getElementById('addCar');
addCarBtn.addEventListener('click', () => formCars.appendChild(createBrandCar));
function createBrandCar() {
const result = document.createElement('li');
let size = formCars.getElementsByTagName('li').length;
result.innerHTML = `
<legend>Car ${size}</legend>
<label>Name
<input type="text" name="carName${size}" />
</label>`;
return result
}
My application renders fine, but when I click the button then I get this error:
Uncaught TypeError: Node.appendChild: Argument 1 does not implement interface Node.
This error points to a line that contains this code:
addCarBtn.addEventListener('click', () => formCars.appendChild(createBrandCar));
What can i do to prevent this error from occurring ?

You should invoke the function by specifying the parenthesis after the function name:
addCarBtn.addEventListener('click', () => formCars.appendChild(createBrandCar()));
Also, since you have already one list item on page load you should increment the size by 1:
let size = ++formCars.getElementsByTagName('li').length;
Demo:
const form = document.getElementById('newBrand');
const formCars = document.getElementById('formCars');
const addCarBtn = document.getElementById('addCar');
addCarBtn.addEventListener('click', () => formCars.appendChild(createBrandCar()));
function createBrandCar() {
const result = document.createElement('li');
let size = ++formCars.getElementsByTagName('li').length;
result.innerHTML = `
<legend>Car ${size}</legend>
<label>Name
<input type="text" name="carName${size}" />
</label>`;
return result
}
<form id="newBrand">
<fieldset>
<ul id="formCars">
<li>
<legend>Car 1</legend>
<label>Name
<input type="text" name="carName1" />
</label>
</li>
</ul>
</fieldset>
<button type="button" id="addCar">+</button>
</form>

Related

How to hide a whole component on selecting a radio button

I am working on html file. I have two two labels(say L1 and L2). Each label has two radio buttons. I want to hide L2 and it's radio buttons if a user selects any radio button from L1.
I know this can be done using java script but how to capture the selection of radio buttons on which i can execute my java script.
I have prepared a version based on your question. Is this what you meant?
[HTML]
<div id="container" class="container">
<div id="first-radio">
<label for="L1">L1</label>
<div class="radio-box">
<input type="radio" name="L1" /> L1-first
</div>
<div style="margin-bottom: 15px" class="radio-box">
<input type="radio" name="L1" /> L1-second
</div>
</div>
<div id="second-radio">
<label for="L2">L2</label>
<div class="radio-box">
<input type="radio" name="L2" /> L2-first
</div>
<div class="radio-box">
<input type="radio" name="L2" /> L2-second
</div>
</div>
[Javascript]
const container = document.getElementById("container");
const firstRadio = document.getElementById("first-radio");
const secondRadio = document.getElementById("second-radio");
const L1_Radio1 = container.children[0].children[1];
const L1_Radio2 = container.children[0].children[2];
const L2_Radio1 = container.children[1].children[1];
const L2_Radio2 = container.children[1].children[2];
const array1 = [L1_Radio1, L1_Radio2];
const array2 = [L2_Radio1, L2_Radio2];
function hideRadio() {
array1.forEach(item => {
item.addEventListener("change", () => {
secondRadio.style.visibility = "hidden";
});
});
array2.forEach(item => {
item.addEventListener("change", () => {
firstRadio.style.visibility = "hidden";
});
});
}
hideRadio();
You can watch it in action here: https://jsfiddle.net/s4onh9qk/6/

Possible to embed html in an if statement?

Is it possible to embed html within javascript? I am trying to pass two different forms based on the input to a radio button. My question is this possible?
<script>
if(document.getElementById('hello').checked) {
<p> form 1 </p>
}else if(document.getElementById('goodbye').checked) {
<p> form 2</p>
}
</script>
<button onclick="">one or the other</button>
You could create an Object with templates forms.
Depending on the checked radio element, you simply reference the template by the checked radio element value:
const form_templates = {
contact: `<form action="/form_contact.php">
<label><span>First name:</span><input type="text" name="fname"></label>
<label><span>Last name:</span><input type="text" name="lname"></label>
<input type="submit" value="Submit">
</form>`,
newsletter: `<form action="/newsletter.php">
<label><span>Email:</span><input type="text" name="email"></label>
<input type="submit" value="Submit">
</form>`
};
const ELS_picker = document.querySelectorAll("[name=form-picker]");
const EL_picked = document.querySelector("#picked");
const pickForm = () => {
const ckd = [...ELS_picker].filter(el => el.checked)[0];
EL_picked.innerHTML = form_templates[ckd.value];
};
// On radio change
ELS_picker.forEach(el => el.addEventListener("change", pickForm));
// Init!
pickForm();
<h3>Select a form:</h3>
<label>Contact: <input type="radio" value="contact" name="form-picker" checked></label>
<label>Newsletter: <input type="radio" value="newsletter" name="form-picker"></label>
<div id="picked"></div>
Example with two forms already defined in the document and by using classList.toggle()
const ELS_picker = document.querySelectorAll("[name=form-picker]");
const pickForm = () => {
const ckd = ELS_picker.forEach(el => {
document.querySelector(`[id="form--${el.value}"]`).classList.toggle("u-none", !el.checked);
});
};
// On radio change
ELS_picker.forEach(el => el.addEventListener("change", pickForm));
// Init!
pickForm();
/* Utility classes */
.u-none {
display: none;
}
<h3>Select a form:</h3>
<label>Contact: <input type="radio" value="contact" name="form-picker" checked></label>
<label>Newsletter: <input type="radio" value="newsletter" name="form-picker"></label>
<form id="form--contact" class="u-none" action="/form_contact.php">
<label><span>First name:</span><input type="text" name="fname"></label>
<label><span>Last name:</span><input type="text" name="lname"></label>
<input type="submit" value="Submit">
</form>
<form id="form--newsletter" class="u-none" action="/newsletter.php">
<label><span>Email:</span><input type="text" name="email"></label>
<input type="submit" value="Submit">
</form>
You can do it, but you may have to inject like this:
<div id="form"></div>
<button onclick="">one or the other</button>
<script>
var formEl = document.getElementById('form');
if(document.getElementById('hello').checked) {
formEl.innerHTML = '<p> form 1 </p>';
}else if(document.getElementById('goodbye').checked) {
formEl.innerHTML = '<p> form 2</p>';
}
</script>
If you want to update the HTML on your JS code, you should use functions like document.createElement.
Check the section Creating and placing new nodes at this Mozilla's doc.

How to create dynamic form elements using cloneNode

I'm trying to create an interactive resume template using javascript and html and have managed to use cloneNode to duplicate work history blocks (see attached screenshot)
The problem(s) I am having is that clicking on the add list item button in the cloned/duplicated work history block at the bottom, creates a <li> item in the 1st/cloned element.
The objective is to be able to add or delete ````` list elements within a specific work history block and to also be able to add/remove entire work history sections. Currently it deletes from the top down, which is also an issue.
Thanks for any pointers in advance.
CODE
<!DOCTYPE html>
<html>
<body>
<div id="test">
<div id="node">
<div class="work_history">
<div class="row">
<strong>
<input type="text" name="company" value="ACME Company">
</strong>
</div>
<div class="row">
<input type="text" name="position" value="Cheese Taster">
</div>
<input type="text" name="start" value="1/2019">
<input type="text" name="end" value="2/2020">
<ul id="list">
<li>
<textarea id="task" name="task" rows="4" cols="50">Did some things. Tasted cheese.</textarea>
</li>
<button onclick="addTask()">Add List Item</button>
<button onclick="RemoveTask()">Delete List Item</button>
</ul>
<button onclick="addWork()">Add Work</button>
<button onclick="removeWork()">Remove Work</button>
</div>
</div>
</div>
<script>
function addWork() {
var div = document.getElementById("node");
var cln = div.cloneNode(true);
//cln.setAttribute( 'id', 'newId');
document.getElementById("test").appendChild(cln);
}
function removeWork(){
var last = document.getElementById("test");
// want to delete the last added work history not first
last.removeChild(last.childNodes[0]);
}
function addTask(){
var ul = document.getElementById("list");
var task = document.getElementById("task");
var li = document.createElement("li");
li.setAttribute('id',task.value);
li.appendChild(document.createTextNode(task.value));
ul.appendChild(li);
}
function removeTask(){
var ul = document.getElementById("list");
var task = document.getElementById("task");
var item = document.getElementById(task.value);
ul.removeChild(item);
}
</script>
</body>
</html>
You'd have to use e.currentTarget instead of document.getElementById, otherwise you're only referring to the first instance of it:
function addWork(e) {
const div = e.currentTarget.parentElement;
const cln = div.cloneNode(true);
document.getElementById("test").appendChild(cln);
}
function removeWork(e) {
const last = e.currentTarget.parentElement;
last.parentElement.removeChild(last);
}
function addTask(e) {
const ul = e.currentTarget.parentNode;
let task = ul.children[0].childNodes[1].value;
let li = document.createElement("li");
// Replace paragraph breaks
task = task.replace(/\r?\n|\r/g, " ");
li.innerText = task;
ul.appendChild(li);
}
function removeTask(e) {
const ul = e.currentTarget.parentNode;
ul.removeChild(ul.lastChild);
}
<!DOCTYPE html>
<html>
<body>
<div id="test">
<div id="node">
<div class="work_history">
<div class="row">
<strong>
<input type="text" name="company" value="ACME Company">
</strong>
</div>
<div class="row">
<input type="text" name="position" value="Cheese Taster">
</div>
<input type="text" name="start" value="1/2019">
<input type="text" name="end" value="2/2020">
<ul id="list">
<li>
<textarea name="task" rows="4" cols="50">Did some things. Tasted cheese.</textarea>
</li>
<button onclick="addTask(event)">Add List Item</button>
<button onclick="removeTask(event)">Delete List Item</button>
</ul>
<button onclick="addWork(event)">Add Work</button>
<button onclick="removeWork(event)">Remove Work</button>
</div>
</div>
</div>
</body>
</html>
This allows you to refer to the specific element where the click event occurred and add/remove any elements that are relative within the DOM.
As a side note, it's best practice to have unique id attributes, adding the same id to multiple elements goes against that.
var add_button = $(".add_form_field");
var wrapper = $(".container1");
var max_fields = 9;
var x = 1;
$(add_button).click(function (e) {
e.preventDefault();
if (x < max_fields) {
x++;
$(wrapper).append(
` <div class="email">
<label for="">Year</label>
<input type="text" name="eduYear${x}">
<label for="">Title Name</label>
<input type="text" name="eduTitle${x}">
<label for="">Institution/School Name</label>
<input type="text" name="eduPlace${x}">
<label for="">Details</label>
<input type="text" name="eduNotes${x}"> <br>Delete<hr></div>`
); //add input box
}
});
$(wrapper).on("click", ".delete", function (e) {
e.preventDefault();
$(this).parent("div").remove();
x--;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container1">
<h2>Educations</h2>
<button type="button" class="add_form_field">Add Education
<span style="font-size:16px; font-weight:bold;">+ </span>
</button>
<div class="email">
<label for="">Year</label>
<input type="number" name="eduYear1">
<label for="">Title Name</label>
<input type="text" name="eduTitle1">
<label for="">Institution/School Name</label>
<input type="text" name="eduPlace1">
<label for="">Details</label>
<input type="text" name="eduNotes1">
</div>
you can try this to create dynamic form

Launching a new window and filling form values using Javascript

I have been learning JavaScript and i am attempting to launch a new window on click after a user has placed info into a form fields and then placing that info into form fields in the newly launched window. I have read many posts and methods in Stackoverflow however i cant seem to get it to work properly.
Starting page HTML:
<form id="memCat" methed="get" class="member_catalogue">
<button type="submit" class="prodBtn" id="catOrder" onclick="openMemberOrder()"><img class="prodImg" src="../../../Images/bcpot002_thumb.jpg" name="Red Bowl"></button>
<div class="cat_block">
<label class="cat_label" for="cat_name">Product Name:</label>
<input class="cat_input" type="text" id="catID" value="bepot002" readonly>
</div>
<div class="cat_block">
<label class="cat_label" for="cat_description">Product Description:</label>
<input class="cat_input" type="text" id="catDesc" value="Ocre Red Pot" readonly>
</div>
<div class="cat_block">
<label class="cat_label" for="cat_price">Per unit price:$</label>
<input class="cat_input" type="number" id="catVal" value="10" readonly>
</div>
</form>
New page HTML:
<form id="memOrder" method="post">
<div>
<label for="pname">Product Name:</label>
<input type="text" id="orderID" readonly>
</div>
<div>
<label for="pdescription">Product Description:</label>
<input type="text" id="orderDesc" readonly>
</div>
<div>
<label for="quantity">Quantity ordered:</label>
<input type="number" class="quantOrder" id="orderOrder" value="1" min="1" max="10">
</div>
<div>
<label for="ind_price">Per unit price: $</label>
<input type="number" class="quantCount" id="orderVal" readonly>
</div>
<div>
<label for="tot_price">Total Price: $</label>
<input type="number" class="quantCount" id="orderTotal" readonly>
</div>
<div>
<button type="reset">Clear Order</button>
<button type="submit" id="orderCalc">Calculate Total</button>
<button type="submit" id="orderPlace">Place Order</button>
</div>
</form>
Script i have to date:
function openMemberOrder() {
document.getElementById("orderID").value = document.getElementById("catID").document.getElementsByTagName("value");
document.getElementById("orderDesc").value = document.getElementById("catDesc").document.getElementsByTagName("value");
document.getElementById("orderVal").value = document.getElementById("catVal").document.getElementsByTagName("value");
memberOrderWindow = window.open('Member_Orders/members_order.html','_blank','width=1000,height=1000');
};
script and other meta tags in head are correct as other code is working correctly.
So after much trial and error i have had success with this:
On the submission page:
1. I created a button on the page that will capture the input form data
2. i created the localstorage function in JS
3. I then placed the script tag at the bottom of the page before the closing body tag
HTML
<button type="submit" class="prodBtn" id="catOrder" onclick="openMemberOrder()"><img class="prodImg" src="../../../Images/bcpot002/bcpot002_thumb.jpg" name="Red Bowl"></button>
Javascript
var catID = document.getElementById("catID").value;
var catDesc = document.getElementById("catDesc").value;
var catVal = document.getElementById("catVal").value;
function openMemberOrder() {
var memberOrderWindow;
localStorage.setItem("catID", document.getElementById("catID").value);
localStorage.setItem("catDesc", document.getElementById("catDesc").value);
localStorage.setItem("catVal", document.getElementById("catVal").value);
memberOrderWindow = window.open('Member_Orders/members_order.html', '_blank', 'width=1240px,height=1050px,toolbar=no,scrollbars=no,resizable=no');
} ;
Script Tag
<script type="text/javascript" src="../../../JS/catOrder.js"></script>
I then created the new page with the following javascript in the header loading both an image grid as well as input element values:
var urlArray = [];
var urlStart = '<img src=\'../../../../Images/';
var urlMid = '_r';
var urlEnd = '.jpg\'>';
var ID = localStorage.getItem('catID');
for (var rowN=1; rowN<5; rowN++) {
for (var colN = 1; colN < 6; colN++){
urlArray.push(urlStart + ID + '/' + ID + urlMid + rowN + '_c' + colN + urlEnd)
}
}
window.onload = function urlLoad(){
document.getElementById('gridContainer').innerHTML = urlArray;
document.getElementById('orderID').setAttribute('value', localStorage.getItem('catID'));
document.getElementById('orderDesc').setAttribute('value', localStorage.getItem('catDesc'));
document.getElementById('orderVal').setAttribute('value', localStorage.getItem('catVal'));
};
I then created 2 buttons to calculate a total based on inputs and clearing values separately, the script for this was placed at the bottom of the page.
function total() {
var Quantity = document.getElementById('orderQuant').value;
var Value = document.getElementById('orderVal').value;
var Total = Quantity * Value;
document.getElementById('orderTotal').value = Total;
}
function clearForm() {
var i = 0;
var j = 0;
document.getElementById('orderQuant').value = i;
document.getElementById('orderTotal').value = j;
}

Is there a way to create Javascript filter with radio buttons and checkboxes?

I have this task that has to been done soon, I have been trying to figure it out for the past couple of days but unfortunately, I have failed every time. I need to create a filter, where the user can click on a radio button to get those specific courses, after that or even before, he can click on checkboxes to filter even further.
I have managed to go through the "first" part of the filtering with radio buttons, the biggest issue is that I can't filter with checkboxes because for example -> you can't choose 2 options from the checkboxes.
Here is HTML
By subject:<br>
<form action="">
<input type="radio" name="name" value="Computing & IT">Computing & IT</input><br>
<input type="radio" name="name" value="Psychology & Sociology">Psychology & Sociology</input><br>
<input type="radio" name="name" value="Business & Management">Business & Management</input><br>
<input type="radio" name="name" value="Law & Criminology">Law & Criminology</input><br>
<input type="radio" name="name" value="Data Analytics">Data Analytics</input><br>
<input type="radio" name="name" value="Finance">Finance</input><br>
<input type="radio" name="name" value="Human Resource Management">Human Resource Management</input><br>
<!-- <input type="submit" value="Submit"> -->
</form>
<hr>
<h4> By Award:</h4>
<form action="">
<input type="checkbox" value="Postgraduate">Postgraduate</input><br>
<input type="checkbox" value="Undergraduate">Undergraduate</input><br>
<input type="checkbox" value="Top-Up">Top-Up</input><br>
</form>
and here is JS
fetch("https://api.myjson.com/bins/1axsrs")
.then(response => response.json())
.then(data => {
let api_array = data.name;
let radio = document.querySelectorAll('input[type=radio]');
let checkboxes = document.querySelectorAll('input[type=checkbox]')
api_array.map(item => {
document.getElementById('app').innerHTML +=
`<div class="card">
<h6>${item.vertical}</h6>
<h4>${item.program}</h4>
<p>${item.level}</p>
<button class="myButton">Enquire Now</button>
`
})
for(let select of radio) {
select.addEventListener('click',() => {
document.getElementById('app').innerHTML = "";
let api_array = data.name.filter(e => e.vertical === select.value)
api_array.map(item => {
document.getElementById('app').innerHTML +=
`<div class="card">
<h6>${item.vertical}</h6>
<h4>${item.program}</h4>
<p>${item.level}</p>
<button class="myButton">Enquire Now</button>
`
})
for(let check of checkboxes) {
check.addEventListener('change',() => {
document.getElementById('app').innerHTML = "";
if(check.checked) {
let chosen = api_array.filter(c => c.level === check.value)
chosen.map(item => {
document.getElementById('app').innerHTML +=
`<div class="card">
<h6>${item.vertical}</h6>
<h4>${item.program}</h4>
<p>${item.level}</p>
<button class="myButton">Enquire Now</button>
`
})
} else {
}
})
}
})
}
})

Categories