My question aims to find the simplest way for removing a child from a div element. In this case either Apple, Orange or Banana. Which means you can put the cursor on one of these words and then click delete child.
The only way Iam thinking is doing it in two steps:
Returning the index of the selected child with returnIndexOfChild() (custom built)
Using the removeChild method
I mean when you are having a big text java script engine has to loop through the whole text to find the index. Is there a more direct way like deleting anchorNode by selection object?
//html part
<div contentEditable="true" id="editableField"><b>Apple</b><i>Orange</i><b>Banana</b></div>
<button onclick="deleteChild()"> Delete</button>
//javascript part
var selection = document.getSelection();
myDiv = document.getElementById("editableField");
//Returns index of selected child (1)
function returnIndexOfChild(){
let i = 0;
for (i; i < myDiv.childNodes.length; i++){
if(selection.anchorNode.parentElement === myDiv.childNodes[i]){
console.log(i);
break;
};
}
return i;
}
//Removing Child(2)
function deleteChild (){
myDiv.removeChild(myDiv.childNodes[returnIndexOfChild()]);
}
You can just call remove() on the element itself
function deleteChild (){
const selection = document.getSelection();
selection.anchorNode?.parentElement?.remove();
}
<div contentEditable="true" id="editableField"><b>Apple</b><i>Orange</i><b>Banana</b></div>
<button onclick="deleteChild()"> Delete</button>
2 solutions:
//html part
<div contenteditable="true" id="editableField">
<li>Apple</li>
<li>Orange</li>
<li>Banana</li>
<li>potato</li>
<li>grape</li>
<li>egg</li>
<li>milk</li>
</div>
<input type="text" class="input" />
<button class="button">Delete</button>
<script>
const myDiv = document.querySelector("#editableField");
const input = document.querySelector(".input");
const btn = document.querySelector(".button");
// first way thanks to event bubbling
myDiv.addEventListener("click", (ev) => {
ev.target.remove();
});
// second way, by iterating through items
btn.addEventListener("click", () => {
// The "onclick="..." in the html is old solution, new and better is addEventListener(...)"
const myDivChildren = [...myDiv.children]; // The "..." is spread operator, "myDiv" is HTMLCollection, an array like object in orter ot iterate ovet it I created array by spreading it
const inputValue = input.value || myDivChildren.length - 1; // take input value if exist, if not then last index so remove last item
myDivChildren.forEach((el, i) => {
if (i == inputValue) {
el.remove(); // When indexes match then delete
}
return; // When indexes match then stop executing loop
});
input.value = "";
});
I got rid of getSelection(), it complicates removing items, do you care about using getSelection()? Should I use it in the answer?
Related
I am looking for a way to remove a text from a div, without removing the button inside.
Please see the image above.
The following code does not work because it removes the button too.
$(".input-group-append").empty();
OR
document.querySelector(".input-group-append").text = '';
document.querySelector(".input-group-append").innerHTML = '';
To remove the text, you can store the children selectors first and clear the parent with innerHTML='' and add that children selectors again.
const parent = document.querySelector(".input-group-append");
const childs = [];
for(let i = 0; i < parent.children.length; i ++) {
childs.push(parent.children[i]);
}
parent.innerHTML = '';
childs.forEach((item) => parent.appendChild(item));
<div class="input-group-append">
<button type="submit" class="btn btn-search">Submit Button</button>
Test Text
</div>
Since you are not planning to remove the button itself and just want to remove the text within the button, you must modify the seclector to direct towards the button itself and then use text or innerText property.
document.querySelector(".input-group-append > button").text = '';
// OR
document.querySelector(".input-group-append > button").innerText = '';
This will remove the text from within the button.
For this use case could probably just do,
el = document.querySelector('.input-group-append')
for (let i = 0;i<el.children.length;i++) {
if(el.childNodes[i].nodeType === 3) {
el.removeChild(el.childNodes[i])
}
}
This shoud remove all loose text from your div without touching elements:
var elements = $(".input-group-append *");
$(".input-group-append").html("");
elements.each(function(){
$(".input-group-append").append($(this)[0]);
});
So I'm making a basic to-do list using only HTML and JS and for some reason, when I go to add an item to the list, the variable that I'm using to select the empty "li" element is returning as "undefined" after I execute the function under the EventListener for the "clear" button. Could someone help out here pls. HTML and JS attached below:
let todos = [];
let add = document.querySelector("#add");
let remove = document.querySelector("#remove")
let clear = document.querySelector("#clear")
let todolist = document.querySelector("#todolist")
let addTodo;
let clearedTodo;
let newTodo;
add.addEventListener("click", function() {
addTodo = prompt("Enter the item you would like to add.")
todos.push(addTodo);
todolist.innerHTML += "<li></li>"
newTodo = document.getElementsByTagName("li")[todos.length - 1]
newTodo.textContent = addTodo;
})
remove.addEventListener("click", function() {
let removeTodo = prompt("Enter the index number of the item you would like to remove.") - 1;
let removedTodo = document.getElementsByTagName("li")[removeTodo]
removedTodo.remove();
todos.splice(removeTodo, 1);
})
clear.addEventListener("click", function() {
todos = [];
document.querySelector("ol").remove();
document.querySelector("div").innerHTML += '<ol id="todolist"></ol>'
console.log("To Do list was cleared.")
})
<h1>The Ultimate To Do List</h1>
<p>Click on an item to mark as done.</p>
<button id="add">ADD</button>
<button id="remove">REMOVE</button>
<button id="clear">CLEAR</button>
<div id="clearer">
<ol id="todolist">
</ol>
</div>
Thanks.
The problem is in your clear function. Mostly it looks good except for one problem that causes the major error. When you remove all the "ol" element, your todolist var loses reference, since it has nothing to point to. You would have to redeclare it.
But there is an easier way to fix this. Remove these lines:
document.querySelector("ol").remove();
document.querySelector("div").innerHTML += '<ol id="todolist"></ol>'
Use this line instead:
todolist.innerHTML = "";
Now the todo list in the DOM is also cleared and your todolist var still points to what its supposed to.
I'm creating a webpage which would collect links from the user and simply open every link in a new tab. For collecting links I am using HTML's <textarea> tag with a submit button.
User is expected to give only one link for each line
https://google.com
https://stackoverflow.com
https://facebook.com
I would open links by sending each passing each URL through this function.
function open(url) {
var open= window.open(url, '_blank');
open.focus();
}
But how exactly to run loop? How to get values from textarea in an array and then run a loop which would send value at every index to this function?
If you think this could be done in a better than other than this, feel free to add your method.
It would help if you gave your textarea a unique identifier, this way we can get at its contents easily. i.e, <textarea id="linksInput">...</textarea>
Then we can do
let links = document.getElementById("linksInput").value.split("\n");
We get the value in the textarea and split it at every newline character ("\n"), getting our individual links in an array, with each element being a single line from the original textarea value. Now we can loop through the array links.
for (let i = 0; i < links.length; i++) {
open(links[i]);
}
You can use the below code to get your result.
HTML
<textarea id='links'>
</textarea>
<button id='trigger'> Get value </button>
JS
document.addEventListener('DOMContentLoaded', () =>{
const ta = document.getElementById('links')
const button = document.getElementById('trigger')
button.addEventListener('click', () => {
const list = ta.value.split('\n')
forEach(let i=0; i < list.length; i++) {
window.open(list[0], "_blank");
}
})
})
You can add an id to the text field and use javascript to get the value of TextArea.
Since you are looking at multiple values separated by "/n", you will have to split the text and loop over the result.
function submitText() {
var textVal = document.getElementById("txtarea").value;
textVal = textVal.split('\n');
if (textVal.length > 0) {
for (const element of textVal) {
console.log(element);
window.open(element, "_blank");
}
}
}
<textarea id="txtarea"></textarea>
<button type="button" onclick="submitText()">Submit</button>
I wanna know how I can change the innerHtml to switch back and forth between two states.
I have this html
<div class="test" id="test">
<p>this is a test</p>
</div>
<p id="js" class="test" >Change</p>
and this is the JavaScript I have
let button = document.getElementById("js");
button.onclick = function() {
document.getElementById("test").innerHTML = "test";
};
how can I change the innerHTML from "test" to "another test" and vice versa ?
It's better not to store state in the HTML - don't test against what's currently in the HTML, keep a variable in your Javascript instead.
You should also only use let when you want to warn other programmers that you're going to reassign the variable in question - otherwise, use const.
Also, if you're changing the text of an element, assign to textContent instead - it's safer, faster, and more predictable.
const button = document.getElementById("js");
const test = document.getElementById("test");
let clicked = false;
button.onclick = function() {
clicked = !clicked;
if (clicked) test.textContent = 'another test';
else test.textContent = 'test';
};
<div class="test" id="test">
<p>this is a test</p>
</div>
<p id="js" class="test" >Change</p>
First, .innerHTML is only for when you are setting/getting a string that contains HTML. When you are not, use .textContent, which is more efficient and reduces security risks.
Then, you only need a toggling if statement, which can be done with a JavaScript ternary operator.
Also, rather than using event properties, like onclick. Use .addEventListener(), which is more robust and follows the modern standard.
// Get a reference to the <p> that is inside of the element who's id is "test"
let output = document.querySelector("#test p");
// Set up an event handler for the "Change" element
document.getElementById("js").addEventListener("click", function() {
// Check the current textContent and set it to the other value
output.textContent === "test" ? output.textContent = "another test" : output.textContent = "test";
});
<div class="test" id="test">
<p>this is a test</p>
</div>
<p id="js" class="test" >Change</p>
Just toggle between the two with an if statement like this:
let button = document.getElementById("js");
let toggleText = document.getElementById("test");
button.addEventListener('click', function() {
if (toggleText.innerHTML !== "another test") {
toggleText.innerHTML = "another test";
} else {
toggleText.innerHTML = "test";
}
});
ALso, as #CertainPerformance mentioned in the other answer, I would recommend that you use textContent rather than innerHTML since you're checking and toggling the element's string content and not the element itself.
I'm going to expand on a couple of excellent answers here.
What if you had more options and wanted to iterate through a list?
In that case, I'd use a data attribute to hold the button state. This is still a valid approach with just two options.
I am going to use Scott's answer as the basis of mine, so everything he says is pertinent.
// Get a reference to the <p> that is inside of the element who's id is "test"
let output = document.querySelector("#test p");
// Set up an event handler for the "Change" element
document.getElementById("js").addEventListener("click", function() {
//Here is out list of options
var options = ["test", "another test", "yet another test", "Really? Another Test?"];
//get the current state value and increment it
var index = parseInt(this.dataset.state, 10) + 1;
//if index is out of bounds set it to 0
if(index > options.length -1 || index < 0)
{
index = 0;
}
//Set the text
output.textContent = options[index];
//Set the new state
this.dataset.state = index;
});
<div class="test" id="test">
<p>this is a test</p>
</div>
<p id="js" class="test" data-state="-1" >Change</p>
I have this unordered list with random elements:
<ul id="uList">
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
<p>You have selected: </p><p id="result"></p>
I added an Event Listener on all of the elements of unordered list.
var elems = document.getElementsByTagName('li');
var selected;
var arr1 = [];
Array.from(elems).forEach(v => v.addEventListener("click", onClickItems,false));
I created a function that toggle when I click on unordered list elements,so i can add and remove the element into/from array.
function onClickItems() {
this.classList.toggle('selected');
if (this.classList.contains('selected')){
selected = this.innerHTML;
arr1.push(selected);
document.getElementById("result").innerHTML = arr1.join("<br>");
} else {
lookValueArray(returenIndex());
document.getElementById("result").innerHTML = arr1.join("<br>");
}
}
the adding part works perfect but when the user selected the same elements from the unordered list to remove it, it won't work. it only removes the last element has been add to the array.
so, I created these two function:
First one, to store the index of the selected element when it enters the array.
function returenIndex () {
var indexx = arr1.indexOf(selected);
return(indexx);
}
second one, to look for the value of the selected index from unordered list and remove it if it is equal to the selected one.
function lookValueArray (inde1) {
if (arr1[inde1].value = selected) {
arr1.splice(inde1, 1);
}
}
still the same output. it adds perfectly but it wont remove it.Moreover, it will only remove the last element was entered into the array even if I selected the second one to be removed.
BTW, I tried to use arr1.splice(0, 0, selected) instead of arr1.push(selected) ,so I can have the element entered the array in specific position but that wont work too.
In your code your selected variable is undefined when you first click one of your elements. You need to add a value to selected when you first click one of the elements so you just need to move selected = this.innerHTML; outside the if statement. You also do not need the if statement inside the lookValueArray() function, which already is wrong because you're doing an asignment instead of verifying using(== or ===). See the working snippet below please:
var elems = document.getElementsByTagName('li');
var selected;
var arr1 = [];
Array.from(elems).forEach(v => v.addEventListener("click", onClickItems, false));
function onClickItems() {
selected = this.innerHTML;
this.classList.toggle('selected');
if (this.classList.contains('selected')) {
//selected = this.innerHTML; //commented this line and added it above, outside the if statement
arr1.push(selected);
document.getElementById("result").innerHTML = arr1.join("<br>");
} else {
lookValueArray(returenIndex());
document.getElementById("result").innerHTML = arr1.join("<br>");
}
}
function lookValueArray(inde1) {
arr1.splice(inde1, 1);
}
function returenIndex() {
var indexx = arr1.indexOf(selected);
return (indexx);
}
.selected {
color: #f00;
}
<ul id="uList">
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
<p>You have selected: </p>
<p id="result"></p>