Sorting a html list using JavaScript function - javascript

I´m trying to sort a html list (dropdown menu format that gets filtered as I write something)
dropdown menu list appears when I click on search field
<div class="search-block">
<!--<img class="searchimage" src="https://cdn.glitch.global/4dc88303-8015-467f-9334-2e63fdb63c75/9385963701556258272-16.png?v=1650523566208" alt="search image">-->
<input id="searchbar" type="text" value="" placeholder=" Search" onclick="myFunction();sort()" onkeyup="filterFunction()">
<div id="myDropdown" class="dropdown-content">
<ol id="list1">
<li>New Born</li>
<li>Smash the Cake</li>
<li>Pregnancy</li>
<li>Pre-Wedding</li>
<li>Family</li>
<li>Birthday</li>
<li>Professional</li>
<li>Social Media</li>
</ol>
<!-- TO DO: ADD ITEMS TO THE LIST-->
</div>
<p class="copyright">© 2022 Farias Carril Photography | Designed and built by Daniel Carril</p>
</div>
using JavaScript function.
However, it is not working. What am I missing?
I´m using usual sort algorithm for a simple list
function sort() {
var list, i, switching, shouldSwitch;
div = document.querySelector(".search-block");
a = div.getElementsById("a");
list = document.getElementById("list1");
switching = true;
while (switching)
{
switching = false;
b = list.getElementsByTagName("li");
for (i=0; i<(b.length - 1); i++){
shouldSwitch = false;
if (b[i].innerHTML.toLowerCase() > b[i+1].innerHTML.toLowerCase()){
shouldSwitch = true;
break;
}
}
if (shouldSwitch)
{
b[i].parentNode.insertBefore(b[i+1], b[i]);
switching = true;
}
}
}

I think the first problem is that getElementsById is not a method on the div tag so this causes the script to encounter an error and halt. The second issue is that calling innerHTML on the li tags will return something like New Born, i.e. the result includes the HTML of the a tag inside the li tag. You can change innerHTML to textContent to get the text inside the a tag (alternatively you could grab the a tag and get its innerHTML).
function sort() {
var list, i, switching, shouldSwitch;
div = document.querySelector(".search-block");
// a = div.getElementsById("a");
list = document.getElementById("list1");
switching = true;
while (switching)
{
switching = false;
b = list.getElementsByTagName("li");
for (i=0; i<(b.length - 1); i++){
shouldSwitch = false;
// textContent instead of innerHTML
if (b[i].textContent.toLowerCase() > b[i+1].textContent.toLowerCase()){
shouldSwitch = true;
break;
}
}
if (shouldSwitch)
{
b[i].parentNode.insertBefore(b[i+1], b[i]);
switching = true;
}
}
}
<div class="search-block">
<!--<img class="searchimage" src="https://cdn.glitch.global/4dc88303-8015-467f-9334-2e63fdb63c75/9385963701556258272-16.png?v=1650523566208" alt="search image">-->
<input id="searchbar" type="text" value="" placeholder=" Search" onclick="sort()" onkeyup="">
<div id="myDropdown" class="dropdown-content">
<ol id="list1">
<li>New Born</li>
<li>Smash the Cake</li>
<li>Pregnancy</li>
<li>Pre-Wedding</li>
<li>Family</li>
<li>Birthday</li>
<li>Professional</li>
<li>Social Media</li>
</ol>
<!-- TO DO: ADD ITEMS TO THE LIST-->
</div>
<p class="copyright">© 2022 Farias Carril Photography | Designed and built by Daniel Carril</p>
</div>
innerHTML
textContent

Related

Using JavaScript to add elements to a html multilevel list

