Loop through <li> and display list containing input value - javascript

I have a list of items like a todo list and i have a search input where i want users to search through the list'
I am using the keyup event and if input matches i am trying to use css to set the matched li to display:'' while the list items that do not match i want to set display:none.
so far i am able to console.log my results but cant effect changes to my li list as the css to set display none doesn't work.
here is my code below.
const Ul = document.querySelector('.clipBoard');
const search = document.querySelector('.search');
array.forEach((item) => {
let button = document.createElement('button');
button.className =
'list-group-item buttonLi';
button.innerText += item;
Ul.appendChild(button);
//Search function
search.addEventListener('keyup', () => {
let filterValue = search.value;
const li = Ul.querySelectorAll('.buttonLi');
for (let i = 0; i < li.length; i++) {
let List = li[i];
if (List.innerHTML.indexOf(filterValue) > -1) {
console.log(li[i].innerHTML);
li[i].style.display = '';
} else {
li[i].style.display = 'none';
}
}
});

I would suggest you to assign an id to each element using the index at that level:
array.forEach((item, INDEX) => {
let button = document.createElement('button');
var id = 'el-'+INDEX
button.setAttribute("id", id);
button.setAttribute("class", "list-group-item buttonLi");
button.innerText += item;
});
Then on your search function use that id to hide the elements
search.addEventListener('keyup', () => {
let filterValue = search.value;
const li = Ul.querySelectorAll('.buttonLi');
for (let i = 0; i < li.length; i++) {
let List = li[i];
if (List.innerHTML.indexOf(filterValue) > -1) {
console.log(li[i].innerHTML);
// something like that
var idToShow = '#el-'+i;
document.querySelector(idToShow).style.display = 'block';
} else {
// something like that
var idToHide = '#el-'+i;
document.querySelector(idToHide).style.display = 'none';
}
}
});
I did not test this code, just trying to point you to an eventual solution!
You could also do the filtering on your array then for each search you re-render your list!

Related

A function to remove a div element that contains specific text in Javascript?

I've written a simple code that takes text from the input field, stores it as a string in an array and creates a div with that same text every time the "add" button is pressed.
Then there's a "remove" button, that removes the item from array if the input matches the item in the array.
I need a function to remove the previously created div with the same text inside as the current input.
E.g. if I type "book1" press "add" - array gets 'book1' as a first item and a div "book1" is created, "book2", "book3" and so on. If I type 'book2' and press remove, it gets removed from the array and a respective div should be removed.
That last function I just can't figure out.
let addBtn = document.getElementById("add-btn");
let removeBtn = document.getElementById("rmv-btn");
let bookArray = [];
addBtn.addEventListener("click", addBook);
removeBtn.addEventListener("click", removeBook);
let innerDiv = document.body.newDiv.innerHTML
function addBook() {
newBook = document.getElementById("input").value;
if (newBook != '') {
bookArray.push(newBook);
addElement();
clear();
console.log(bookArray);
} else {
clear();
console.log(bookArray);
}
}
function removeBook() {
inputBook = document.getElementById("input").value;
for (i = 0; i < bookArray.length; i++) {
if (inputBook.toString() === bookArray[i].toString()) {
bookArray.splice([i], 1);
console.log(bookArray);
removeElement()
return;
} else {
clear();
}
}
console.log(bookArray);
}
function clear() {
document.getElementById("input").value = "";
}
function addElement() {
let newDiv = document.createElement("div");
newDiv.innerHTML = newBook;
my_div = document.getElementById("mydiv");
document.body.appendChild(newDiv, my_div);
}
function removeElement() {
alert("this bit needs working out");//???
}
<input type="text" id="input" />
<button id="add-btn">Add</button>
<button id="rmv-btn">Remove</button>
<div id="mydiv"></div>
</div>
You need to change how you are adding the div because it adding it outside and not as a child of my_div
let addBtn = document.getElementById("add-btn");
let removeBtn = document.getElementById("rmv-btn");
let bookArray = [];
addBtn.addEventListener("click", addBook);
removeBtn.addEventListener("click", removeBook);
function addBook() {
newBook = document.getElementById("input").value;
if (newBook != '') {
bookArray.push(newBook);
addElement();
clear();
console.log(bookArray);
} else {
clear();
console.log(bookArray);
}
}
function removeBook() {
inputBook = document.getElementById("input").value;
for (i = 0; i < bookArray.length; i++) {
if (inputBook.toString() === bookArray[i].toString()) {
bookArray.splice([i], 1);
console.log(bookArray);
removeElement(i);
return;
} else {
clear();
}
}
console.log(bookArray);
}
function clear() {
document.getElementById("input").value = "";
}
function addElement() {
let newDiv = document.createElement("div");
// count number of children in mydiv
let count = document.getElementById("mydiv").childElementCount;
// add an id
newDiv.id = 'mydiv-' + count;
newDiv.innerHTML = newBook;
my_div = document.getElementById("mydiv");
my_div.appendChild(newDiv, my_div);
}
function removeElement(el) {
// remove html element from dom
let my_div = document.getElementById("mydiv");
my_div.removeChild(my_div.childNodes[el]);
}
A workaround to remove book by the input value by user:
Modify the addElement function to:
function addElement() {
let newDiv = document.createElement("div");
newDiv.innerHTML = newBook;
newDiv.setAttribute('data-book-name', newBook); //new added line | setting data attribute
my_div = document.getElementById("mydiv");
document.body.appendChild(newDiv, my_div);
}
removeElement will be:
function removeElement() {
document.querySelector('[data-book-name="'+ newBook +'"]')?.remove();
}
But this will remove first book in the DOM. If you want to remove all books with same name use:
function removeElement() {
var books = document.querySelectorAll('[data-book-name="'+ newBook +'"]');
if(books.length == 0) return;
books.forEach(x => x.remove())
}

Javascript passing info from one function to another

I've created a JS function that hides a certain amount of breadcrumbs if there are too many. They are replaced by a button (ellipsis), when you click the button the hidden breadcrumbs are revealed.
The Problem: I loop through the breadcrumbs to see if there are enough to hide. If there are I hide them. But I can't figure out how to then call the code to create the button. If I call the button code in the loop I get more than 1 button generated.
Right now the button will always appear whether there are enough breadcrumbs to hide or not.
In my mind, I would have the for loop with the if statement return true to what would then be the button function. But I can't figure out how to do this. Please offer any pointers for restructuring this code if you can.
Here's a Codepen: https://codepen.io/sibarad/pen/GRvpEbp
Basic HTML:
<nav aria-label="breadcrumb">
<ol class="c-breadcrumb mb-7 md:mb-8">
<li class="c-breadcrumb-item">
Breadcrumb 1
</li>
<li class="c-breadcrumb-item">
Breadcrumb 2
</li>
<li class="c-breadcrumb-item">
Longer Breadcrumb Name 03
</li>
</ol>
</nav>
Javascript:
function breadcrumb() {
// Target specific breadcrumbs, not 1st or last 2
let hiddenbreadcrumb = document.querySelectorAll('.c-breadcrumb-item:nth-child(1n+2):nth-last-child(n+3)');
// Loop through select breadcrumbs, if length is greater than x hide them.
for (var i = 0; i < hiddenbreadcrumb.length; i++) {
if(hiddenbreadcrumb.length >= 3) {
hiddenbreadcrumb[i].style.display = "none";
}
}
// This would be the button function, but I don't know how to engage this only if the if statement above was met.
let li = document.createElement('li');
li.className = 'c-breadcrumb-item';
let ellipbutton = document.createElement('button');
ellipbutton.type = 'button';
ellipbutton.innerHTML = '...';
ellipbutton.className = 'c-breadcrumb_btn u-btn-clear';
ellipbutton.onclick = function() {
console.log("clicked");
for (var i = 0; i < hiddenbreadcrumb.length; i++) {
hiddenbreadcrumb[i].style.display = "flex";
}
li.style.display = "none";
};
li.appendChild(ellipbutton);
let container = document.querySelector('.c-breadcrumb-item:first-child');
container.insertAdjacentElement("afterend", li);
}
breadcrumb();
We can refactor your code slightly to achieve this - the if statement which checks whether there are more than 3 breadcrumbs doesn't need to be inside the for loop - it's redundant to keep checking the same value multiple times.
If we move that outside the loop then it can
a) prevent unnecessary looping when there aren't enough breadcrumbs, and
b) wrap around the button creation code as well, which should solve your problem.
For example:
if (hiddenbreadcrumb.length >= 3) {
for (var i = 0; i < hiddenbreadcrumb.length; i++) {
hiddenbreadcrumb[i].style.display = "none";
}
let li = document.createElement('li');
li.className = 'c-breadcrumb-item';
let ellipbutton = document.createElement('button');
ellipbutton.type = 'button';
ellipbutton.innerHTML = '...';
ellipbutton.className = 'c-breadcrumb_btn u-btn-clear';
ellipbutton.onclick = function() {
console.log("clicked");
for (var i = 0; i < hiddenbreadcrumb.length; i++) {
hiddenbreadcrumb[i].style.display = "flex";
}
li.style.display = "none";
};
let container = document.querySelector('.c-breadcrumb-item:first-child');
container.insertAdjacentElement("afterend", li);
}
It looks like some small initialization issues. This should correct it:
Change this:
let hiddenbreadcrumb = document.querySelectorAll('.c-breadcrumb-item:nth-child(1n+2):nth-last-child(n+3)');
// Loop through select breadcrumbs, if length is greater than x hide them.
for (var i = 0; i < hiddenbreadcrumb.length; i++) {
if(hiddenbreadcrumb.length >= 3) {
hiddenbreadcrumb[i].style.display = "none";
}
}
to this:
let hiddenbreadcrumb = document.querySelectorAll('.c-breadcrumb-item');
if(hiddenbreadcrumb.length < 3)
return
for (var i = 1; i < hiddenbreadcrumb.length - 1; i++) {
hiddenbreadcrumb[i].style.display = "none";
}
Try this... it allows 3 li items as item1 ... item2ndLast, itemLast
(function () {
"use strict";
function breadcrumb() {
let hiddenbreadcrumb = document.querySelectorAll(".c-breadcrumb-item:nth-child(1n+2)");
if (hiddenbreadcrumb.length <= 3) return;
for (var i = 1; i < hiddenbreadcrumb.length - 1; i++) {
hiddenbreadcrumb[i].style.display = "none";
}
let li = document.createElement("li");
li.className = "c-breadcrumb-item";
let ellipbutton = document.createElement("button");
ellipbutton.type = "button";
ellipbutton.innerHTML = "...";
ellipbutton.className = "c-breadcrumb_btn u-btn-clear";
ellipbutton.onclick = function () {
console.log("clicked");
for (var i = 0; i < hiddenbreadcrumb.length; i++) {
hiddenbreadcrumb[i].style.display = "flex";
}
li.style.display = "none";
};
li.appendChild(ellipbutton);
let container = document.querySelector(".c-breadcrumb-item:first-child");
container.insertAdjacentElement("afterend", li);
}
breadcrumb();
})();

