Appending HTML with click function jQuery not working - javascript

http://jsfiddle.net/CCKUz/
So I have a box with a <span class="open"> that will increase the height of a collapsible div to view the content. It's collapsible simply by CSS height and the open click function sets height to auto. Easy and this works.
The problem happens when I go to append the open and close spans. When I include them in the actual html, they work fine. When I append them, they no longer function. I thought maybe this was due to not being available for the js to apply the .click function to them since they were created after the load but even creating them and applying the .click in the same function doesn't help this problem.
Is there anything you see there that might be affecting this? Thanks.
HTML:
<div class="box collapsible">
<h3>Title</h3>
<p>This is a sample paragraph that is here for placer purposes.</p>
</div>
CSS:
.box { height: 20px; border: 1px solid #000000; padding: 10px; margin: 20px; position: relative; overflow: hidden; }
h3 { margin: 0 0 20px 0; line-height: 20px; }
.open, .close { text-indent: -9999px; width: 20px; height: 20px; position: absolute; top: 10px; right: 10px; }
.open { background: #00ff00; }
.close { background: #0000ff; }
JS:
$(function(){
var box = $(".collapsible");
var close = $(".collapsible span.close");
var open = $(".collapsible span.open");
box.each(function(){
box.append('<span class="open">Open</span>');
open.each(function(i){
open.click(function(){
alert("You clicked open");
$(this).parent(box).css("height","auto").append('<span class="close">Close</span>');
$(this).hide();
$(this).parent().find(close).show();
});
});
close.each(function(i){
close.click(function(){
$(this).parent(box).css("height","15px");
$(this).hide();
$(this).parent().find(open).show();
});
});
});
});

No need for loops, jQuery does that internally, and you need delegated event handlers with dynamic elements, like so:
$(function () {
var box = $(".collapsible");
box.append( $('<span />', {'class':'open'}) )
.on('click', '.close', function () {
$(this).hide()
.closest('.collapsible')
.css("height", "auto")
.append( $('<span />', {'class':'close'}).show() );
})
.on('click', '.close', function () {
$(this).hide()
.closest('.collapsible')
.css("height", "15px")
.find('.open').show();
});
});

you select the open-elements before adding them:
var open = $(".collapsible span.open");
Try this:
$(function(){
var box = $(".collapsible");
var close = $(".collapsible span.close");
box.each(function(){
box.append('<span class="open">Open</span>');
var open = $(".collapsible span.open"); //do it here!!
open.each(function(i){
open.click(function(){
alert("You clicked open");
$(this).parent(box).css("height","auto").append('<span class="close">Close</span>');
$(this).hide();
$(this).parent().find(close).show();
});
});
close.each(function(i){
close.click(function(){
$(this).parent(box).css("height","15px");
$(this).hide();
$(this).parent().find(open).show();
});
});
});
});

There is no need for .each delegate the function
$(document).on('click','.collapsible span.open',function(){
demo here http://jsfiddle.net/CCKUz/2/

The problem is that you are adding your .close spans dynamically, so your initial search will not find anything, so it will not add any click handlers to them. You can use event delegation to fix this easily.
.on('click', 'span.close', function(evt){
You can also simplify your code a lot:
$(".collapsible")
.append('<span class="open">Open</span>')
.on('click', 'span.open', function(evt){
// Search within the parent '.collapsible'.
$(evt.delegateTarget)
.css("height", "auto")
.append('<span class="close">Close</span>');
// Hide the '.open' span.
$(this).hide();
})
.on('click', 'span.close', function(evt){
// Search within the parent '.collapsible'.
$(evt.delegateTarget)
.css("height","15px");
.find('.open').show();
// Remove the old '.close' button since the
// open handler will make a new one.
$(this).remove();
})

Related

Removing dynamically generated elements, when clicking on an element within itself in jQuery?

How can I remove a dynamically generated block of elements when clicking the button inside of it?
function controlContent(target, trigger) {
//this will add a new div to target which is an existing html element
$(trigger).on("click", () => {
$(target).append(`
<div class="dynamic-container">
<button class="remove-btn">Remove the div I am inside</button>
</div>
`)
}
//this should remove the div that was added when I click the remove button
$(target).on("click", ".remove-btn", () => {
$(this).closest(".dynamic-container").remove();
}
}
FIRST: you should use $(document).on("click", target, function(){...} for dynamically generated elements
SECOND: As simple as parent()
$(document).on("click", target, function(){
$(this).parent().remove();
});
EXAMPLE:
$(".button1").on("click", function(){
$(".generatedbuttons").append('<div class="green"><button class="button2">Click me to remove me and my parent</button></div>');
});
$(document).on("click", ".button2", function(){
$(this).parent().remove();
});
.button1 {
display:block;
float: left;
}
.green {
padding: 10px;
background-color: green;
display: block;
float: left;
clear: both;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="button1">Click me to generate buttons</button>
<div class="generatedbuttons">
</div>
use normal function and also use dynamic click listener so you don't need to create a new event lister every time.
$(document).on('click', '.remove-btn', function(){
$(this).closest(".dynamic-container").remove();
})

Check next hovered item with jQuery

I have the following code that detects if a user is hovering over a box:
var toolTipHover = false;
$('#chartTooltip').on('mouseover', function () {
toolTipHover = true;
}).on('mouseout', function () {
toolTipHover = false;
});
$('.box').on('mouseover', function () {
$('#chartTooltip').show();
}).on('mouseout', function () {
console.log(toolTipHover);
if (!toolTipHover) {
$('#chartTooltip').hide();
}
toolTipHover = false;
});
And if they are then it shows the #chartTooltip element. (The tooltip is positioned and populated via some other means.)
However if the user hovers the tooltip itself it causes the tooltip to disappear (because they are no longer hovering the box). So I'm trying to check if the tooltip is being hovered (i.e. the next element hovered). and if so then ignore the mouseout event.
But toolTipHover is always false. I presume due to a race exception where mouseout has completed before the mouseover for the #chartTooltip can return the variable value of true.
How can I get around this?
I'm going to assume #chartToolTip is outside of .box for this. Instead of a flag variable (toolTipHover), just check the mouseleave event toElement property. So for example:
$('.box').on('mouseleave', function(e){
if (!$(e.toElement).is('.tooltip')){
$('.tooltip').hide();
}
})
Here is an example: https://jsfiddle.net/qvqafyf2/
$('.tooltip').hide();
$('.box').on('mouseover', function(e){
$('.tooltip').show();
})
$('.box').on('mouseleave', function(e){
if (!$(e.toElement).is('.tooltip')){
$('.tooltip').hide();
}
})
$('.tooltip').on('mouseleave', function(e){
if (!$(e.toElement).is('.box')){
$(this).hide();
}
})
.box{
width: 200px;
height: 200px;
background: red;
}
.tooltip{
height: 50px;
width: 50px;
background: green;
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
</div>
<div class="tooltip">
hi
</div>
You could add #chartTooltip with .box in your function like this:
$('.box , #chartTooltip').on('mouseover', function()
here is fiddle

Mouseout and click

When a user mouses over a div it should change to the color red, when they mouse out it should change back to transparent. When they click on the div, it should change to color red.
For some reason, the mouse out event listener is conflicting with the click event listener. Can someone help? When I click on the div, it doesn't change to red.
div$.on('mouseover', function () {
$(this).css('background-color', 'red');
});
div$.on('mouseout', function () {
$(this).css('background-color', 'white');
});
div$.on('click', function () {
$(this).css('background-color', 'red');
});
Note, I have to apply a background image dynamically to each element, so using CSS classes to add the background image is out of the question (because I don't know it before hand).
You could set a boolean variable to confirm that the click has occurred and then only run the mouseout code if the variable is false like this:
var is_clicked = false;
div$.on('mouseover', function () {
$(this).css('background-color', 'red');
});
div$.on('mouseout', function () {
if(!is_clicked) {
$(this).css('background-color', 'white');
}
});
div$.on('click', function () {
$(this).css('background-color', 'red');
is_clicked = true;
});
Note: For multiple div elements user multiple is_clicked variables
You can always do a CSS implementation with :hover; just make sure to add a specifying class to each element you would like this effect on.
1. :hover and jQuery
var div$ = $('.redHover'); // name the class whatever you like
div$.on('click', function () {
$(this).css('background-color', 'red');
});
div {
display: inline-block;
}
.redHover {
height: 100px;
width: 100px;
border: 1px solid black;
}
.redHover:hover {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='redHover'></div>
<div class='redHover'></div>
<div class='redHover'></div>
2. :hover and vanilla JS
var els = document.querySelectorAll('.redHover');
for (var i = 0; i < els.length; ++i) {
els[i].addEventListener('click', function() {
this.style.backgroundColor = 'red';
});
}
div {
display: inline-block;
}
.redHover {
height: 100px;
width: 100px;
border: 1px solid black;
}
.redHover:hover {
background: red;
}
<div class='redHover'></div>
<div class='redHover'></div>
<div class='redHover'></div>
Instead use mouseenter insead of mouseover see why.
The best thing you can go with would be the following notes:
To those elements with hover effect add a class like hoverable.
Hover effect is only applied to those elements having this class.
HTML:
<div class="hoverable"></div>
CSS:
.hoverable:hover{
background-color: red
}
JavaScript:
div$.on('click', function () {
$(this).css('background-color', 'red');
});
In this way, you can simply decide whether an element should be hover-able or not by adding or removing hoverable class. Also hover effect is applied in CSS level not JavaScript, which is more acceptable.
As far as I understand you really want to change picture in the div, not just background color which is relatively easy. Try this:
<div class="hoverable">
<img src="myImg.jpg" />
</div>
//css
.hoverable img{visibility:hidden;}
.hoverable:hover img{visibility:visible;}
.clicked img{visibility:visible!important;}
//JS
$('.hoverable').click(function(){
$(this).addClass('clicked');
});

New class keeps old class behaviour

I'm taking by first babysteps in jQuery and stumbled upon a problem I can't seem to get around.
I couldn't find an article that quite described what my problem was, so I would like to try to get an answer this way.
I don't understand why my objects keep behaving like their former class.
When I setup a hover action for a class, and change the class of the object by clicking, jQuery keeps doing the animation for the new class.
I used toggleClass() and removeClass/ addClasswithout any result:
https://jsfiddle.net/biest9160/f0na6sro/
var wide = function() {
$(this).animate({ 'width': '120px' }, 200);
}
var normal = function() {
$(this).animate({ 'width': '100px' }, 200);
}
$(document).ready(function() {
$('.class1').hover(wide, normal);
$('.class1').click(function() {
$(this).toggleClass('class1 class2');
})
})
div {
width: 100px;
height: 100px;
border: 1px solid #000;
margin: auto;
}
.class2 {
background: #555;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box1" class="class1">box1</div>
<div id="box1" class="class1">box2</div>
<div id="box1" class="class1">box3</div>
<div id="box1" class="class1">box4</div>
I don't understand why the the hover action is triggered while the object has a new class.
Initialy you attach the event to the element with the class name. After the class is changed the event remains on the element.
To remove the event you can use .unbind. To remove .hover event you can check this answer.
A working example using .unbind to remove the event and after to reattach it will look like in the snippet (basically is toggle hover event):
var wide = function(){
$(this).animate({'width':'120px'},200);
}
var normal = function(){
$(this).animate({'width' : '100px'},200);
}
$(document).ready(function(){
$('.class1').hover(wide,normal);
$('.class1').click(function(event){
var $this = $(this);
$this.unbind('mouseenter mouseleave'); // remove hover
if( $this.hasClass('class2'))
{
$this.hover(wide, normal); // reattach hover
}
$this.toggleClass('class1 class2');
})
})
div{
width:100px;
height:100px;
border: 1px solid #000;
margin: auto;
}
.class2{
background: #555;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box1" class="class1">box1</div>
<div id="box1" class="class1">box2</div>
<div id="box1" class="class1">box3</div>
<div id="box1" class="class1">box4</div>
Use .on() menthod to bind the event which will actually bind the event on the parent of the class.
Here is the example:
$(document).on("click", '.class1', function(){
$(this).toggleClass('class1 class2');
});
This will defiantly work...

jQuery dialog - div positioned on top of dialog box inputs disabled

The problem is this:
A dialog box is opened. I click the input field of the dialog box to open a div that is absolutely positioned over the dialog box. The input cannot be interacted with.
Here is the example on Jsfiddle
You can mouse over the input and the mouse cursor will change to the 'I' icon. You can even interact with the close anchor tag on the absolutely positioned div. It's not a z-index issue. It works in jQuery UI 1.9 and older. Strangely, after the absolute div has been added to the DOM, if you append an empty div to the end of the body html (using firebug to edit the code realtime), the input works.
Any ideas?
Thanks in advance,
Bontke
$('#open_dialog').click(function (event) {
var dialog_html = '<div id="dialog_body">' +
'<input type="text" name="test1"/>' +
'</div>';
$(dialog_html).dialog({
title: 'WTF Test',
height: 110,
width: 300,
modal: 'true',
close: function () {
$(this).remove();
$('#test_div').remove();
}
});
//dialog input click
$('input[name=test1]').click(function (event) {
var html = $('<div id="test_div" style="border: 1px solid red; z-index: 10000; position: absolute; left: 45%; top: 60%; width: 235px; height: 100px; background-color: blue;"><input name="foobar"/><a id="test_close" style="color: white;" href="#">close</a><br/><span style="color: white">super awesome text</span></div>'),
body = $(document.body);
if ($('#test_div').length === 0) {
//append div to body
html.appendTo(body);
//add close functionality to test_div
$('#test_close').click(function (event) {
event.preventDefault();
//remove test_div from DOM
$(event.currentTarget).parent().remove();
});
}
});
});
The dialog_html dialog is set to modal: 'true' which means it will deactivate everything else on the page. If you remove this it removes any problems. I think you're getting mixed results because you're adding to the DOM after jQuery has made the dialog modal and you really shouldn't be able to interact with the second popup at all, but it is breaking. You may want to try making the second pop-up modal, or adding it as a child of the first dialog rather than appending it to document.body
Sorry for the delayed reply, here is the solution:
http://jsfiddle.net/aY9ms/5/
I want the dialog box to be a modal. You are right, the adding the DOM is the because of how dialog box works. And in my case, it is better to add any html to the dialog box parent for better memory clean up. And adjusting the overflow on the dialog box allows the div to float over the dialog box as I want.
Thanks for all of the feedback and help!
var $ = $j;
var dialog_html = '<div id="dialog_body">' +
'<input type="text" name="test1"/>' +
'</div>';
$(dialog_html).dialog({
title: 'WTF Test',
height: 110,
dragable: true,
width: 300,
modal: 'true',
close: function () {
$(this).remove();
$('#test_div').remove();
}
});
//dialog input click
$('input[name=test1]').click(function (event) {
var html = $('<div id="test_div" style="border: 1px solid red; z-index: 10000; position: absolute; left: 45%; top: 60%; width: 235px; height: 100px; background-color: blue;"><input name="foobar"/><a id="test_close" style="color: white;" href="#">close</a><br/><span style="color: white">super awesome text</span></div>'),
dialog_box = $('#dialog_body').parent(),
body = $(document.body);
//adjust css
dialog_box.css({'overflow': 'inherit'});
if ($('#test_div').length === 0) {
//append div to body
//html.appendTo(body);
html.appendTo(dialog_box);
//add close functionality to test_div
$('#test_close').click(function (event) {
event.preventDefault();
//remove test_div from DOM
$(event.currentTarget).parent().remove();
});
}
});

Categories