Why is my if else statement not working? jquery - javascript

I have an if else statement that is supposed to hide/show list items when other list items are appended/removed. It only works if I put the if else statement after the #delete-square function but it only works for one list item. Here is my fiddle: http://jsfiddle.net/matty91/zqmps11b/6/
This is probably really simple to do but I don't know javascript/jquery that well.
Example: So for every blue square that is added, take away a green square. There should always be 4 squares present. (if I have 2 blue I should have 2 green. If I have 4 blue then I should have no green. The user should be able to add as many blue squares as he wants but if the blue squares go below 3 then add 1 green) Hopefully that makes sense :)
Let me know if I need to explain a bit more for what I'm trying to accomplish!
Thanks in advance!
$(document).ready(function(){
if ($("ul.db-view-list li .quad #chart_div").length == 1){
$("li.ph:last-child").hide();
} else if($("ul.db-view-list li .quad #chart_div").length == 2){
$("li.ph:nth-child(2)").hide();
} else if($("ul.db-view-list li .quad #chart_div").length == 3){
$("li.ph:nth-child(1)").hide();
} else if($("ul.db-view-list li .quad #chart_div").length >= 4){
$("li.ph:first-child").hide();
} else {
$("li.ph").show();
};
$(".add-square").click(function(){
$(".db-view-list").prepend("<li><button id='delete-square'>X</button><div class='quad'><div id='chart_div'></div></div></li>");
$(document).on('click', '#delete-square', function(){
$(this).parent().remove();
});
});
});
.db-view-list{
padding: 0px;
margin: 0px;
height: 300px;
}
.db-view-list li{
padding:0px;
list-style-type: none;
}
.quad{
width: 100px;
height: 100px;
float: left;
}
.default-message{
background-color: green;
border: solid 1px white;
width: 100%;
height: 100%;
margin:0px;
padding: 0px;
}
#chart_div{
width: 100%;
height: 100%;
background-color: blue;
border: solid 1px white;
}
#delete-square{
position:absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="db-view-list">
<li class="ph">
<div class="quad">
<p class="default-message">
click add square to add a graph first
</p>
</div>
</li>
<li class="ph">
<div class="quad">
<p class="default-message">
click add square to add a graph 2
</p>
</div>
</li>
<li class="ph">
<div class="quad">
<p class="default-message">
click add square to add a graph 3
</p>
</div>
</li>
<li class="ph">
<div class="quad">
<p class="default-message">
click add square to add a graph last
</p>
</div>
</li>
</ul>
<button class="add-square">
add square
</button>

http://jsfiddle.net/zqmps11b/28/
Keep in mind the CSS is changed as well to accommodate Classes instead of IDs.
Your if statements were setup to only be checked on document.ready which only occurs once. This should work:
var numOfNewBoxes = 0;
// declare variable to count new boxes.
$(document).ready(function () {
// the if/else statement should be removed from the document.ready function
//You're not reloading the page every time you tap the 'add square button
//change the ids to classes because there should only be 1 instance of each ID.
$(".add-square").click(function () {
$(".db-view-list").prepend("<li><button class='delete-square'>X</button><div class='quad'><div class='chart_div'></div></div></li>");
//hide the last of the original boxes that are visible
$('.default-message:visible:last').hide();
numOfNewBoxes ++;
//remove any old on click events attached to the class delete-square
$('.delete-square').off('click');
//assign the event to the delete square class only - not the document.
//This stops the event from continuously firing on click.
$('.delete-square').on('click', function () {
numOfNewBoxes --;
//show the first of the original boxes if they are hidden
// only if there are < 4 new boxes;
$(this).parent().remove();
(numOfNewBoxes < 4) ? ($('.default-message:hidden:first').show()) : false;
});
});
});

Since you need to have more than one chart_div and delete_button, you can't use that as an id. Use a class instead:
$(document).ready(function () {
var chartDivs = $("ul.db-view-list li .quad .chart_div");
if (chartDivs.length == 1) {
$("li.ph:last-child").hide();
} else if (chartDivs.length == 2) {
$("li.ph:nth-child(2)").hide();
} else if (chartDivs.length == 3) {
$("li.ph:nth-child(1)").hide();
} else if (chartDivs.length >= 4) {
$("li.ph:first-child").hide();
} else {
$("li.ph").show();
}
;
$(".add-square").click(function () {
$(".db-view-list").prepend("<li><button class='delete-square'>X</button><div class='quad'><div class='chart_div'></div></div></li>");
});
//this will apply to .delete-squares created in the future
//so you can just do it once.
$(document).on('click', '.delete-square', function () {
$(this).parent().remove();
});
});