JavaScript I have to click twice to select to element

Please anyone can help to fix the issue with my code, sometimes I have to click twice to select the next elements
var varientbtn = document.getElementsByClassName('clickthisbtn');
for(let i = 0; i < varientbtn.length; i++) {
varientbtn[i].onclick = function () {
const rbs = document.querySelectorAll('input[name="choice"]');
let selectedValue;
let varientSelectedPrice;
for (const rb of rbs) {
if (rb.checked) {
selectedValue = rb.value;
varientSelectedPrice = rb.getAttribute("data-price");
break;
}
}
document.getElementById('log').innerHTML = selectedValue;
document.getElementById('varientprice').innerHTML = varientSelectedPrice;
console.log(selectedValue, varientSelectedPrice);
}
}
Live preview:
https://codepen.io/Elkazi/pen/wvJeErg
That's because when one of labels be clicked, the checked value of related radio still not change.
Try this
const rbs = document.querySelectorAll('input[name="choice"]');
for(let i = 0; i < rbs.length; i++) {
rbs[i].addEventListener('change', function () {
let selectedValue;
let varientSelectedPrice;
for (const rb of rbs) {
if (rb.checked) {
selectedValue = rb.value;
varientSelectedPrice = rb.getAttribute("data-price");
break;
}
}
document.getElementById('log').innerHTML = selectedValue;
document.getElementById('varientprice').innerHTML = varientSelectedPrice;
console.log(selectedValue, varientSelectedPrice);
});
}
rbs[0].dispatchEvent(new Event('change'));
Since you are adding event listener to the label element, you should make use of its for attribute to get the related input field. That way you don't have to run a loop for all inputs and will always get the latest/correct value.
this will point to the element on which the event handler is called.
var varientbtn = document.getElementsByClassName('clickthisbtn');
for(let i = 0; i < varientbtn.length; i++) {
varientbtn[i].onclick = function () {
let relatedInput = document.getElementById(this.getAttribute("for"));
let selectedValue = relatedInput.value;
let varientSelectedPrice = relatedInput.getAttribute("data-price");;
document.getElementById('log').innerHTML = selectedValue;
document.getElementById('varientprice').innerHTML = varientSelectedPrice;
console.log(selectedValue, varientSelectedPrice);
}
}