I'm working with JavaScript and HTML and I would like to be able to add user input to a multilevel list in HTML. I have started by making a multilevel list in HTML. As an example I have made a list with Dog information.
<div>
<h3> Dogs </h3>
<ul id="myList">
<li><b>Dog Breeds</b>
<ul>
<li class="facts"> There are a approximately 340 recognized breeds.</li>
</ul>
</li>
<li><b>Dog Fur</b>
<ul>
<li class="facts"> Depending on the dogs, there are a lot of different kinds of fur.</li>
</ul>
</li>
</ul>
</div>
Underneath this list I have made 2 fields which can hold userinput and a button next to it which can add the typed in information to the list. My code for the button and type fields is the following:
<input type='text' id='input' placeholder="Title"/>
<button type="button" id="add">Add new dog fact</button><br>
<textarea id="input2" rows="5" cols="18" placeholder="The dog fact.."></textarea>
In order to add the input to the list, I have written this piece of code:
"myList" is the id I have given the unordered list.
document.getElementById("add").onclick = function() {
var title = document.getElementById("input").value;
var description = document.getElementById("input2").value;
var li = document.createElement("li");
li.textContent = title + description;
document.getElementById("myList").appendChild(li);
document.getElementById("input2").value = ""; // clears the value
document.getElementById("input").value = ""; // clears the value
My problem now, is that it will not be structured as I would like.
By using the code above, the output will be as following if I type in "Dog Size" as title and "Dogs can be both large and small." as the description:
Dog SizeDogs can be both large and small.
instead of:
Dog Size
Dogs can be both large and small.
Does anyone know how to change this, so the user input will be structured the same way the rest of the list is? So that the description will be nested within the title? I'm aware that it is because I have defined "li.textContent" as "title + description", I just don't know how else to add the description data. I have tried to create 2 new list elements in the javaScript code, but this just, as expected, creates 2 new list elements and then I tried to style the description-element with "title.style.listStyleType = "none";", but if I place it in the function, then the entire functions stops working. I'm very confused, and if anyone is able to help me I would be very grateful! Thank you :)
use innerHTML and add <br> between title and description.
document.getElementById("add").onclick = function() {
var title = document.getElementById("input").value;
var description = document.getElementById("input2").value;
var li = document.createElement("li");
li.innerHTML = title + "<br>" + description;
document.getElementById("myList").appendChild(li);
document.getElementById("input2").value = "";
document.getElementById("input").value = "";
}
<div>
<h3> Dogs </h3>
<ul id="myList">
<li><b>Dog Breeds</b>
<ul>
<li class="facts"> There are a approximately 340 recognized breeds.</li>
</ul>
</li>
<li><b>Dog Fur</b>
<ul>
<li class="facts"> Depending on the dogs, there are a lot of different kinds of fur.</li>
</ul>
</li>
</ul>
</div>
<input type='text' id='input' placeholder="Title" />
<button type="button" id="add">Add new dog fact</button><br>
<textarea id="input2" rows="5" cols="18" placeholder="The dog fact.."></textarea>
</div>
Instead of using onclick, use addEventListener and if you want to add the description(as ul) under the title, below is the code.
const list = document.querySelector('#myList');
document.querySelector('button#add')
.addEventListener('click', function() {
const title = document.querySelector('#input').value;
const description = document.querySelector('#input2').value;
const li = document.createElement('li');
li.innerHTML = `<b>${title}</b>`;
const ul = document.createElement('ul');
const childli = document.createElement('li');
childli.textContent = description;
ul.appendChild(childli);
li.appendChild(ul);
list.appendChild(li);
});
<div>
<h3> Dogs </h3>
<ul id="myList">
<li><b>Dog Breeds</b>
<ul>
<li class="facts"> There are a approximately 340 recognized breeds.</li>
</ul>
</li>
<li><b>Dog Fur</b>
<ul>
<li class="facts"> Depending on the dogs, there are a lot of different kinds of fur.</li>
</ul>
</li>
</ul>
</div>
<input type='text' id='input' placeholder="Title" />
<button type="button" id="add">Add new dog fact</button><br>
<textarea id="input2" rows="5" cols="18" placeholder="The dog fact.."></textarea>

Sort Parent Elements by criteria of Child Elements with JavaScript and / or TinySort

I have a series of list items in the following structure. I am trying to use Tinysort to sort the list items of the ordered list class="collection-grid editable ui-sortable". The criteria for sorting is the text in double stars below which is the text of div class collection-item-title.
<div id="collection-items" class="collection-items">
<ol class="collection-grid editable ui-sortable">
<li class="collection-item-container track_play_hilite subscriber-item initial-batch active editing">
<div class="collection-title-details">
<a href="https://sts9.bandcamp.com/album/20190907" class="item-link">
<div class="collection-item-title">
**2019.09.07 :: Red Rocks Amphitheatre :: Morrison, CO**
</div>
</a>
</div>
</li>
<li class="collection-item-container track_play_hilite subscriber-item initial-batch active editing">
<div class="collection-title-details">
<a href="https://sts9.bandcamp.com/album/20190906" class="item-link">
<div class="collection-item-title">
**2019.09.06 :: Red Rocks Amphitheatre :: Morrison, CO**
</div>
</a>
</div>
</li>
</ol>
</div>
What I have so far is the following:
tinysort('ol#collection-grid editable ui-sortable>li',{selector:'div.collection-item-title'});
This doesn't seem to work. I am open to any methods that will work an I am not limited to Tinysort.
I was able to use the below function to sort the items correctly.
function sortUsingNestedText(parent, childSelector, keySelector) {
var items = parent.children(childSelector).sort(function(a, b) {
var vA = $(keySelector, a).text();
var vB = $(keySelector, b).text();
return (vA > vB) ? -1 : (vA < vB) ? 1 : 0;
});
parent.append(items);
}
sortUsingNestedText($('.collection-grid'), "li", "div.collection-item-title");

Search on Collapsible contents not working in angular

I have implemented collapsible in my angular application. But those collapsible contents are coming from database service and I am setting those collapsible contents with the help of ngFor as-
<input type="text" name="search" class="form-control" id="myInput" onkeyup="myFAQsSearchFun()" placeholder="Enter your query " >
<div *ngFor="let item of faqs;let i = index;" id="div2">
<button class="accordion" (click)="toggleAccordian($event, i)">
<a style="text-decoration:none;" > {{item.question}}</a>
</button>
<div class="panel" hide="!item.isActive">
<p><br> {{item.answer}} </p>
</div>
<br>
</div>
Collapsible is working fine but the problem is that I want to search those contents based on what I type in search bar. For this I have implemented following code-
function myFAQsSearchFun() {
var input, filter, ul, li, a, i, txtValue;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
ul = document.getElementById("div2");
li = ul.getElementsByTagName("button");
window.alert(li.length);
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("a")[0];
txtValue = a.textContent || a.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
Window.alert is giving output as "1". But ngFor loops for 3 times as I can see 3 collapsibles.
What I am doing wrong. Pls help.
Thanks in advance!
Instead of using document.getElementById("myInput"), use Angular forms to get input.
You will have the data that you have displayed in HTML available in controller, so instead of looping through DOM, you can just filter the Array in the controller itself.
After filtering, just add a flag for each item in the FAQ to hide or show them.
Add ngIF in the HTML based on the above flag.
HTML :
<input [(ngModel)]="model.search" >
<div *ngFor="let item of faqs;let i = index;" >
<div *ngIf="!item.hidden">
<button class="accordion" (click)="toggleAccordian($event, i)">
<a style="text-decoration:none;" > {{item.question}}</a>
</button>
<div class="panel" hide="!item.isActive">
<p><br> {{item.answer}} </p>
</div>
<br>
</div>
</div>
JS:
model = {search: ''};
faqs = [{question:'asf',answer:'asd'}, {question:'asf',answer:'asd'}]
myFAQsSearchFun() {
var input, filter, ul, li, a, i, txtValue;
input = model.search;
filter = input.toUpperCase();
faqs.forEach((faq) => {
if (faq.question.toUpperCase().indexOf(filter) > -1) {
faq.hidden = false;
} else {
faq.hidden = true;
}
});
}

Chosen JavaScript can't click/select on update dynamically

I have a website where I need to filter a list of media types depending on the media family. ie: if print is chosen, it must only show options to do with print, if digital is chosen, it must only show options to do with digital stuff.
I can update the list with new values, but then they are not clickable anymore?
Here are the screenshots:
I am already using: $("#mec_id").trigger("liszt:updated"); where mec_id is the id of the select. Here is the HTML after the media family is chosen, when trying to click on the media type it does not give the option to click/select the option. In the code I have selected print because there is only one value for the dropdown there (to save space in the code).
HTML:
<select id="mec_id" class=" chosen-select" tabindex="-1" multiple="" style="width: 100%; display: none;" data-placeholder="Select Media Type" name="mec_id[]">
<option data-val="12" value="print">print</option>
</select>
<div id="mec_id_chosen" class="chosen-container chosen-container-multi" style="width: 349px;" title="">
<ul class="chosen-choices">
<li class="search-field">
<input class="default" type="text" style="width: 132px;" autocomplete="off" value="Select Media Type" tabindex="8">
</li>
</ul>
<div class="chosen-drop">
<ul class="chosen-results">
<li class="active-result" data-option-array-index="12">print</li>
</ul>
</div>
</div>
JavaScript/JQuery (function of the AJAX Success call):
success: function (data) {
var ul = document.createElement('ul');
ul.className = "chosen-results";
for (var i = 0; i < data.length; i++) {
if (i == 0) {
$('#media_types .chosen-drop').contents().remove();
$('#mec_id').contents().remove();
}
var text = data[i].text;
var li = document.createElement('li');
li.className = "active-result";
li.setAttribute('data-option-array-index', data[i].id);
li.innerHTML = text;
ul.appendChild(li);
// create options
var option = document.createElement('option');
option.setAttribute('data-val', data[i].id);
option.value = data[i].text;
option.text = data[i].text;
document.getElementById("mec_id").appendChild(option);
}
$('#mec_id_chosen .chosen-drop').append(ul);
$("#mec_id").trigger("liszt:updated");
},
Are you sure it's not suppose to be chosen:updated instead of liszt:updated
I don't see any references to liszt - http://harvesthq.github.io/chosen/

I am having a few problems trying to create a jquery live search function for basic data set?

I am designing a simple jquery live search function within a widget on a site i'm developing. I have borrowed some code I found and it is working great. The problem is though that instead of using a list like this:
<ul>
<li>Searchable Item 1</li>
<li>Searchable Item 2</li>
etc
I am using a list like this:
<ul>
<li>
<a href="#">
<div class="something>
<img src="something.jpg">
<p>Searchable Item 1</p>
</div>
</a>
</li>
etc.
As you can see the text I want to search is in the p tag. The functions I have used are searching all the other stuff (a href, div, img) and matching text found in those tags as well as the item within the p tag. Sorry if my explanation is a bit confusing but I will show you an example of the code here:
//includes im using
<script type="text/javascript" src="js/jquery-1.7.min.js" ></script>
<script type="text/javascript" src="js/quicksilver.js"></script>
<script type="text/javascript" src="js/jquery.livesearch.js"></script>
//document ready function
$(document).ready(function() {
$('#q').liveUpdate('#share_list').fo…
});
//actual search text input field
<input class="textInput" name="q" id="q" type="text" />
//part of the <ul> that is being searched
<ul id="share_list">
<li>
<a href="#">
<div class="element"><img src="images/social/propellercom_icon.jpg… />
<p>propeller</p>
</div>
</a>
</li>
<li>
<a href="#">
<div class="element"><img src="images/social/diggcom_icon.jpg" />
<p>Digg</p>
</div>
</a>
</li>
<li>
<a href="#">
<div class="element"><img src="images/social/delicios_icon.jpg" />
<p>delicious</p>
</div>
</a>
</li>
</ul>
also here is the jquery.livesearch.js file I am using
jQuery.fn.liveUpdate = function(list){
list = jQuery(list);
if ( list.length ) {
var rows = list.children('li'),
cache = rows.map(function(){
return this.innerHTML.toLowerCase();
});
this
.keyup(filter).keyup()
.parents('form').submit(function(){
return false;
});
}
return this;
function filter(){
var term = jQuery.trim( jQuery(this).val().toLowerCase() ), scores = [];
if ( !term ) {
rows.show();
} else {
rows.hide();
cache.each(function(i){
var score = this.score(term);
if (score > 0) { scores.push([score, i]); }
});
jQuery.each(scores.sort(function(a, b){return b[0] - a[0];}), function(){
jQuery(rows[ this[1] ]).show();
});
}
}
};
I believe the problem lies here:
var rows = list.children('li'),
cache = rows.map(function(){
return this.innerHTML.toLowerCase();
});
it is just using whatever it finds between the li tags as the search term to compare against the string entered into the text input field. The search function actually does work but seems to find too many matches and is not specific as I am also using a quicksilver.js search function that matches terms that are similar according to a score. When I delete all the other stuff from the li list (a href, img, div, etc) the search function works perfectly. If anyone has any solution to this I would be really greatful, I have tried things like:
return this.children('p').innerHTML but it doesn't work, I'm ok with PHP, C++, C# etc but totally useless with javascript and Jquery, they're like foreign languages to me!
In the jquery.livesearch.js file I believe you can replace this line:
var rows = list.children('li'),
with:
var rows = list.children('li').find('p'),
This should make it so the livesearch plugin will only search the paragraph tags in your list.
You will need to change the .show()/.hide() lines to reflect that you are trying to show the parent <li> elements since you are now selecting the child <p> elements:
Change:
rows.show();//1
rows.hide();//2
jQuery(rows[ this[1] ]).show();//3
To:
rows.parents('li:first').show();//1
rows.parents('li:first').hide();//2
jQuery(rows[ this[1] ]).parents('li').show();//3

Categories

Resources