I believe you should also put that if/else statement in a function and have it execute whenever you delete or add a div. Now, the if/else statement is only executed once: when the document is ready.

Related

Hide and show an item based on a toggled is-active class

I used the following code to toggle a button class in order to make a full-screen mobile menu.
HTML
button class="hamburger hamburger--slider" type="button">
<a href='#'><div class="hamburger-box">
<div class="hamburger-inner"></div>
</div>
</a>
document.addEventListener('DOMContentLoaded', function() {
jQuery(function($){
$('.hamburger').click(function(){
$('.hamburger--slider').toggleClass('is-active');
});
});
});
Now I would like to hide another item in my header when the toggled class .is-active is present.
The following code works to hide the item, but once the toggled class is gone, the item does not reappear but stays hidden until the page is reloaded.
jQuery(function($) {
if ($('.hamburger--slider.is-active').length) {
$('.rey-headerCart-wrapper').hide();
}
});
Appreciate any help :) !
you have to show the element again after the burger menu closes:
document.addEventListener('DOMContentLoaded', function() {
jQuery(function($){
$('.hamburger').click(function(){
$('.hamburger--slider').toggleClass('is-active');
// hide / show other element
if ($('.hamburger--slider.is-active').length) {
$('.rey-headerCart-wrapper').hide();
} else {
$('.rey-headerCart-wrapper').show();
}
});
});
});
Or in vanilla javascript:
window.addEventListener("load", () => {
document.querySelector(".hamburger").addEventListener("click", () => {
document.querySelector(".hamburger--slider").classList.toggle("is-active");
// hide / show other element
const cart = document.querySelector(".rey-headerCart-wrapper");
if (document.querySelector(".hamburger--slider.is-active")) {
cart.style.display = "none";
} else {
cart.style.display = "block";
// apply original display style
// cart.style.display = "inline-block";
// cart.style.display = "flex";
};
});
})
In order to make toggle functions like this more understandable, maintainable and extendable you need to think about your HTML structure.
In your current structure, you have a button that toggles a class on itself. Therefore any element beyond that button that has to change appearance or beaviour has to check which class that button has, or you have to extend the click-event handler in order to add these elements (that's what you did here).
This can get quite messy really fast.
A better approach could be to not toggle a class on the button but on an element that is a common parent to all elements that you want to change the behavior of.
That way anything you ever add to that wrapper already can be manipulated via CSS, without the need of changing your JS.
$('.nav-toggler').on('click', function() {
$('#nav-wrapper').toggleClass('active');
});
.menu, .cart {
padding: 1em;
margin: 2px;
}
.cart {
background: #FFF000;
}
.menu{
background: #F1F1F1;
display: none;
}
#nav-wrapper.active > .menu {
display: block;
}
#nav-wrapper.active > .cart {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="nav-wrapper">
<button class="nav-toggler">Toggle</button>
<div class="menu">My Menu</div>
<div class="cart">My Cart</div>
</div>

How to call different functions when scrolled using JavaScript?

I was trying to call different functions using JavaScript when a key is pressed. It worked perfectly! How can I achieve the same effect by using the scroll wheel?
The goal is to change the background image of the webpage, carry out a query in a SQL Table and store the x and y co ordinates of the pointer in a table.
Hope this can help :)
$(document).scroll(()=>{
if($(document).scrollTop() >= 970){
//If you want to get style permenent remove line below
$("body").css("background","red");
}
else if($(document).scrollTop() >= 508){
//If you want to get style permenent remove line below
$("body").css("background","blue");
}
else if($(document).scrollTop() >= 8){
//If you want to get style permenent remove line below
$("body").css("background","indigo");
}
})
/*This is for smooth scrolling*/
html {
scroll-behavior: smooth;
}
.big {
height: 500px;
width: 100%;
border: solid black 1px;
}
.active {
color:red;
}
<div id="main">
<div class="big" id ="home">Home</div>
<div class="big" id ="about">About Us</div>
<div class="big" id ="contacts">Contacts</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
You're looking at the onscroll and scroll event.
<div onscroll="myFunction()"></div>
or
document.getElementById("myDIV").addEventListener("scroll", myFunction);
or
document.getElementById("myDIV").onscroll = function() {myFunction()};
and add the function in all cases:
function myFunction() {
console.log("It works");
}
https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onscroll
https://www.w3schools.com/jsref/event_onscroll.asp

How can I access a DOM element with jQuery that I have "moved" around the page?

