Flipping with navigation keys divs that are :checked in input - javascript

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');
}
}
});
});

Related

If container has children of a certain class

I'm working on a live search function, but I need to hide any containers that do not have a match.
This is a sample of how the containers are populated if nothing is entered in the search bar. EDIT: This will be identical even if there is a string in the search bar. fadeOut() hides the element, doesn't remove it.
<div id="Alabama_container" class="state-container">
<h1>Alabama</h1>
<div id="330_store-object" class="store-object" style="">
<h4>Store 330 - Birmingham</h4>
<p>(205) 981-1320</p>
<p>5201 US-280, Birmingham, AL 35242, USA</p>
<button id="330_store-object-link" class="button">View on Map</button><button id="330_store-object-floorPlan" class="button">Floorplans</button>
</div>
<div id="337_store-object" class="store-object" style="">
<h4>Store 337 - Dothan</h4>
<p>(334) 671-1370</p>
<p>4401 Montgomery Hwy #300, Dothan, AL 36303, USA</p>
<button id="337_store-object-link" class="button">View on Map</button><button id="337_store-object-floorPlan" class="button">Floorplans</button>
</div>
</div>
The state-container elements are generated on the DOM first then store-object elements are appended to the appropriately named state-container.
Search Function Sample:
$(document).ready(function () {
$("#store-search").keyup(function () {
var filter = $(this).val(),
count = 0;
$(".store-object").each(function () {
// If the store object doesn't match, remove it
if ($(this).text().search(new RegExp(filter, "i")) < 0) {
$(this).fadeOut();
// Show the store objects that do match the query
} else {
$(this).show();
count++;
}
});
// Results counter for troubleshooting
var numberItems = count;
$("#filter-count").text(count + "Results Founds");
});
});
My search function simply uses filter to determine any matching strings within the store-object elements and hides any that don't match. However, the matches still reside in their state-container so what you end up with is a list of states without any results inside.
What I want to do is loop through state-container elements and determine if it contains any store-object children so I can handle it appropriately. What would I use to achieve this?
There are several different ways to achieve what you want. One of which would be using the :visible selector and then hiding the state-container on an empty set.
$('.state-container').each(function(){
if($(this).find('.store-object:visible').length === 0){
$(this).hide();
}
});
Keep in mind, you'll need to run that after all of the children's fadeOut animations have completed.
Another approach would be to keep a tally of the hidden elements as you go through the search, and if all children were hidden remove the parent.
$(document).ready(function () {
$('.state-container').each(function(){
$(this).data('total', $(this).find('.store-object').length);//set a count of total
});
$("#store-search").keyup(function () {
var filter = $(this).val(),
count = 0;
//reset the hidden count for the states
$('.state-container').each(function(){
$(this).data('hidden', 0);//initialize to 0
$(this).show();
});
$(".store-object").each(function () {
var parent = $(this).parent();
// If the store object doesn't match, remove it
if ($(this).text().search(new RegExp(filter, "i")) < 0) {
$(this).fadeOut();
parent.data('hidden', parent.data('hidden') + 1);//increment hidden count
// Show the store objects that do match the query
} else {
$(this).show();
count++;
}
if(parent.data('hidden') == parent.data('total')){
parent.hide();
}
});
// Results counter for troubleshooting
var numberItems = count;
$("#filter-count").text(count + "Results Founds");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id='store-search' />
<div id="Alabama_container" class="state-container">
<h1>Alabama</h1>
<div id="330_store-object" class="store-object" style="">
<h4>Store 330 - Birmingham</h4>
<p>(205) 981-1320</p>
<p>5201 US-280, Birmingham, AL 35242, USA</p>
<button id="330_store-object-link" class="button">View on Map</button><button id="330_store-object-floorPlan" class="button">Floorplans</button>
</div>
<div id="337_store-object" class="store-object" style="">
<h4>Store 337 - Dothan</h4>
<p>(334) 671-1370</p>
<p>4401 Montgomery Hwy #300, Dothan, AL 36303, USA</p>
<button id="337_store-object-link" class="button">View on Map</button><button id="337_store-object-floorPlan" class="button">Floorplans</button>
</div>
</div>
You can check if store-container has store-object and then only loop through them like:
$(".store-container").find(".store-object").length &&
$(".store-object").each(function () {
After your edit, I could say that you should check for visible length like:
$(".state-container").find(".store-object:visible").length &&
But, I would still say that you don't need to check anything because you're already checking for the condition that if it's visible then only fadeOut. That is, even if this is hidden, there's nothing problem using fadeOut. But what I can say is that you can pause the search execution:
setTimeout(()=>{
// your each function
}, 600);

Show/Hide objects by attribute in HTML list

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();
}
});

How to update all values in an array? -JS/Jquery

I'm trying to update an array when clicking on the li tag. I've been testing, testing, and unable to come up with a solution.
I have two tabs: The "Create" tab opens a container that allows you to insert paragraphs, the "Home" tab opens another container containing a "Select paragraph" button.
Problem
It won't update the values of the array when I do it for the second time. I.e., if I switch between the tabs and go on select mode again to select/deselect, it will not update the new selection, instead I get the same selection from the first time.
I've created an example so you can look at it and if there is a better way to accomplish this (which I know there is) then be my guest. Link is below the next paragraph.
Instructions
In order to select a paragraph, first you need to add a paragraph which is created on the fly, then you switch to "Home" section, click on the "Select paragraph" button, this takes you to the "Create" section on select mode. To select/deselect, click on any paragraph. When you select a paragraph, it stores its position using jQuery - index() in the "storeClass" array. Once you're done selecting paragraphs then you exit the select mode by clicking "Ok" button and it switches to "Home" section, but let's say you want to create another paragraph then you click on "Create" tab, create the paragraph, switch to "Home" tab, go on select mode and select again and switch between tabs and you will see just the first selection you made on the first time.
Here is the same example: http://jsfiddle.net/7mbhnvas/8/
HTML
<ul class="tab">
<li><a class="paragraph-tab">Create</a></li>
<li><a class="select-tab">Home</a></li>
</ul>
<div class="wrap">
<div class="create-para-cont">
<h3>Create a paragraph</h3>
<ul class="para-results">
</ul>
<div class="para-tool">
<p><textarea class="textarea"></textarea></p>
<button type="button" class="create-para-button">Create paragraph</button>
<div>
<button type="button" class="select-ok-button">OK</button>
</div>
</div>
</div>
<div class="select-para-cont">
<h3>Select Mode</h3>
<p><button type="button" class="select-para-button">Select paragraph</button></p>
</div>
</div>
jQuery
$('ul.tab li a:first').addClass('tab-active');
$('.create-para-cont').addClass('cont-active');
$('.create-para-button').on('click', function(){
$('.create-para-cont').addClass('cont-active');
var parent = $('.para-results');
var child = $('<li></li>');
var p = $('<p></p>');
var textarea = $('.textarea').val();
if($('.create-para-cont').hasClass('cont-active')){
p.text(textarea);
child.append(p);
parent.append(child);
} else {
return false
}
});
var storeClass = [];
$('.select-para-button').on('click', function(){
$('.create-para-cont').addClass('cont-select');
if($('.para-results li').length >= 1){
$('.textarea, .create-para-button').hide();
$('.select-para-cont').hide();
$('.select-tab').removeClass('tab-active');
$('.create-para-cont').show();
$('.paragraph-tab').addClass('tab-active');
$('.select-ok-button').show();
for ( var i = 0; i < storeClass.length; i = i + 1 ) {
$('.para-results').each(function( index ) {
$( this ).find( "li:eq("+ storeClass[ i ] +")" ).addClass('p-selected');
});
}
}
});
$('ul.tab li').on('click','a', function(){
if($(this).hasClass('paragraph-tab')){
$('.para-results').children('li').removeClass('p-selected');
$('.select-para-cont').hide();
$('.select-tab').removeClass('tab-active');
$('.create-para-cont').show();
$('.paragraph-tab').addClass('tab-active');
} else {
$('.create-para-cont').removeClass('cont-active');
$('.create-para-cont').hide();
$('.paragraph-tab').removeClass('tab-active');
$('.select-para-cont').show();
$('.select-tab').addClass('tab-active');
}
});
$('ul.para-results').on('click','li', function(){
if($('.create-para-cont').hasClass('cont-select')){
$(this).toggleClass('p-selected');
var selected = $('.p-selected ');
var pSelected = selected.parent().children().index(this);
storeClass.push( pSelected );
} else {
return false;
}
});
$('.select-ok-button').on('click', function(){
if($('.create-para-cont').hasClass('cont-select')){
$('.create-para-cont').removeClass('cont-select');
$('.create-para-cont').removeClass('cont-active');
$('.create-para-cont').hide();
$('.paragraph-tab').removeClass('tab-active');
$('.select-para-cont').show();
$('.select-tab').addClass('tab-active');
}
});
I would reset storeClass to a blank array when the 'OK' button is clicked, and then re-push all the correct values into it in that same click handler:
$('.select-ok-button').on('click', function(){
if($('.create-para-cont').hasClass('cont-select')) {
storeClass = []; // make it blank
$('.p-selected').each(function() {
storeClass.push($(this).index()); // push each one into the array
});
....
}
});
Then your click handler of ul.para-results would look like this:
$('ul.para-results').on('click','li', function(){
if($('.create-para-cont').hasClass('cont-select')){
$(this).toggleClass('p-selected');
} else {
return false;
}
});
Here's an updated Fiddle

Javascript Loop Show hide elements in document (Jquery OK too)

I have a redundant process for making div's visible / hidden and I believe the way to make it more efficient is to use a loop.
Currently I have numerous div's through the document but there are 6 in particular that I want to deal with. I have a series of buttons that correspond to the six div's. When person clicks button A I want to show (make visible) div A and hide Div's B,C,D,E,F. My javascript is something like this:
<a href="#" onclick="ShowMe('A'); return false" />
<a href="#" onclick="ShowMe('B'); return false" />
<a href......etc />
<div id="A">blah...blah</div>
<div id="B">blah...blah</div>
<script type="java....">
function ShowHideDiv(DivName)
{
if(DivName == 'A')
{
var diva = document.getElementById('A');
div.style.visibility = 'visible';
var divb = document.getElementById('B');
div.style.visibility = 'hidden';
etc....
}
else if (DivName == 'B')
{
var diva = document.getElementById('A');
div.style.visibility = 'hidden';
var divb = document.getElementById('B');
div.style.visibility = 'visible';
etc...............
}
}
</script>
So as mentioned a prime candidate for loop but my question is how to contain the loop. For example if my loop went through the entire document object then I would have divs that I want visible being hidden so how do I avoid this?
I had two thought but was if others had additional thoughts, ideas, techniques etc.
Give my divs a really oddball prefix to their name like ShowHide_A then my loop can go through all the divs in the document object, parse it's name, if it doesn't have the prefix then move to the next one. This of course would be very inefficient if we had a large document and the script was getting every object and parsing then checking the name.
Wrap the div's in question in a parent container such as:
Then my javascript could be contained to looping through just the DivParent tree. But what if my div's are at different places in the document model? Do I keep them in the ParentDiv and position then where they belong with with css position properties?
Any other ideas would be greatly appreciated
JB
Let me suggest a better approach.
If you can use jQuery, you can do the following:
Assign a class (e.g. box) to all of your divs. Then your button needs to call this function:
function toggleDiv (divID) {
$(".box").hide();
$("#"+divID).show();
}
What you can also do is assign e.g. data-div attribute to your button which contains the ID of the div to hide/show, and then you can transform the above to the following (assuming your buttons have the button class):
$(".button").click(function () {
var divID = $(this).attr("data-div");
$(".box").hide();
$("#"+divID).show();
});
The above covers everything, assigning events to the buttons and hiding/showing divs.
see suppose you have markup like this
<div id="A" class="marked" >A</div>
<div id="B" class="marked" >B</div>
<div id="C" class="marked" >C</div>
<div id="D" class="marked" >D</div>
<div id="E" class="marked" >E</div>
<input type="button" value="Show A" data-target-div="A" />
<input type="button" value="Show B" data-target-div="B" />
then add a script like this:
$('input[type=button]').click(function(){
$('.marked').hide(200);
$('#'+$(this).data('target-div')).show();
});
it should work.
see this fiddle
so, you are not iterating through all the dom elements, you are picking exactly the ones you need to deal with. upon click, you hide all of them, and show the one which is target i.e. data-target-div
jQuery based solution:
Add a class to your div's that allow hiding/showing and then do
function ShowHideDiv(DivName)
{
$(".ShowHide").not("#" + DivName).hide();
$("#" + DivName).show();
}
Add class='switchable' (or whatever) to each such DIV then using prototype.js you could do something like this
function showMe( elem ) {
$$( '.switchable' ).each( function( switchable ) {
if ( switchable.id == $(elem).id )
switchable.show();
else
switchable.hide();
} );
}

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