Trying to create a button with an li and it's not working

I'm trying to make a grocery list app using an array similar to a todo list. I've got it working with an add button, and had a remove button that would remove an item from the list. But now I'm trying to make it so that a remove button is created with each li so that each grocery item can be selectively removed. I gave it a shot but I'm not quite sure what I've done wrong here.
let addButton = document.getElementById('add-button');
addButton.addEventListener('click', add);
let addInput = document.getElementById('add-input');
//let removeButton = document.getElementById('remove-button');
//removeButton.addEventListener('click', remove);
let groceryList = [
]
function add() {
groceryInput = addInput.value;
groceryList.push(groceryInput);
addInput.value = '';
displayGroceries();
}
function remove(event) {
let position = event.currentTarget.id;
groceryList.splice(position, 1);
displayGroceries();
}
function displayGroceries() {
let groceryUl = document.getElementById('grocery-ul');
groceryUl.innerHTML = '';
for (let i = 0; i < groceryList.length; i++) {
let groceryLi = document.createElement('li');
groceryLi.innerHTML = groceryList[i];
groceryUl.appendChild(groceryLi);
}
let removeButton = document.createElement('button');
removeButton.innerText = "Remove";
removeButton.addEventListener('click', remove);
removeButton.id = i;
groceryLi.appendChild(removeButton);
}
<div class="container">
<h1>Grocery List</h1>
<input id="add-input" placeholder="Add Groceries" autocomplete="off">
<button id="add-button">Add</button>
<!--<button id="remove-button">Remove</button>-->
<div>
<ul id="grocery-ul"></ul>
</div>
Its not working as groceryLi.appendChild(removeButton) you are calling outside for loop.
You have defined groceryLi using let and let have a block scope.
Moving code to add button inside resolves issue
Find fixed method for displayGroceries as follows
function displayGroceries() {
let groceryUl = document.getElementById('grocery-ul');
groceryUl.innerHTML = "";
for (let i = 0; i < groceryList.length; i++) {
let groceryLi = document.createElement("li");
groceryLi.innerHTML = groceryList[i];
let removeButton = document.createElement("button");
removeButton.innerText = "Remove";
removeButton.addEventListener("click", remove);
removeButton.id = i;
groceryLi.appendChild(removeButton);
groceryUl.appendChild(groceryLi);
}
}
In your example you are calling on the incrementing value of i outside of the scope of its loop.
You can create the button using the same method you are using to create your list item tag, then add the button to the UL element tag using .insertAdjacentElement('beforeend', removeBtn).
Then you can use a removeEl function that looks at the event.target parentNode and firstChild --> li that will contain the grocery item and its remove button to both remove the element from the DOM and the array.
function removeEl(event) {
event.target.parentNode.remove(event.target)
if (groceryList.includes(event.target.parentNode.firstChild.textContent)) {
let k = groceryList.indexOf(event.target.parentNode.firstChild.textContent);
if (k !== -1) {
groceryList.splice(k, 1);
}
}
displayGroceries();
}
//and the for loop that creates the new elements in displayGroceries()
for (let i = 0; i < groceryList.length; i++) {
let groceryLi = document.createElement('LI');
let removeBtn = document.createElement('BUTTON');
groceryUl.classList.add('flex-display')
removeBtn.textContent = `remove ${groceryList[i]}`;
removeBtn.setAttribute('onclick', `removeEl(event)`)
groceryLi.innerHTML = groceryList[i];
groceryUl.appendChild(groceryLi);
groceryLi.insertAdjacentElement('beforeend', removeBtn);
}
let addButton = document.getElementById('add-button');
addButton.addEventListener('click', add);
let addInput = document.getElementById('add-input');
//let removeButton = document.getElementById('remove-button');
//removeButton.addEventListener('click', remove);
let groceryList = [
]
function add() {
groceryInput = addInput.value;
groceryList.push(groceryInput);
addInput.value = '';
displayGroceries();
}
function removeEl(event) {
//this targets the LI element, parent of the button
event.target.parentNode.remove(event.target)
//event.target.parentNode.firstChild.textContent -> the grocery item
if (groceryList.includes(event.target.parentNode.firstChild.textContent)) {
// get the index
let k = groceryList.indexOf(event.target.parentNode.firstChild.textContent);
if (k !== -1) {
groceryList.splice(k, 1);
}
}
displayGroceries();
}
function displayGroceries() {
let groceryUl = document.getElementById('grocery-ul');
groceryUl.innerHTML = '';
for (let i = 0; i < groceryList.length; i++) {
let groceryLi = document.createElement('LI');
let removeBtn = document.createElement('BUTTON');
groceryUl.classList.add('flex-display')
removeBtn.textContent = `remove ${groceryList[i]}`;
removeBtn.setAttribute('onclick', `removeEl(event)`)
groceryLi.innerHTML = groceryList[i];
groceryUl.appendChild(groceryLi);
groceryLi.insertAdjacentElement('beforeend', removeBtn);
}
}
.flex-display {
display: flex;
align-items: start;
flex-direction: column;
}
li {
list-style: none;
}
button {
margin-left: 1rem;
}
<div class="container">
<h1>Grocery List</h1>
<input id="add-input" placeholder="Add Groceries" autocomplete="off">
<button id="add-button">Add</button>
<!--<button id="remove-button">Remove</button>-->
<div>
<ul id="grocery-ul">
</ul>
</div>

How can I make a function to filter my names into an array list?

I want to make a filter name with an array list but it does not go any way. Can any of you help me?
This is my private project I'm working on
I want to filter out the names when typing in the input file
// List of Names
myList = ["A","B","C","D",];
// declare Var
var ul, li, sortMyNames, input, inputValue;
function getNames() {
// FUNCTION TO SORT NAMES IN A LIST
sortMyNames = sortNames();
// GET INPUT
getInpValue = getInputValue();
// GET UL
ul = document.getElementById("myUL");
for (var i = 0; i < myList.length; i++) {
// CREATE LIST ITEM
li = document.createElement("li");
// SET ITS CONTENTS
li.appendChild(document.createTextNode(myList[i][0]));
txtValue = li.textContent || li.innerText;
if (txtValue.toUpperCase().indexOf(inputValue) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
ul.appendChild(li);
}
return ul;
}
function getInputVaule() {
// GET INPUT
input = document.getElementById("filter-input");
//GET THE VALUE FROM INPUT
inputValue = input.value.toUpperCase();
console.log(inputValue);
}
function sortNames() {
myList.sort();
}
One problem appears to be that you are constantly adding new <li> elements to the <ul>, but are never clearing the <ul> or removing any list items from it.

Categories

Resources