remove a child element br - javascript

I am working on a dynamic Checkbox where I can add and remove e.g. users. The adding is working fine, but to remove all the child elements troubles. Especially the br I don't know how to remove.
<style>
.container { align:right; border:1px solid #000000; width:300px; height: 100px; overflow-y: scroll;}
</style>
<script type="text/javascript">
var addTask = function () {
var newCheckbox = document.createElement("input");
newCheckbox.type = "checkbox";
newCheckbox.value = document.getElementById("MailAddress").value;
newCheckbox.id = "C11";
document.getElementById("UserList").appendChild(newCheckbox);
var label = document.createElement('label');
label.htmlFor = document.getElementById("MailAddress").value;
label.id = "L11";
label.appendChild(document.createTextNode(document.getElementById("MailAddress").value));
document.getElementById("UserList").appendChild(label);
document.getElementById("L11").appendChild(document.createElement("br"));
}
function delTask() {
var item = document.getElementById("C11");
item.parentNode.removeChild(item);
var item = document.getElementById("L11");
item.parentNode.removeChild(item);
// How can I remove die <br> too?
}
</script>
</head>
<body>
<header>
<p>Usergroup:</p>
</header>
<input type="text" id="MailAddress">
<input type="submit" value="Add Mail Address" onClick="addTask()" id="AddUser">
<div class="container" id="UserList"></div>
<input type="submit" value="Delete One Mail" onClick="delTask()" id="remove">

you can use document.getElementsByTagName('br') to get the array of all br tags then you can remove the br tag you want to remove. This requires you to know how many br tags are there in your document beforehand so that you'll remove the one with the correct index.
var x = document.getElementsByTagName("br");
x[1].parentNode.removeChild(x[1]);
will delete the second br tag in the document, assuming you have two br tags to begin with.

If removing <br> is the issue, then try this
var e = document.getElementsByTagName("p")[0];
e.innerHTML = e.innerHTML.replace('<br>', '');

This should do what you need - it looks for the elements with IDs and then removes every subsequent sibling node up to an element (or tag), as opposed to comment, text, etc.
function delTask() {
var el1 = document.getElementById("C11");
var el2 = document.getElementById("L11");
var next = el2.nextSibling;
// create array to hold all the elements to be removed
var items = [el1, el2, next];
// iterate through siblings until a tag (here <br/>) is found
while(next && next.nodeType != 1) {
next = next.nextSibling;
items.push(next);
}
// remove elements in reverse order
while(var el = items.pop()){ el.parentNode.removeChild(el); }
item.parentNode.removeChild(item);
}
A few notes there: you should not use "var" with the same variable multiple times in one block. The IDs (C11, L11) should be parameters, not hardcoded values.

Related

Making array with input of textarea

I'm trying to capture the input of a textarea and converting it to an array but it is reading the whole input as one element and making array of length 1.
<html>
<textarea id="area"></textarea>
<input type="submit" onclick="won()">
<p id="one" style="display: none;"></p>
</html>
The js part displays a message of the length of the array.
var area = document.getElementById("area");
var lines = area.value.split("\n");
var pa = document.getElementById("one");
function won() {
pa.style.display = "block";
pa.innerHTML = lines.length;
}
What I'm trying to achieve with the whole thing is that. The multi line input is to be converted into an array with each new line being a new element. Then I loop through the array and if even one element doesn't pass a validation function, an exception message is displayed under the texarea.
Can someone kindly help me with this?
With your snippet, you're grabbing the value onload so it would be empty, it should be in the event where you grab the value. Also avoid inline event triggering, add the event via js.
var area = document.getElementById("area");
var button = document.getElementById("btn-submit");
var one = document.getElementById("one");
button.addEventListener('click', () => {
// get value
var lines = area.value.split("\n");
one.style.display = "block";
one.innerHTML = lines.length;
})
<textarea id="area"></textarea>
<button type="button" id="btn-submit">Submit</button>
<p id="one" style="display: none;"></p>
What I'm trying to achieve with the whole thing is that. The multi
line input is to be converted into an array with each new line being a
new element. Then I loop through the array and if even one element
doesn't pass a validation function, an exception message is displayed
under the texarea.
const area = document.getElementById("area");
const button = document.getElementById("btn-submit");
const error = document.getElementById("error");
const items = document.getElementById("items");
button.addEventListener('click', () => {
// get textarea value, remove emptys
const lines = area.value.split("\n").filter(Boolean);
// reset error and items dom
error.innerHTML = items.innerHTML = ''
// do your validation, could loop or use .some(), .includes()
if (!lines.length) {
error.innerHTML = 'Enter at least one item'
} else if (!lines.includes('cat')) {
error.innerHTML = 'Entered lines should include at least one cat'
} else {
// no errors
items.innerHTML = `${lines.length} items<br><ul><li>${lines.join('</li><li>')}</li></ul>`
}
})
<textarea id="area"></textarea>
<button type="button" id="btn-submit">Submit</button>
<div id="error"></div>
<div id="items"></div>
Simply put your line var lines = area.value.split("\n"); under the won function like below and you will get your total lines.
Example
var area = document.getElementById("area");
var pa = document.getElementById("one");
function won() {
var lines = area.value.split("\n");
pa.style.display = "block";
pa.innerHTML = lines.length;
}
You can check it here too, https://codepen.io/vadera-abhijeet/pen/yLPxLRY

How do I add multiple classes to an element with JS?

I have below JS code:
<script>
function CommentStyle() {
var elementAuthor = document.getElementById("author");
var elementEmail = document.getElementById("email");
var elementUrl = document.getElementById("url");
elementAuthor.classList.add("form-control ulockd-form-bps required email");
elementEmail.classList.add("form-control ulockd-form-bps required email");
elementUrl.classList.add("form-control ulockd-form-bps required email");
}
window.onload = CommentStyle;
alert("Hello! I am an alert box!!");
</script>
ffee
<style>
.form-control {
border: 1px dashed #cccccc;
}
</style>
Alert works but the class is not added.Also how can I short this code instead of add new line for every id because the class is same?
classList.add takes multiple parameters, but will not accept strings with a space in it. You can pass in multiple strings, or if you have your classes stored in a variable classes in the form "firstClass secondClass thirdClass", you can use .split(' ') to split by spaces and then use the spread operator ... to pass the array's contents into classList.add as individual arguments.
This is even simpler for this case, since each element shares the same classes:
(Edit: OP actually ran this code on every page, including those without the relevant elements, so a check was added to exit if they did not exist in the DOM.)
function CommentStyle() {
let elementAuthor = document.getElementById("author"),
elementEmail = document.getElementById("email"),
elementUrl = document.getElementById("url");
// check IDs exist
if (!elementAuthor || !elementEmail || !elementUrl) return;
let classes = "form-control ulockd-form-bps required email".split(' ');
elementAuthor.classList.add(...classes),
elementEmail.classList.add(...classes),
elementUrl.classList.add(...classes);
// for demo purposes:
let [authorClasses, emailClasses, urlClasses] = [
elementAuthor.className,
elementEmail.className,
elementUrl.className
];
console.log({
authorClasses,
emailClasses,
urlClasses
});
}
window.onload = CommentStyle;
<label for="author">Author</label><br>
<input type="text" id="author"><br><br>
<label for="email">Email</label><br>
<input type="text" id="email"><br><br>
<label for="email">Url</label><br>
<input type="text" id="url"><br>
You don't have to access each field separately by ID, just give them all the same class and loop through that class.
<div class="comment-field" id="author"></div>
<div class="comment-field" id="email"></div>
<div class="comment-field" id="url"></div>
function CommentStyle() {
var comment_fields = document.querySelectorAll(".comment-field");
comment_fields.forEach(function(el){
el.classList.add("form-control","ulockd-form-bps","required","email");
});
}

How can I append some radio buttons with loop and wrap it around a form element?

I have an array and I want to append every element of this array as a radio button inside a specific DOM. My approach is to loop over the array.
However, I want to create an html form element that wraps around this newly with jQuery created radio buttons.
form opening tag.
Loop over the array and append all radio buttons.
form closing tag.
The form element is openend and closed immediately, then follows the radio buttons created by the loop.
I think its because of the async nature of JavaScript.
let arr = ['Apple', 'Banana', 'Tomatoe', 'Sugar'];
function loop_append(elem) {
$('a').append(`
<label for=${elem}>${elem}</label
<input type="radio" name="${elem}"></input></br>`
function radioButtonappender() {
$('.a').append('<form name="test">');
for (let i = 0; i < arr.length; i++) {
loop_apend(arr[i]);
}
$('.a').append('</form>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="A">
<div class="a">
</div>
</div>
Expected result:
<div class="A">
<div class="a">
<form name="test">
/* -> ALL THE RADIO BUTTONS AND LABELS */
</form>
</div>
</div>
Actual (wrong) result
<div class="A">
<div class="a">
<form name="test"> </form>
/* -> ALL THE RADIO BUTTONS AND LABELS */
</div>
</div>
Here is one approach (in vanilla javascript), using:
a for...of loop
document.createElement()
.setAttribute()
.textContent
.appendChild
Working Example:
let arr = ['Apple', 'Banana', 'Tomato', 'Sugar'];
function addRadioButtonsForm(arr) {
const a = document.getElementsByClassName('a')[0];
// BUILD THE FORM
let form = document.createElement('form');
form.setAttribute('name', 'test');
for (element of arr) {
// BUILD THE LABEL
let label = document.createElement('label');
label.setAttribute('for', element);
label.textContent = element;
form.appendChild(label);
// BUILD THE RADIO BUTTON
let radio = document.createElement('input');
radio.setAttribute('type', 'radio');
radio.setAttribute('name', 'ingredients');
form.appendChild(radio);
// BUILD THE LINEBREAK
let linebreak = document.createElement('br');
form.appendChild(linebreak);
}
a.appendChild(form);
}
addRadioButtonsForm(arr);
<div class="A">
<div class="a">
</div>
</div>
You can use this to vastly simplify things:
let arr = ['Apple', 'Banana', 'Tomatoe', 'Sugar'];
$('.a').append('<form name="test"></form>');
for ( var i = 0, l = arr.length; i < l; i++ ) {
$('form').append(`<label for=${arr[i]}>${arr[i]}</label>
<input type="radio" name="${arr[i]}"></input></br>`);
}
Rounin's solution works, but for some reason the labels are not clickable, only the actual buttons.
I played around with it. I have not included the form element here:
function addRadioButtonsForm(array, myId) {
const rbParent = document.getElementById('myId');
for (let i = 0; i<array.length; i++) {
// BUILD THE RADIO BUTTON
let radio = document.createElement('input');
radio.type = 'radio';
radio.name = "options";
radio.value = "option"+i ;
RBParent.appendChild(radio);
// BUILD THE LABEL
let label = document.createElement('label');
label.textContent = options[i]+"\n";
RBParent.appendChild(label);
// BUILD THE LINEBREAK
let linebreak = document.createElement('br');
RBParent.appendChild(linebreak);
};
}

how to bind dynamically created button click events to dynamically created input in javascript?

I am very new to javascripts and trying to create a dynamic html form where there are multiple button, and each button click map to a corresponding form input. Here is my code:
<html>
<head>
<title>Create Group</title>
<script src="/js/jquery-3.4.1.min.js"></script>
<script>
$(document).ready(function(){
$("#generate_form").click(function(){
var number = document.getElementById("number_of_groups").value;
var container = document.getElementById("container");
while (container.hasChildNodes()) {
container.removeChild(container.lastChild);
}
var i;
for (i=1;i<=number;i++){
var p = document.createElement("p");
var node = document.createTextNode("group " + i + " :");
p.appendChild(node);
container.appendChild(p);
var input = document.createElement("input");
input.type = "text";
var thisID = 'group_'+i;
input.id = thisID;
input.name=thisID;
container.appendChild(input);
var button = document.createElement("button");
button.id = "button_"+i;
button.type = "button";
container.appendChild(button);
button.onclick = function(){ document.getElementById(thisID).value = "hello world";};
var buttonLabel = document.createTextNode("Generate");
button.appendChild(buttonLabel);
container.appendChild(document.createElement("br"));
}
})
});
</script>
</head>
<body>
<h2>Create some group(s)</h2>
<br>
Create <input type="text" id="number_of_groups" name="number_of_groups" value="1"> group(s).
<button id="generate_form" type="button">GO</button>
<div id="container"/>
</body>
</html>`
So, the user would input number of groups to create and click 'Go' button, then the code should dynamically generate the form with the number the user choose. Each group of the form includes a input textbox and a 'Generate' button. When the button is clicked, the input textbox will show "hello world". However, the "hello world" only show up in the last input textbox no matter which 'Generate' button I click. So I changed the onclick function of the button to:
button.onclick = function(){ alert(thisID);};
Then I found that thisID is always the id of the last input textbox no matter which 'Generate' button I click. I guess that is because the binding of the click event does not happen till the script is done when 'thisID' would always be its latest value.
Would anyone please help me to realize the functionality I want? Thank you very much!
You would need to wrap the code within the for loop in a separate function, passing in the value of i as a parameter. This would create a closure, creating a new execution scope for your code. Otherwise what is happening is that your var is being hoisted, and is not exclusive to each iteration of the for loop, so your DOM is reflecting only the last value it was assigned.
for (i=1;i<=number;i++){
(function (i) {
var p = document.createElement("p");
var node = document.createTextNode("group " + i + " :");
p.appendChild(node);
container.appendChild(p);
var input = document.createElement("input");
input.type = "text";
var thisID = 'group_'+i;
input.id = thisID;
input.name=thisID;
container.appendChild(input);
var button = document.createElement("button");
button.id = "button_"+i;
button.type = "button";
container.appendChild(button);
button.onclick = function(){ document.getElementById(thisID).value = "hello world";};
var buttonLabel = document.createTextNode("Generate");
button.appendChild(buttonLabel);
container.appendChild(document.createElement("br"));
})(i);
}
You can check out an article on closures here:
https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36
EDIT: As one of your commenters mentioned, you can also set your vars to 'let' to achieve a similar effect. This is because let scopes the variable to the current code block, rather than being hoisted to the scope of the function, so each for loop iteration has a private let variable. It is still recommended to get a good understanding of closures and how they work, however.
Since you are already using JQuery, you can reduce some of the logic.
Let me know if this helps-
<html>
<head>
<title>Create Group</title>
</head>
<script src="/js/jquery-3.4.1.min.js"></script>
<script>
$(document).ready(()=>{
var txtGroup='<input type="text" id="txt_group_{0}" value="">';
var btnGroup='<button id="btn_group_{0}" type="button">Click Me</button>';
var container=$('#container');
$('#generate_form').click((e)=>{
var groupCount=parseInt($('#number_of_groups').val());
var idToStart=$('#container').children('div').length+1;
for(let i=idToStart;i< idToStart+groupCount;i++){
var divGroup=`<div id="div_group_${i}">`+
txtGroup.replace('{0}',i)+
btnGroup.replace('{0}',i)+`</div>`;
container.append(divGroup);
$('#btn_group_'+i).on('click',(e)=>{
console.log('#txt_group_'+i);
$('#txt_group_'+i).val('Hello World');
});
}
});
});
</script>
<body>
<h2></h2>
<br>
Create <input type="text" id="number_of_groups" name="number_of_groups" value="1"> group(s).
<button id="generate_form" type="button">GO</button>
<div id="container"></div>
</body>
</html>

Removing a text field using Javascript

I have the following code to add text fields when the function is called:
<span id="response"></span>
<script>
var qcountBox = 2;
var acountBox = 2;
var qboxName = 0;
var aboxName = 0;
function addInput()
{
var qboxName="question"+qcountBox;
var aboxName="answer"+acountBox;
if(qcountBox <=10 && acountBox <= 10)
{
document.getElementById('response').innerHTML+='<br/>Question '+qcountBox+': <input type="text" name="'+qboxName+'"/>';
document.getElementById('response').innerHTML+='<br/>Answer '+acountBox+': <input type="text" name="'+aboxName+'"/><br/>';
qcountBox ++;
acountBox ++;
}else
alert("No more than 10 questions allowed at this time.");
}
I also would like to be able to add a function to remove any new fields I have added. Any suggestions? Thanks
<script>
var qcountBox = 1;
var acountBox = 1;
var qboxName = 0;
var aboxName = 0;
function addInput()
{
var qboxName="question"+qcountBox;
var aboxName="answer"+acountBox;
if(qcountBox <=10 && acountBox <= 10)
{
document.getElementById('response').innerHTML+='<div id="'+qcountBox+'"><br/>Question '+qcountBox+': <input type="text" name="'+qboxName+'"/>';
document.getElementById('response').innerHTML+='<br/>Answer '+acountBox+': <input type="text" name="'+aboxName+'"/><br/></div>';
qcountBox ++;
acountBox ++;
}else
alert("No more than 10 questions allowed at this time.");
}
function removeInput(id)
{
document.getElementById(id).innerHTML = '';
}
You can remove any question that you added using the id of the question div (same as qboxName)
Surround each new piece of HTML in a span with a common class name. Then, find all the objects with that class name and remove them.
Add the span and class name to these:
document.getElementById('response').innerHTML+='<span class="added"> <br/>Question '+qcountBox+': <input type="text" name="'+qboxName+'"/></span>';
document.getElementById('response').innerHTML+='<span class="added"><br/>Answer '+acountBox+': <input type="text" name="'+aboxName+'"/><br/></span>';
Then, you can remove all the added spans like this:
var items = document.getElementsByClassName("added");
for (var i = 0; i < items.length; i++) {
items[i].parentNode.removeChild(items[i]);
}
Note: This is a generally better way to add your new HTML as it doesn't rewrite all previous HTML - it just adds new DOM objects:
var span = document.createElement("span");
span.className = "added";
span.innerHTML = '<br/>Question '+qcountBox+': <input type="text" name="'+qboxName+'"/><br/>Answer '+acountBox+': <input type="text" name="'+aboxName+'"/><br/>';
document.getElementById('response').appendChild(span);
You should actually create an input element in javascript and append it to your container through appendChild instead of using innerHTML +=.
You should also set an ID for those fields, not just a name. But it can be the same as theirs names.
Like this
var input = document.createElement("input");
input.type = "text";
input.name = input.id = qboxName;
document.getElementById("response").appendChild(input);
And then, you know, do the same for the other input field you need.
I know you need a text label for the boxes, or whatever, just do the same process to insert a span tag before them.
Also, I don't see a reason for those two counting variables. Instead of qcountBox and acountBox it's totally possible to have only one single counting variable. Maybe I'm wrong but shouldn't you increase this counting before setting the boxes names?
As for removing it, you can use the removeChild method, then, decrease your counting variable. like this:
function removeInput()
{
var qboxName = "question" + count;
var aboxName = "answer" + count;
document.getElementById("response").removeChild(document.getElementById(aboxName));
document.getElementById("response").removeChild(document.getElementById(aboxName));
count--;
}
Maybe if you're going to insert other elements together with these fields, like span tags for labels etc, it would be better to wrap them all up in a div or something, then simply do a removeChild to this container div only.

Categories