How to fix the recursion problem in jQuery code - javascript

I have been on a game project for a while. I have used bootstrap and jQuery. But to keep it simple, here is what the piece of code in which I did not understand anything looks like. I wanted that by clicking and only clicking on item A, item B will show and disappear after clicking on it. I added an instruction that will show me after every click on an item a message in the console and watch what happens!
let elt_boxOne = $("#bx_one");
let elt_boxTwo = $("#bx_two");
elt_boxTwo.hide();
elt_boxOne.click($.proxy(function() {
elt_boxTwo.show();
elt_boxTwo.click($.proxy(function() {
console.log("Hello world");
elt_boxTwo.hide();
}, this));
}, this));
/*As you can see the first time has no problem but if we try the second time there will be two messages and the third click will show three etc... I mean what the hell is going on???*/
#bx_one {
width: 200px;
height: 50px;
background-color: red;
text-align: center;
font-weight: bold;
}
#bx_two {
width: 200px;
height: 50px;
background-color: orange;
text-align: center;
font-weight: bold;
}
<div id="bx_one">Box one</div>
<div id="bx_two">Box two</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

You are initializing the click listener to many times, when you click on button 1. You have to move it outside, independent of the first click handler... like this:
BTW, you don't need proxies, you can use arrow functions if you need the context inside.
let elt_boxOne = $("#bx_one");
let elt_boxTwo = $("#bx_two");
elt_boxTwo.hide();
elt_boxOne.click(() => {
elt_boxTwo.show();
});
elt_boxTwo.click(() => {
console.log("Hello world");
elt_boxTwo.hide();
});
#bx_one {
width: 200px;
height: 50px;
background-color: red;
text-align: center;
font-weight: bold;
}
#bx_two {
width: 200px;
height: 50px;
background-color: orange;
text-align: center;
font-weight: bold;
}
<div id="bx_one">Box one</div>
<div id="bx_two">Box two</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Do not create your "box 2" listener inside of your "box 1" listener. Simply separate the two element's click handlers.
const
$boxOne = $("#bx-one"),
$boxTwo = $("#bx-two").hide();
$boxOne.on('click', () => $boxTwo.show());
$boxTwo.on('click', () => {
console.log("Hello world!");
$boxTwo.hide();
});
.bx {
width: 200px;
height: 50px;
text-align: center;
font-weight: bold;
}
#bx-one { background-color: red; }
#bx-two { background-color: orange; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="bx-one" class="bx">Box one</div>
<div id="bx-two" class="bx">Box two</div>

yes the code I gave is simple ... But it does not perfectly illustrate my problem. In fact in my original code this is a dialog box that pops up when I click on a button, and this dialog box contains a "confirm" button. I want that when I click on the confirm button (Unlike the display of "hello world" in the console in this code) a confirmation message goes from the dialog box to the object that contains the first button that I clicked. So i told myself that the two click events must be connected. i could be wrong

Related

Display alert if clicking outside div

