Show/Hide objects by attribute in HTML list - javascript

For example, I have checkbox that can be checked or unchecked.
Whenever it is checked, I want all the elements in the HTML list to be displayed.
Whenever it is not checked, I want just some objects (that are not filtered) to be displayed, like others don't exist (I don't want white spaces etc).
The HTML (Handlebars) list:
<ol>
{{#each personList}}
<li>{{showPerson this}}</li>
{{/each}}
</ol>
Handlebars helper:
Handlebars.registerHelper('showPerson', function(person) {
return person.firstName + " " + person.lastName;
});
My filtering function looks like this:
function filterOldPeople(person) {
return person.age > 60;
}
The thing I want to achieve is something like this:
var filter; // I am getting this boolean value from checkbox
if (filter) {
doFilter(); // will filter the HTML list that is already rendered
}
Now I don't know how the function doFilter() should look like to achieve this. Now with jQuery the problem is I can get the HTML object of list item but not the actual person object so this won't work:
$( "li" ).filter(filterOldPeople).addClass("hide");
And something like that is exactly what I need. How do I achieve this?

Here you go! Only thing you want to do is to place all elements you want to hide in one div and then hide it, it is alot of easier to hide one element than couple of them.
function check() {
if (document.getElementById("test").checked == true) {
document.getElementById("two").style.display = "none";
} else {
document.getElementById("two").style.display = "block";
}
}
<div class="info">
<div id="one">
If you click on me, #two will hide.
<input type="radio" id="test" onclick="check()">
</div>
<div id="two">
Hi, click on the button!
</div>
</div>

If you don't want to use two lists, you could modify using something like the following (add code to function as needed):
HTML
<ul id="theList">
<li class="number">One</li>
<li>Red</li>
<li class="number">Two</li>
<li>Green</li>
<li class="number">Three</li>
<li>Blue</li>
</ul>
<br /><input type="checkbox" id="numbers" checked><label for="numbers">Show Numbers</label>
JS
$('#numbers').change(function() {
$('.number').hide();
});
https://jsfiddle.net/1ngotz5u/

How I would approach this would be:
function filterOldPeople(person) {
return person.age > 60;
}
// Get all li Elements (useful so we don't have to search the dom multiple times)
var liElements = $("li");
// loop through each li and filter it.
function filterAges() {
liElements.each(function () {
if (filterOldPeople($(this).val())) {
$(this).addClass("hide");
}
});
}
// Show all hidden elements by removing the hide class
function showAll() {
liElements.removeClass("hide");
}
// Create our event
$("#checkbox").change(function () {
if ($(this).is(":checked")) {
filterAges();
} else {
showAll();
}
});

Related

How to unificare function (connect 3 functions into 1)

I Would like to merge 3 functions into 1, because I feel like it is possible, but I have no idea how to make it correctly
Here is my solutuion. I do not understand why it only hides location-type2 and does not show it.
I have really no idea what is wrong here, because it hides things correctly, it just does not show them at all.
Also, here is my HTML. I am catching value from "data-value" and using this I am trying to merge this functions, but it does not work.
$("#check3, #check2, #check1").click(function () {
console.log($(this).data("value"));
if ($(this).data("value") === 1) {
if ($("#check1").checked) {
$(".location-type1").removeClass("display-none");
}
else {
$(".location-type1").addClass("display-none");
}
}
else if ($(this).data("value") === 2) {
if ($("#check2").checked) {
$(".location-type2").removeClass("display-none");
}
else {
$(".location-type2").addClass("display-none");
}
}
else {
if ($("#check3").checked) {
$(".location-type3").removeClass("display-none");
}
else {
$(".location-type3").addClass("display-none");
}
}
});
I would like to have this 3 functiones being merged:
$("#check1").click(function(){
if (document.getElementById('check1').checked)
{
$(".location-type1").removeClass("display-none")
}
else {
$(".location-type1").addClass("display-none");
}
});
$("#check2").click(function(){
if (document.getElementById('check2').checked)
{
$(".location-type2").removeClass("display-none")
}
else {
$(".location-type2").addClass("display-none");
}
$("#check3").click(function(){
if (document.getElementById('check3').checked)
{
$(".location-type3").removeClass("display-none")
}
else {
$(".location-type3").addClass("display-none");
}
});
<div class="form-group"> <input type="checkbox" style="display: none" id="check1" data-value="1" checked> <label for="check1">Restauracja</label> </div>
<div class="shop-position location-type1" data-lat="52.4068200" data-lng="16.9299300" data-type="1">
<div class="location-text">
<strong>Vininova1</strong>
<div>Podgórna 14</div>
<div>Poznań</div>
Pokaż na mapie
</div>
</div>
Anytime you find yourself writing the same or very similar code that you've already written, you should stop and think about how to re-write it to be more loosely coupled and therefore more usable. In your case, we really only need one function with a single statement in it.
Also, input elements already have a value attribute, so it's redundant to add a data-value to them.
Additionally, don't use inline styles if you can avoid it. They cause duplication of code and make the code more difficult to read and scale. Instead, use CSS classes.
// Get the checkboxes into a JQuery wrapped set
let inputs = $("#parent input[type='checkbox']");
// Set the event handler up on the parent of the 3 checkboxes
$("#parent").on("click", function (event) {
if(event.target.nodeName === "INPUT"){
// Get the actual checkbox that was clicked with: event.target
// Get the index of the clicked checkbox within the set
// Toggle the use of the class on the location item that corresponds to the index of the clicked checkbox(es)
$("#locations div")[$("#parent input[type='checkbox']").index(event.target)].classList.toggle("display-none");
}
});
.display-none {
display:none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="parent">
<input type="checkbox" value="one">One<br>
<input type="checkbox" value="two">Two<br>
<input type="checkbox" value="three">Three
</div>
<div id="locations">
<div class=".location-type1 display-none">Location 1</div>
<div class=".location-type2 display-none">Location 2</div>
<div class=".location-type3 display-none">Location 3</div>
</div>
Use switch.
If you were using only data("value"), switch would be by this value:
switch(data("value")) {
case...
}
But in your case checks are different. Then:
switch(true) {
case data("value") === 2:
....
case document.getElementById('check3').checked:
....
}

one function to fire on same class elements click

I'm trying to make controls for category list with sub-category and sub-sub-category lists.
Here's HTML:
<ul class="selectbox-ul">
<li>
<div>Category</div>
<ul class="selectbox-ul-child">
<li>
<div>Subcategory</div>
<ul class="selectbox-ul-child">
<li>
<div>Sub-subcategory</div>
</li>
</ul>
<span id="trigger">icon</span>
</li>
</ul>
<span id="trigger">icon</span>
</li>
....
</ul>
So my shot was to add class for ul.selectbox-ul-child :
var trigger = document.getElementById("trigger");
function subCatStatus() {
if(this.parentElement.children[1].className != "... expanded") {
this.parentElement.children[1].className += " expanded"
} else {
this.parentElement.children[1].className == "..."
};
};
trigger.addEventListener("click", subCatStatus);
And it works only for first span#trigger(that shows subcategories), next one (for sub-subcategories) does nothing (I've also tried to use .getElementsByClassName it didn't work for any of triggers) . So i'd like to get some explanation why doesn't this one work. And some advice how to make it work.
As others have already mentioned, you can't stack multiple elements with the same ID since document.getElementById() is not supposed to return more than one value.
You may try instead to assign the "trigger" class to each of those spans instead of IDs and then try the following code
var triggers = document.getElementsByClassName("trigger");
function subCatStatus() {
if(this.parentElement.children[1].className != "... expanded") {
this.parentElement.children[1].className += " expanded"
} else {
this.parentElement.children[1].className == "..."
};
};
for(var i = 0; i < triggers.length; i++) {
triggers[i].addEventListener("click", subCatStatus);
}
javascript getElementById returns only single element so it will only work with your first found element with the ID.
getElementsByClassName returns an array of found elements with the same class, so when adding listener to the event on element you would require to loop through this array and add individually to it.

Flipping with navigation keys divs that are :checked in input

I need the next & previous buttons to navigate through the divs that was selected in checkboxes. That means that user selects several options press the start button and do some actions in first selected option, then he press next and navigates to next div and again do some actions.
$(document).ready(function () {
$('#roomsubmit').click(function () {
$(".room").hide();
if ($("#node").is(':checked')) {
$("#hallway").show();
$("#hallway").addClass("roomNew");
} else if ($("#node-2").is(':checked')) {
$("#livingroom").show();
$("#livingroom").addClass("roomNew");
} else if ($("#node-3").is(':checked')) {
$("#bedroom").show();
$("#bedroom").addClass("roomNew");
} else if ($("#node-4").is(':checked')) {
$("#playroom").show();
$("#playroom").addClass("roomNew");
}
});
$(function () {
$(".swap").on({
click: function () {
var parent = $(this).closest('.roomNew');
parent.css('display', 'none');
if (this.id == 'previousBtn') {
parent.prev('.roomNew').css('display', 'block');
} else {
parent.next('.roomNew').css('display', 'block');
}
}
});
});
});
.room {
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<label for="node">Hallway
<input type="checkbox" id="node" />
</label>
<label for="node-2">Livingroom
<input type="checkbox" id="node-2" />
</label>
<label for="node-3">Bedroom
<input type="checkbox" id="node-3" />
</label>
<label for="node-4">Playroom
<input type="checkbox" id="node-4" />
</label>
<button id="roomsubmit">Start calculation</button>
<div id="hallway" class="room">Works in hallway
<button class="swap previousBtn" id="previousBtn">prev</button>
<button class="swap nextBtn" id="nextBtn">next</button>
</div>
<div id="livingroom" class="room">Works in livingroom
<button class="swap previousBtn" id="previousBtn">prev</button>
<button class="swap nextBtn" id="nextBtn">next</button>
</div>
<div id="bedroom" class="room">Works in bedrrom
<button class="swap previousBtn" id="previousBtn">prev</button>
<button class="swap nextBtn" id="nextBtn">next</button>
</div>
<div id="playroom" class="room">Works in playroom
<button class="swap previousBtn" id="previousBtn">prev</button>
<button class="swap nextBtn" id="nextBtn">next</button>
</div>
jsfiddle for the above code
I have something for you, Roby. Sorry for delay - had to work it out.
jsFiddle Demo
First, there are now two arrays: arrRooms (an array of objects which map the nodename to the room), and newRooms (an array to store checkmarked rooms - poor name, but oh well).
The arrRooms array is used to get the room name when given the node. This eliminated all those if-else lines.
A new function $('input:checkbox').click was created to add/remove the checked/unchecked nodes from the newRooms array. This leaves you with an array containing just the checked rooms.
Next, the #roomsubmit.click function was simplified to use the above arrays. All it does now is (1) grab the first item in the newRooms array (the checked rooms) (2) display that room's DIV, and (3) remove that item from the newRooms array. This creates a "cafeteria plate" scenario where each time you click #roomsubmit ("Start Calculation" button), the next checked room is displayed.
Important: Note that you have several elements with the same ID (id="nextBtn" and id="previousBtn"). Not allowed, I'm afraid. Every ID must be completely unique in the DOM. However, there is no need to use IDs at all since they are not referenced in the code at the moment. The jQuery selector uses the class, so just delete the ID attributes from the HTML.
By the way, to make the previous button work, you can modify your swap function to work with the above, or else change your approach completely and just create another empty array and when you delete a room from the newRooms[] array, add it into the prevRooms[] array. When the previous button is clicked, grab the room-to-display from the prevRooms[] array, delete it from there, and stick it back into the newRooms[] array. You will work it out... (In fact, you may need three variables: prevRooms array, currRoom var, and newRooms array --- put some legos on a desk to represent the checked rooms, and use three circles to represent the three arrays - and imagine clicking the next/prev buttons and moving the curr room lego from one pile into the next, and you'll quickly work out how to do this.)
javascript/jQuery code:
var tmp;
var arrRooms={'node':'hallway','node-2':'livingroom','node-3':'bedroom','node-4':'playroom','node-5':'cabinet','node-6':'kitchen','node-7':'bathroom','node-8':'wc'};
var newRooms=[];
$('input:checkbox').click(function(){
if ($(this).is(':checked')) {
newRooms.push(this.id);
//alert( JSON.stringify(newRooms) );
}else{
newRooms.splice(newRooms.indexOf(this.id),1); //delete from newRooms
//alert( JSON.stringify(newRooms) );
}
});
$('#roomsubmit').click(function () {
$(".room").hide();
tmp = arrRooms[newRooms[0]];
//alert('tmp = ' +tmp);
$('#' +tmp).addClass('roomNew').show();
newRooms.splice(0,1);
//alert( JSON.stringify(newRooms) );
});
$('.nextBtn').click(function(){
$('#roomsubmit').click();
});
$(function () {
$(".swap").on({
click: function () {
var parent = $(this).closest('.roomNew');
parent.css('display', 'none');
if (this.id == 'previousBtn') {
parent.prev('.roomNew').css('display', 'block');
} else {
parent.next('.roomNew').css('display', 'block');
}
}
});
});

Modify this function to remove values if they're unchecked

I'm using this function with an unordered list (<ul>) in order to replicate the functionality of a Select dropdown element. The function correctly shows the user's selected values in the designated container when they are checked, but it isn't removing them when an item is unchecked.
I've included the relevant snippet below, and posted a working example with the complete code here: http://jsfiddle.net/chayacooper/GS8dM/7/
JS
$(document).ready(function () {
$(".dropdown_box").click(function () {
$("#select_colors").show();
});
$(".dropdown_container ul li").click(function () {
var text = $(this.children[0]).find("input").val();
var currentHtml = $(".dropdown_box span").html();
$(".dropdown_box span").html(currentHtml.replace('Colors', ''));
$(".dropdown_box span").append(', ' + text);
});
});
HTML
<div class="dropdown_box"><span>Colors</span></div>
<div class="dropdown_container">
<ul id="select_colors">
<li><label><input type="checkbox" name="color[]" value="Black" />Black</label></li>
</ul>
</div>
You should give the container id to the function. Then, before you add the text of the selection, you should make sure that it is not in the text. If it is, delete it.

How to display search results onkeyup?

I have a search box that as the user types letters into the search box, we will filter and display the results. However, as the user types each letter the search results are getting toggled between showing and hiding. I am very new to JS so I hope it could be an easy fix.
Here is my HTML:
See Below
Here is my toggle JS:
See Below
How can I tweak the JS to not toggle back and forth?
//Here are my edits to help answer the question. This is the JS and HTML I am using to display the results:
HTML:
<div class="friendssearch" onclick="toggle_visibility('friendslist');">
<div class="friendssearch">
<div id="friendssearchbox"></div>
</div>
<ul id="friendslist" style="display: none;">
<li>
<a href="#">
<div class="friendsflybox" title="Friends Name">
<p class="friendsflyboxname">Ryan Bennett</p>
</div>
</a>
</li>
</ul>
</div>
Javascript:
<script>
(function ($) {
// custom css expression for a case-insensitive contains()
jQuery.expr[':'].Contains = function(a,i,m){
return (a.textContent || a.innerText ||
"").toUpperCase().indexOf(m[3].toUpperCase())>=0;
};
function listFilter(header, list) { // header is any element, list is an unordered list
// create and add the filter form to the header
var form = $("<form>").attr({"class":"filterform","action":"#"}),
input = $("<input>").attr({"class":"filterinput clearFieldBlurred
ClearField","type":"text", "value":"Start typing a Name"});
$(form).append(input).appendTo(header);
$(document).ready(function() {
$('.clearField').clearField();
});
$(input)
.change( function () {
var filter = $(this).val();
if(filter) {
// this finds all links in a list that contain the input,
// and hide the ones not containing the input while showing the ones that do
$(list).find("a:not(:Contains(" + filter + "))").parent().slideUp();
$(list).find("a:Contains(" + filter + ")").parent().slideDown();
} else {
$(list).find("li").slideDown();
}
return false;
})
.keyup( function () {
// fire the above change event after every letter
$(this).change();
});
}
//ondomready
$(function () {
listFilter($("#friendssearchbox"), $("#friendslist"));
});
}(jQuery));
</script>
You'll need to do something similar to the code I have posted below. This assumes that you can access the object that contains the search results.
function toggle_visibility(id)
{
//Check if there are any search results to display
var searchResultLength = document.getElementById(searchResultID).innerHTML.length;
if (searchResultLength > 0) // display div
{
var e = document.getElementById(id);
e.style.display = 'block';
}
else //No search results, hide div
{
e.style.display = 'none';
}
}
Basically, you need to determine if you have search results to display before you attempt to toggle the div's visibility.
//EDIT AFTER COMMENTS
OK, so it looks like the results are adding li's to the ul. So, assuming that the code is taking away the li's as well as adding them, you should be checking for the number of elements in the ul == 0. See below.
$('#friendslist > li').length
To be honest, I'm having a bit of difficulty trying to determine exaclty what the code is
doing. I'm certainly not a jquery expert. I would say if the above code doesn't get you going in the right direction, I'm out of ideas.
If you're only wanting it to display when you enter the field use the onFocus="method()" attribute. followed by onBlur="method()". this will display the block when you enter the field and hide it when you leave.
<input id="searchbox" type="text" onFocus="toggle_visibility('friendslist');" onBlur="toggle_visibility('friendslist')">
<ul id="friendslist" style="display: none;">
<!--search results HTML-->
</ul>
teach a man to fish: http://www.w3schools.com/jsref/dom_obj_event.asp
// EDIT
I think Quickfire's answer is the best solution. but as I understand it you want you results to show/hide, so I modified his method to better suit your markup.
function toggle_visibility(id){
//Get the total number of <li> within my search result
var results=document.getElementById(searchResultID).childNodes.length;
if (results > 0){ // we have more than 0 results
var e = document.getElementById(id);
e.style.display = 'block'; // show the element
}else{ //No search results, hide div
e.style.display = 'none'; //hide the element
}
}

Categories