I have a page with two areas. There are boxes in each area. If the user clicks on a box in the top area, it gets moved to the bottom and vice versa. This works fine for the first movement. Theoretically, I should be able to move them back and forth between sections as I please.
Box HTML:
<div id="top-area">
<div class="top-box" id="blue-box"></div>
<div class="top-box" id="yellow-box"></div>
<div class="top-box" id="green-box"></div>
</div>
<hr/>
<div id="bottom-area">
<div class="bottom-box" id="red-box"></div>
<div class="bottom-box" id="gray-box"></div>
</div>
I use jQuery.remove() to take it out of the top section and jQuery.append() to add it to the other. However, when I try to move a box back to its original position, the event that I have created to move them doesn't even fire.
jQuery/JavaScript:
$(".top-box").on('click', function ()
{
var item = $(this);
item.remove();
$(this).removeClass("top-box").addClass("bottom-box");
$("#bottom-area").append(item);
});
$(".bottom-box").on('click', function ()
{
var item = $(this);
item.remove();
$(this).removeClass("bottom-box").addClass("top-box");
$("#top-area").append(item);
});
I have verified that the classes I am using as jQuery selectors are getting added/removed properly. I am even using $(document).on() to handle my event. How come my boxes are not triggering the jQuery events after they are moved once?
Please see the Fiddle: http://jsfiddle.net/r6tw9sgL/
Your code attaches the events on the page load to the elements that match the selector right then.
If you attach the listener to #top-area and #bottom-area and then use delegated events to restrict the click events to the boxes, it should work like you expect. See .on: Direct and Delegated Events for more information.
Use the below JavaScript:
$("#top-area").on('click', '.top-box', function ()
{
var item = $(this);
item.remove();
$(this).removeClass("top-box").addClass("bottom-box");
$("#bottom-area").append(item);
});
$("#bottom-area").on('click', '.bottom-box', function ()
{
var item = $(this);
item.remove();
$(this).removeClass("bottom-box").addClass("top-box");
$("#top-area").append(item);
});
Alternatively:
You could also change .on() to .live(), which works for "all elements which match the current selector, now and in the future." (JSFiddle)
JSFiddle
Here's another way you could work it:
function toBottom ()
{
var item = $(this);
item.remove();
item.off('click', toBottom);
item.on('click', toTop);
$(this).removeClass("top-box").addClass("bottom-box");
$("#bottom-area").append(item);
}
function toTop ()
{
var item = $(this);
item.remove();
item.off('click', toTop);
item.on('click', toBottom);
$(this).removeClass("bottom-box").addClass("top-box");
$("#top-area").append(item);
}
$(".top-box").on('click', toBottom);
$(".bottom-box").on('click', toTop);
#top-area, #bottom-area {
height: 100px;
border: 1px solid black;
padding: 10px;
}
.top-box::before {
content: "Top";
}
.bottom-box::before {
content: "Bottom";
}
#blue-box, #red-box, #yellow-box, #green-box, #gray-box {
width: 100px;
cursor: pointer;
float: left;
margin: 0 5px;
text-align: center;
padding: 35px 0;
}
#blue-box {
background-color: blue;
}
#red-box {
background-color: red;
}
#yellow-box {
background-color: yellow;
}
#green-box {
background-color: green;
}
#gray-box {
background-color: gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top-area">
<div class="top-box" id="blue-box"></div>
<div class="top-box" id="yellow-box"></div>
<div class="top-box" id="green-box"></div>
</div>
<hr/>
<div id="bottom-area">
<div class="bottom-box" id="red-box"></div>
<div class="bottom-box" id="gray-box"></div>
</div>
This basically removes the listener that switched the object to bottom to a listener that switches the object to the top and viceversa.

How to find nearest child to a click location?