I have a div class ".square", i want to show an alert if there is a mouse clicking outside of the div element, i can't find something similar according to mouse event on this website w3schools. ( i want the opposite of my actual code ) Thank you.
function myFunction() {
alert('hi')
}
.square{
width: 100px;
height: 100px;
background-color: red;
}
<div class="square" onclick="myFunction()" ></div>
Simple solution: Add a listener to the window that produces the alert and add a listener to the div that stops the click event from propagating so that it never reaches the window.
Disclaimer: calling stopPropagation is not a great thing to do as it's quite intrusive, but I'm guessing you're just trying things out, so it should be fine.
window.onclick = () => alert('hi')
.square{
width: 100px;
height: 100px;
color: red;
background-color: teal;
}
<div onclick="event.stopPropagation()" class="square">TEST</div>
Here's a good answer that describes a more proper way to achieve this.
And here's that answer adjusted to your case in a more correct solution where we look at the click event to determine if we should call alert:
const outsideClickListener = element => ({ target }) => {
if (!element.contains(target)) {
alert("hi");
}
};
const squareEl = document.getElementById("square");
document.addEventListener("click", outsideClickListener(squareEl));
#square{
width: 100px;
height: 100px;
color: red;
background-color: teal;
}
<div id="square">TEST</div>
Why should we not use stopPropagation? In a small project there's not a big problem to use it (which is why it's my top recommendation). But in a big real world project it's ill advice, because it can break behavior of other stuff. See below example. Developer A added Test 1 and expects alert('hi 1') to be ran every time the user clicks outside of Test 1. But developer B added Test 2 which calls stopPropagation that stops all events, so when the user clicks Test 2 (which is outside of Test 1) alert('hi 1') is not ran and we have a bug.
window.onclick = () => alert('hi 2')
const outsideClickListener = element => ({ target }) => {
if (!element.contains(target)) {
alert("hi 1");
}
};
const squareEl = document.getElementsByClassName("square")[0];
document.addEventListener("click", outsideClickListener(squareEl));
.square, .circle {
width: 100px;
height: 100px;
color: red;
background-color: teal;
}
.square {
background-color: teal;
}
.circle {
background-color: wheat;
}
<div class="square">TEST 1</div>
<div onclick="event.stopPropagation()" class="circle">TEST 2</div>
<div class="square">squre</div>
.square{
width:200px;
height:200px;
border:1px solid red;
}
let sq = document.querySelector('.square');
window.addEventListener('click', function(e){
if (sq.contains(e.target)){
alert('inside square box')
} else{
alert('outside square box')
}
});
Make a click event listener for the body.
If the body is clicked check if the target is the square, or if the target is a child of the square
function myFunction() {
alert('hi');
}
$(document).ready(function(){
$('body').on('click', function(e) {
if($(e.target).is('.square') || $(e.target).closest('.square').length) {
myFunction();
}
});
});
.square{
width: 100px;
height: 100px;
color: red;
background:red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div class="square">
</div>
<body>

Jquery click on popup div to show another div

The requirement is user can Click on black box to show orange box, and click on orange box to show red box, but the orange box and red box should be hidden
when user click anywhere of the document except the orange box or the
red box itself.
But currently the issue is that we cannot click on orange box to show red box
Would much appreciate if you could help me out, thanks a lot
Demo link: http://plnkr.co/edit/OqlfbmFPKdXx0wDhnLxZ?p=preview
$(function() {
$('#mypop').click(function(e) {
event.stopPropagation();
});
$(document).on('click', '#myclick', function() {
$('#mypop').toggle();
$(document).one('click', function() {
$('#mypop').hide();
});
});
$(document).on('click', '#myclick1', function() {
$('#mypop2').show();
});
$(document).on('click', '#myclick2', function() {
$('#mypop2').show();
});
})()
#mypop {
background-color: orange;
position: absolute;
top: 130px;
left: 50px;
width: 150px;
padding: 15px;
}
.mydiv {
background-color: black;
padding: 30px;
width: 50px;
cursor: pointer;
color: white;
}
#mypop2 {
margin-top: 150px;
background-color: red;
width: 100px;
height: 50px;
padding: 18px;
display: none;
}
#myclick1,
#myclick2 {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="myclick" class='mydiv black-box'>
click me!
</div>
<div id="mypop" style="display:none;" class='orange-box'>
<p>hello world</p>
<div id='myclick1'>BUTTON1</div>
<div id='myclick2'>BUTTON2</div>
</div>
<div id="mypop2" class='red-box'>
Hello World!!!
</div>
try this. I think this is what you are excepting but I'm not sure since you keep editing your question.
Demo Link: http://plnkr.co/edit/n7rdgqTwiFrXtpgoX4TQ?p=preview
$('#myclick1').click(function(){
$('#mypop2').show();
});
$('#myclick2').click(function(){
$('#mypop2').show();
});
You have couple of things mixed up.
The main stop-point was the very first event listener
$('#mypop').click(function(e) {
which is incompatible with the rest of listeners
$(document).on('click','#myclick1',function(e){
after I have changed it to
$(document).on('click','#mypop', function(e){
the other listeners have started working.
Second thing is that for embedded elements (parent-child) you need to stop event propagation, otherwise the parent event is triggered as well (which is not desired)
$(document).on('click','#myclick1',function(e){
e.stopPropagation();
:
});
I have also changed the CSS a bit and added class hide to use instead of styles. Toggling this class is what hides and shows an element.

Disable OnClick Event Until Another One Is Triggered First

I have 6 divs (.selector) set to do (onclick):
Show all tables
Show Nº1, Hide rest
Show Nº2, Hide rest
...
Show Nº5, Hide rest
They also toggle a class "activated" that changes the background color.
What I'm trying to do is that once I click on "Show Nº1, Hide rest" disable the click option (On this div) until I click in another one first like "Show all tables" or "Show Nº2, Hide rest".
Something like the "once function" but that resets as soon as another div is activated. Any way to do this?
Here is my CSS
.selector {
height: 25px;
width: 25px;
background-color: #702C3D;
margin-left: 2px;
margin-right: 2px;
float: left;
cursor: pointer;
}
.selector.activated {
background-color: #000000;
}
Here is my JavaScript
$('.selector').on('click', function(event) {
$('.selector').not(this).removeClass('activated');
$(this).toggleClass('activated');
});
If you change toggleClass to addClass in your click function. Then, more than 1 click in your .activated will have no effect (as the click is disabled):
$('.selector').on('click', function(event) {
$('.selector').not(this).removeClass('activated');
$(this).addClass('activated');
});
Or you can check if the clicked .selector has .activated class like:
$('.selector').on('click', function(event) {
if($(this).is('.activated')) return;
$('.selector').not(this).removeClass('activated');
$(this).toggleClass('activated');
});
There's two things to do:
Wrap the JavaScript inside a function
Unbind the click event everytime you click on something
Here's how:
function clickEvent(elements){
elements.bind('click', function(event) {
$('.selector').not(this).removeClass('activated');
$(this).toggleClass('activated');
$('.selector').unbind('click');
clickEvent($('.selector').not(this));
});
}
clickEvent($('.selector'));
.selector {
height: 25px;
width: 25px;
background-color: #702C3D;
color: #FFF; //for display purposes
margin-left: 2px;
margin-right: 2px;
float: left;
cursor: pointer;
}
.selector.activated {
background-color: #000000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="selector">1</div><div class="selector">2</div><div class="selector">3</div><div class="selector">4</div><div class="selector">5</div><div class="selector">6</div>
You should be able to do
if($(this).hasClass('activated'))
return;
To skip it if this was allready activated.

CSS property update not working with mouse click

i am trying to implement accordion.
My accordion should expand on mouse hover on the "accordian head".
And also mouse click on "accordian head" should show/hide the accordion-body.
I got the show/hide working through CSS on hover.
But when i club mouse click event , the functionality is not working
here is the sample
http://jsfiddle.net/yf4W8/157/
.accordion-body{display:none;}.accordion:hover div{display:block;}
you need to change
myDivElement.style.display = none;
myDivElement.style.display = block;
to
myDivElement.style.display = "none"; //double quotes are missing
myDivElement.style.display = "block"; //double quotes are missing
Demo
I have created a working demo, please check the link below not it is working on mouse click. Replace your JavaScript code with this and remove the css properties.
function expandAccordionBody(){
var myDivElement = document.getElementById("accbody" );
var cStyle=window.getComputedStyle(myDivElement, null);
if(cStyle.display=='block'){
myDivElement.style.display='none';
}else{
myDivElement.style.display='block';
}
}
Demo
I took a liberty to change your code a bit. This code works.
Hope that this is what you meant to do....
Instead of using pure Javascript I used jQuery event click and hover.
here is the link for working code
click here for DEMO
HTML code;
<div class="accordion">
<div class="headA">
Head
</div>
<div id="accbody" class="accordion-body">
Body
</div>
</div>
CSS code;
.accordion {
border: 1px solid #444;
margin-left: 60px;
width: 30%;
}
.accordion:hover div {
display: block;
}
.accordion-body a {
background-color: green;
display: block;
color: white;
padding: 25px;
text-align: center;
}
.headA a {
text-align: center;
display: block;
background-color: yellow;
padding: 25px;
}
jQuery code;
$(document).ready(function() {
// on page load hide accordion body
var accordionBody = $('#accbody');
accordionBody.hide();
// first make on click event happening
// when user clicks on "Head" accordion "Body will show up"
$('.headA').click(function() {
if (accordionBody.is(':hidden')) {
accordionBody.slideDown(400);
} else {
accordionBody.slideUp(400);
}
});
$('.headA').hover(function() {
if (accordionBody.is(':hidden')) {
accordionBody.slideDown(400);
} else {
accordionBody.slideUp(400); // turn this off if you want only to slide down and not back up
}
});
});

Blog / Message - How do I fix that empty message divs will piling on / next to each other and make the close button work?

So I'm making a sort of blog posting system or TODO list, however you want to call it.
I want that the following can happen / is possible:
[Working] The user types something in the textarea
[Working] The user clicks on the button.
[Working] A new div will be created with the text of the textarea.
[Working] The textarea will be empty.
[Not Working] The user has got the choice to delete the post by clicking the 'X' on the right side of each '.post' div.
BUT: If I click on the button when there's nothing in the textarea, there appears an empty div, with only an 'X' close button, no background color either. They appear on the same line as the previous message, so you can get a lot of 'X's next to each other.
AND: Clicking the 'X' close button doesn't do anything. No errors in Firefox console.
If it's not clear enough, run this JSFiddle, click the button and I think you'll understand what I mean:
JSFiddle
HTML:
<!DOCTYPE html>
<html>
<head>
<link href="main.css" rel="stylesheet">
<script src="jquery.min.js"></script>
<meta charset="UTF-8">
</head>
<body>
<div id="blog">
<h1>Blog post application</h1>
<div id="post-system">
<textarea id="poster" rows="5" cols="50" placeholder="Update status."></textarea>
<div id="button">Post</div>
<div id="posts">
</div>
</div>
</div>
</body>
</html>
jQuery Script:
<script>
$(document).ready(function () {
$('#button').click(function () {
var text = $('#poster').val();
$('#posts').prepend("<div class='post'>" + text + "<span class='close-post'>×</span></div>");
$('#poster').val('');
});
$('.close-post').click(function () {
('.close-post').parent().hide();
});
});
</script>
CSS:
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
#blog {
background-color: blue;
margin: 50px;
padding: 50px;
text-align: center;
border-radius: 10px;
color: white;
display: block;
}
#poster {
color: default;
resize: none;
border: 1px solid black;
text-decoration: blink;
font-size: 20px;
display: inline-block;
position: relative;
border-radius: 5px;
border: 2px solid black;
padding-left: 10px;
padding-top: 5px;
}
#button {
background-color: #00FFFF;
color: white;
border: 2px solid white;
border-radius: 5px;
cursor: pointer;
width: 50px;
float: left;
}
.post {
background-color: white;
color: blue;
margin-top: 20px;
width: auto;
display: block;
}
.close-post {
margin-right: 10px;
float: right;
color: red;
cursor: pointer;
}
You appear to have two issues:
1) You don't want a post to be created if the textarea is empty
Simple fix . . . check to see if it is empty, before calling the logic to add the new post (and use jQuery's $.trim() to account for only blank spaces):
$('#button').click(function() {
var text = $.trim($('#poster').val());
if (text !== "") {
$('#posts').prepend("<div class='post'>" + text + "<span class='close-post'>×</span></div>");
$('#poster').val('');
}
});
2) The 'X' buttons are not closing the posts
This also should be a pretty easy fix . . . the reason that they are not working is because the 'X' buttons don't exist when the page is loaded so $('.close-post').click(function() { is not binding to them on page load. You will need to delegate that event binding, so that it will apply to the 'X' buttons that are dynamically added after the page is loaded.
Now, not knowing what version of jQuery that you are using (I can't access jsFiddle from work), I'll point you to the right place to figure out the correct way to do it: https://api.jquery.com/on/
If it is jQuery 1.7 or higher, you would do it like this:
$("#posts").on("click", ".close-post", function() {
$(this).parent().hide();
});
If your version is earlier than that, then investigate the jQuery .delegate() and .live() methods to determine which is the right one to use for your code..
Try this:
$(document).ready(function() {
$('#button').click(function(event) {
event.preventDefault();
var text= $('#poster').val();
if (text === '') {
alert('Nothing to post!');
return;
}
$('#posts').prepend("<div class='post'>" + text + "<span class='close-post'>×</span></div>");
$('#poster').val('');
});
$('#posts').on('click', '.close-post', function() {
$(this).closest('.post').fadeOut();
});
});
JSFiddle
The way you are doing this, the user will only ever see what they are posting - if you're trying for a chat type where users talk to each other then you will need to store what is being typed on the server side and refresh the screen using something like ajax
but in response to your question, you need to bind the close click like this:
$( "#posts" ).on( "click", ".close-post", function() {
$(this).parent().hide(); // $(this) is the clicked icon, the way you did it above wouldn't as if it had the dollar, it would close all .close-post parents
});
See the part about delegated events: http://api.jquery.com/on/

Categories

Resources