Fiddle: http://jsfiddle.net/1bgun0k0/1/
I have a DIV with several child SPANs.
<div id="parent">
<span class="child">Alpha</span>
<span class="child">Beta</span>
<span class="child">Gamma</span>
</div>
Child elements have a margin:
#parent { padding: 5px; }
.child { margin: 5px; }
When user clicks between child elements (or at either end of the parent DIV outside a child element), I need to insert a new child there.
How do I detect between which child elements user clicked?
Update: I need to support multiple rows of children (thanks, Roko, for the heads-up). Clicks between rows should be ignored. Clicks on the left and right side of the whole row should be handled correctly.
Since margins don't receive click events, I might suggest using a 5px placeholder div instead of a margin, so that clicking between children will result in a click to the placeholder.
On that click, you insert a new child (and a new 5px placeholder) underneath.
UPDATE: Since you changed the question from clicking between to clicking beside, you might try this trick using pseudo elements (to prevent divitis)
https://stackoverflow.com/a/23243996/1998238
An alternative solution is to use CSS to mask the area you are clicking. You can do this by wrapping your elements like so:
<div id="parent">
<div id="alpha" class="spacer">
<span class="child">Alpha</span>
</div>
<div id="beta" class="spacer">
<span class="child">Beta</span>
</div>
<div id="gamma" class="spacer">
<span class="child">Gamma</span>
</div>
</div>
Here is the code: https://jsfiddle.net/theodin/5enfs52t/2/
On click:
Iterate through each child, grabbing children on the left and right based on position in relation to the cursor. (Check event.pageY to make sure they're on the right row.)
If a child to the left is found, keep iterating to the end. The last left child will be the true left child.
If a child to the right is found, stop iterating. This is the one you want.
If a left child is found, insert the text and a space after it. You're done.
If a right child is found, insert the text and a space before it.
Snippet
var n = 0;
$('#parent').click(function(e) {
if(e.target.id === 'parent') {
var parent= $(this),
firstChild= $(this).find('.child').first(),
lastChild = $(this).find('.child').last(),
leftChild,
rightChild,
text= function() {return $('<span class="child new">New child '+(++n)+'</span>');}
parent.find('.child').each(function() {
var pos= $(this).offset(),
h= $(this).height();
if(pos.top <= e.pageY && pos.top+h >= e.pageY) {
if(pos.left <= e.pageX) {
leftChild= $(this);
}
else if(pos.left >= e.pageX) {
rightChild= $(this);
return false;
}
}
});
if(leftChild) {
leftChild.after(text()).after(' ');
}
else if(rightChild) {
rightChild.before(text()).before(' ');
}
else if(!firstChild.length || e.pageY < firstChild.offset().top) {
parent.prepend(text()).before(' ');
}
else if(e.pageY > lastChild.offset().top) {
lastChild.after(text()).after(' ');
}
//otherwise, we're between rows
}
});
body {
margin: 10px;
padding: 10px;
}
#parent {
padding: 5px;
background-color: green;
cursor: pointer;
width: 450px;
line-height: 2.7em;
}
.child {
margin: 5px;
white-space: nowrap;
background-color: yellow;
border: 1px solid black;
}
.new {
background-color: lightblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent">
<span class="child">Alpha</span>
<span class="child">Beta</span>
<span class="child">Gamma</span>
<span class="child">Delta</span>
<span class="child">Epsilon</span>
<span class="child">Zeta</span>
<span class="child">Eta</span>
<span class="child">Theta</span>
<span class="child">Iota</span>
<span class="child">Kappa</span>
<span class="child">Lambda</span>
<span class="child">Mu</span>
<span class="child">Nu</span>
<span class="child">Xi</span>
<span class="child">Omicron</span>
<span class="child">Pi</span>
<span class="child">Rho</span>
<span class="child">Sigma</span>
<span class="child">Tau</span>
<span class="child">Upsilon</span>
<span class="child">Phi</span>
<span class="child">Chi</span>
<span class="child">Psi</span>
<span class="child">Omega</span>
</div>
http://jsfiddle.net/tukqnujm/2
This was suggested previously, but you can add transparent clickable elements between the others to act as margins.
var parent = $("#parent");
parent.on("click", function(e) {
if(e.target.classList.contains("between")) {
var item = document.createElement("span");
item.classList.add("item");
var between = document.createElement("span");
between.classList.add("between");
e.target.parentNode.insertBefore(item, e.target);
e.target.parentNode.insertBefore(between, item);
}
});
Be careful though, inline-block tags add a space to the document if there are spaces between elements, and those spaces won't be clickable. That's why I put comments in the jsfiddle.
<div id="parent"><!--
--><span class="between"></span><!--
--><span class="item"></span><!--
--><span class="between"></span><!--
--></div>
You can track the position of the cursor (because the cursor will not be immediately over any .child element, so binding the click event to it is useless), and then retrieve a list of .child elements that are to the left of this coordinate. Get the last .child element that satisfy this criterea, append new element behind it.
Also, you should use .on() for the click event binding for .child, because newly added elements will not have the click event registered (because with your existing code, you are binding the click event at runtime, where newly added elements are not present on the page).
$('.child').on('click', function(e) {
e.stopImmediatePropagation();
$(".debug").removeClass("debug");
$(this).toggleClass("debug");
})
$("#parent").click(function(e) {
e.stopImmediatePropagation();
$(".debug").removeClass("debug");
$(this).toggleClass("debug");
// Get mouse position along x-axis
var xPos = e.pageX,
yPos = e.pageY;
// Get x-axis offset of child
// Return array of child elements that is to the left of mouseclick
// and get the last child, append new element after it
var $prevChild = $('.child').filter(function() {
return ($(this).offset().left < xPos && $(this).offset().top < yPos)
}),
$content = $('<span class="child">New child</span>');
// Additional logic from #AlexanderGladysh
if ($prevChild.length > 0) {
$content.insertAfter($prevChild.last());
} else {
$(this).prepend($content);
}
})
See fiddle here: http://jsfiddle.net/teddyrised/1bgun0k0/9/

set a newly created div on top of the older divs

I have a bunch of divs inside a container. The position of the content divs is relative, because I want them to appear one below the other and their height is unknown.
These divs are created dynamically (appendchild) inside the container div. Now, each div appears on the end (bottom) of the stack but my requirement is that the divs have a "newest first" option too, that is, each new div appears on top, not on bottom of the content divs (if the user selects the "newest first" in the settings).
html:
<div class="container">
<div id="div1" class="content">aaa<br>aaa</div>
<div id="div2" class="content">bbb<br><br>bbb</div>
<div id="div3" class="content">ccc</div>
<div id="div4" class="content">ddd</div>
</div>
css:
.container {
position: absolute;
top: 10px;
left: 10px;
right: 10px;
bottom: 10px;
border: 1px solid red;
}
.content {
position: relative;
top: 0px;
left: 5px;
width: 200px;
height: auto;
border: 1px solid blue;
margin: 3px;
}
http://jsfiddle.net/jk559/1/
so I'd like the end-user visible order to be: div4, div3, div2, div1.
How can I achieve this? (css/js)
preferrably no jquery.
thanks in advice!
Pure css solution:
Use flexbox to achieve this.
.container {
display:flex;
flex-direction:column-reverse;
justify-content: flex-end;
align-content: flex-end;
}
Updated fiddle here.
Read more information here.
try this
theParent = document.getElementById("theParent");
theKid = document.createElement("div");
theKid.setAttribute("id","div5");
theKid.setAttribute("class","content");
theKid.innerHTML = 'eee';
// append theKid to the end of theParent
theParent.appendChild(theKid);
// prepend theKid to the beginning of theParent
theParent.insertBefore(theKid, theParent.firstChild);
Demo Fiddle http://jsfiddle.net/jk559/4/
You can easily do it with JQuery with the following function.
$('.container > div').each(function() {
$(this).prependTo(this.parentNode);
});
UPDATED FIDDLE
As you mentioned in the question, I will try to attain the expected output with the pure javascript.
You can insert content in the beginning simply using .prepend() .
$(".container").prepend("<div id='div5' class='content'>eee</div>");
Demo
JS FIDDLE UPDATED DEMO
Use prepend() to add as first child of an element
/* $( ".container" ).prepend( "Your div with id here" ); */
/* Example */
$( ".container" ).prepend( "<div id='div5' class='content' >div5 on top </div>" );
Take a look at this answer about reordering dom items.
Basically, you have to maintain a state that decides the ordering. When you insert items (see insertItem below) you append or prepend based on the state. When the user selects the newest first option (see newFirst below), you first reverse the dom elements and then flip the state so that subsequent insert happen at the right place.
var newFirst = false;
var list = document.getElementById('my-list');
function newFirst() {
var items = list.childNodes;
var itemsArr = [];
for (var i in items) {
if (items[i].nodeType == 1) { // get rid of the whitespace text nodes
itemsArr.push(items[i]);
}
}
itemsArr.reverse();
for (i = 0; i < itemsArr.length; ++i) {
list.appendChild(itemsArr[i]);
}
newFirst = !newFirst;
}
function insertItem(content) {
var item = document.createElement("div");
item.setAttribute("class","content");
item.innerHTML = content;
if(newFirst) {
list.insertBefore(item, list.firstChild);
} else {
list.appendChild(item);
}
}
try this :
$("div[id*=div]").sort(function(a,b){
if(a.id > b.id) {
return -1;
} else {
return 1;
}
}).each(function() {
var elem = $(this);
$(".container").append(elem);
});
this will sort your divs inside container like this : div4, div3, div2, div1
if you want change the order to : div1, div2, div3, div4 just change if(a.id > b.id) to if(a.id < b.id)
you can add a link called change order then call this code when you click on it

Categories

Resources