Fire jQuery on dynamically inserted textstring - javascript

I'm trying to remove a text string and bind it to a click event but I can't figure this one out. I want to remove all non-numerical characters inside my em element:
<div class="cart">
<dl>
<dt>
<span class="cartspan">
<em class="minicart"></em>
<em id="headercartqty">8 items</em>
</span>
</dt>
</dl>
</div>
I use this script to remove it on page load:
$('em#headercartqty').text(function(_,xText){
return xText.replace(/[^\d]/g, '');
})
My problem is that when I click on a button with the class .actionbutton it dynamically updates the string and it then shows the word items again.
How do I bind the script to the button? I understand I should use .on somehow? This is what I've got so far:
$(document).ready(function () {
$(document).on('click', ".actionbutton", function () {
$('em#headercartqty').text(function(_, xText){
return xText.replace(/[^\d]/g, '');
})
});
});

DOMSubtreeModified will detect a change to the content, which you can then make your change:-
$('em#headercartqty').bind("DOMSubtreeModified",function(){
$(this).text(function(_, xText){
return xText.replace(/[^\d]/g, '');
})
});
UPDATE
As #abl advised in the comments below:-
Be very careful with this event it is easy to cause an infinite loop
if you decide to change the DOM inside the event handler.
Maybe try:-
function updateQuantity(){
$(this).text(function(_, xText){
return xText.replace(/[^\d]/g, '');
})
$('em#headercartqty').one("DOMSubtreeModified", updateQuantity);
}
$('em#headercartqty').one("DOMSubtreeModified", updateQuantity);
Or
$('em#headercartqty').bind("DOMSubtreeModified",function(){
if(/[^\d]/g.test($(this).text())){
$(this).text(function(_, xText){
return xText.replace(/[^\d]/g, '');
})
}
});
Though the first update calls the function twice, where the second calls it 3 times.

Your current $(document).on('click', ".actionbutton", function () seems to work properly, so I guess the problem is: it works too early.
In other words, when the .actionbutton is clicked the two events (the original one which updates content and the yours) are fired, then the yours finishes it work before the other one.
So you might try using setTimeout to make your own event to delay its work, like this:
$(document).ready(function () {
$(document).on('click', ".actionbutton", function () {
setTimeout(function() {
$('em#headercartqty').text(function(_, xText){
return xText.replace(/[^\d]/g, '');
});
},
100); // <-- make different tries to adjust delay to the minimum
});
});

$(function(){
$('.actionbutton').on('click',function(e){
e.preventDefault();
var el= $('em#headercartqty');
el.text(el.text().replace(/[^\d]/g, ''));
});
})

Related

toggleClass for different functions

I guess this code does not work, because at DOM load jQuery caches its objects and bind the functions to them?
$('span.button.slide_out').on('click', function () {
$(this).toggleClass('slide_out').toggleClass('slide_in');
$('#testbox').slideDown();
});
$('span.button.slide_in').on('click', function () {
$(this).toggleClass('slide_out').toggleClass('slide_in');
$('#testbox').slideUp();
});
I know I could write this easily with slideToggle or something else, but I have to fire different actions on every first and every second click. How can I achieve this using the same selector (instead of creating two different selectors)?
JS FIDDLE
The binding is indeed done on DOM creation, but that doesn't have to be a problem in this case, it also means that the button is still clicked if it no longer has the slide_out class. Therefore you can reuse the same click event and check the current state to choose whether to slide up or down. For example:
$('.slide_out').on('click', function () {
if($(this).toggleClass('slide_out slide_in').hasClass('slide_in'))
$('#testbox').slideDown();
else
$('#testbox').slideUp();
});
Fiddle
You could use the solution from Event binding on dynamically created elements?, as suggested by https://stackoverflow.com/users/502381/juhana:
HTML:
<span class="button_container"><span class="button slide_out">Click me</span></span>
<div id="testbox">Whohoohoooo, I am slidiiing!<br><br><small>Hey… wait! Why I am not sliding up again?</small></div>
JS:
$('.button_container').on('click', '.slide_out', function () {
$(this).toggleClass('slide_out').toggleClass('slide_in');
$('#testbox').slideDown();
});
$('.button_container').on('click', '.slide_in', function () {
$(this).toggleClass('slide_out').toggleClass('slide_in');
$('#testbox').slideUp();
});
http://jsfiddle.net/ag3cpcfb/
But, in my opinion it would be better to make your code simpler by using slideToggle() and adjust your css classes:
HTML:
<span class="button">Click me</span>
<div id="testbox">Whohoohoooo, I am slidiiing!<br><br><small>Hey… wait! Why I am not sliding up again?</small></div>
JS:
$('.button').on('click', function () {
var $testbox = $('#testbox');
if ($testbox.is(':visible')) {
console.log('Click 1');
} else {
console.log('Click 2');
}
$(this).toggleClass('slide_in');
$testbox.slideToggle();
});
http://jsfiddle.net/k77ferjh/
But this fires "Click 1" all of the time if you repeatedly click on the button. If this is not an issue, fine, if it is, you can also use a number to keep track of your clicks:
JS:
var clicks = 0;
$('.button').on('click', function () {
clicks++;
if (clicks % 2 == 0) {
console.log('Slide out');
} else {
console.log('Slide in');
}
$(this).toggleClass('slide_in');
$('#testbox').slideToggle();
});
http://jsfiddle.net/k77ferjh/1/

jQuery Simple text change on image hover

I'm trying to create a script for changing text on image hover. This is the HTML in simple version:
<section id="#first">
<div class="img-1"></div>
<div class="img-2"></div>
</section>
<section id="#second">
<div class="text-1"></div>
<div class="text-2"></div>
</section>
Javascript
jQuery(document).ready(function($){
$('.img-1').hover(
function(){ $('.text-1').addClass('text-1-active') },
function(){ $('.img-1').addClass('img-1-active') },
function(){ $('.text-2').removeClass('text-2-active') },
function(){ $('.img-2').removeClass('img-2-active') }
)
$('.img-2').hover(
function(){ $('.text-2').addClass('text-2-active') },
function(){ $('.img-2').addClass('img-2-active') },
function(){ $('.img-1').removeClass('img-1-active') },
function(){ $('.text-1').removeClass('text-1-active') }
)
});
Can't change the HTML structure. The classes do get added but don't get removed.
FIDDLE
:) actually this is all you need: DEMO
$("#first [class^=img-]").hover(function() {
$('#second .text-'+ this.className.replace(/\D/g,'')).toggle();
});
If you want to toggle classes? Nothing simpler: DEMO
$("#first [class^=img-]").hover(function() {
$(this).toggleClass("wow");
$('#second .text-'+ this.className.replace(/\D/g,'')).toggleClass("wow");
});
To explain the above, you just need to find out the number of the hovered element and reference-by number the needed .text-N element.
Also this <section id="#first">, that #first is not the way to set an ID to an HTML element.
Use simply <section id="first">
You are attempting to pass four separate callback functions, rather than a single callback that executes all the necessary code.
Here is what you want:
jQuery(document).ready(function($){
$('.img-1').hover(
function(){
$('.text-1').addClass('text-1-active');
$('.img-1').addClass('img-1-active');
$('.text-2').removeClass('text-2-active');
$('.img-2').removeClass('img-2-active');
}
)
$('.img-2').hover(
function(){
$('.text-2').addClass('text-2-active');
$('.img-2').addClass('img-2-active');
$('.img-1').removeClass('img-1-active');
$('.text-1').removeClass('text-1-active');
}
)
});
http://jsfiddle.net/w4mLtec8/5/
first, you use the .hover function wrongly, it should only accept 2 arguments which is for mouseenter and mouseleave. You should be using it like this
$("selector").hover(
function(){
// mouseenter function
},
function(){
// mouseleave function
}
});
and second you don't need to use too long class name to to decide it's active or not, hence you can use it to diferentiate it like this text-1 active and text-2 active, so you can write it like this in jQuery
jQuery(document).ready(function($){
$('.img-1').hover(
function(){ $('.text-1').addClass('active') },
function(){ $('.text-1, .text-2').removeClass('active') }
)
$('.img-2').hover(
function(){ $('.text-2').addClass('active') },
function(){ $('.text-1, .text-2').removeClass('active') }
)
});
and CSS
.text-1,
.text-2{
display:none;
}
.text-1.active,
.text-2.active{
display:block;
}
here's the Updated Fiddle with the optimized way to use it.
I'm making an assumption of what you're looking for...but try this jQuery code:
jQuery(document).ready(function ($) {
$('.img-1').mouseover(function () {
$('.text-1').addClass('text-1-active');
$('.img-1').addClass('img-1-active')
}).mouseout(function () {
$('.text-1').removeClass('text-1-active');
$('.img-1').removeClass('img-1-active');
});
$('.img-2').mouseover(function () {
$('.text-2').addClass('text-2-active');
$('.img-2').addClass('img-2-active')
}).mouseout(function () {
$('.text-2').removeClass('text-2-active');
$('.img-2').removeClass('img-2-active');
});
});
You are handing the hover event a list of functions. Just send it one that does eveything.
I.E.
jQuery(document).ready(function($) {
$('.img-1').hover(
function() {
$('.text-1').addClass('text-1-active');
$('.img-1').addClass('img-1-active');
$('.text-2').removeClass('text-2-active');
$('.img-2').removeClass('img-2-active');
}
);
$('.img-2').hover(
function() {
$('.text-2').addClass('text-2-active');
$('.img-2').addClass('img-2-active');
$('.img-1').removeClass('img-1-active');
$('.text-1').removeClass('text-1-active');
}
);
});
Try this
jQuery(document).ready(function($){
$('.img-1').hover(function(){
$('.text-1').toggleClass('text-1-active');
$('.img-1').toggleClass('img-1-active');
$('.text-2').toggleClass('text-2-active');
$('.img-2').toggleClass('img-2-active');
});
$('.img-2').hover(function(){
$('.text-2').toggleClass('text-2-active');
$('.img-2').toggleClass('img-2-active');
$('.img-1').toggleClass('img-1-active');
$('.text-1').toggleClass('text-1-active');
});
});
jQuery(document).ready(function($){
$('.img-1').hover(
function(){
$('.text-1').toggleClass('text-1-active');
$('.img-1').toggleClass('img-1-active');
}
)
$('.img-2').hover(
function(){
$('.text-2').toggleClass('text-2-active');
$('.img-2').toggleClass('img-2-active');
}
)
});
http://jsfiddle.net/w4mLtec8/10/
If I understand what's to be done, the approach itself used to solve the problem could be better. Basically, use CSS to your advantage. Here, I've reduced the number of times we call JQuery by taking a little time to set up the HTML and CSS.
Tag the corresponding text div with a number
Put the same number in a data attribute so the item to hover knows which text it's associated with
I believe the intent is to have one text hover active at a time, so we can simple remove all 'active'. Naturally, we'd one to restrict the selector here to only pull text hovers, but you get the idea.
//Javascript Code
$('.img').hover( function() {
var name = $(this).attr('data-name');
$('.text').removeClass('active');
$('.text[data-name="'+name+'"]').addClass('active');
});
http://jsfiddle.net/LkL9uo0k/1/
As far as I understand, you don't need classes to show and hide the text, use .show() and .hide() to take care of it, in the original js you're passing 4 functions to the hover event whereas only 2 are needed, one executes when the element is hovered and the second one when mouse exits the element causing hover event to stop.
Here's the modified js, take a look at the fiddle too -
jQuery(document).ready(function($){
$('.img-1').hover(
function(){
$('.text-1').show();
$('.text-2').hide();
},
function(){
$('.text-1, .text-2').hide();
}
);
$('.img-2').hover(
function(){
$('.text-2').show();
$('.text-1').hide();
},
function(){
$('.text-1, .text-2').hide();
}
);
});
FIDDLE
I'm basically hiding both texts on exit, if you want one text block to always stay visible you can hide the other one in hover 'exit' function. Here's the fiddle for that -
http://jsfiddle.net/w4mLtec8/9/

html div onclick event

I have one html div on my jsp page, on that i have put one anchor tag, please find code below for that,
<div class="expandable-panel-heading">
<h2>
<a id="ancherComplaint" href="#addComplaint"
onclick="markActiveLink(this);">ABC</a>
</h2>
</div>
js code
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
alert('123');
});
function markActiveLink(el) {
alert($(el).attr("id"));
}
here I when I click on div I got alert with 123 message, its fine but when I click on ABC I want message I want to call markActiveLink method.
JSFiddle
what is wrong with my code? please help me out.
The problem was that clicking the anchor still triggered a click in your <div>. That's called "event bubbling".
In fact, there are multiple solutions:
Checking in the DIV click event handler whether the actual target element was the anchor
→ jsFiddle
$('.expandable-panel-heading').click(function (evt) {
if (evt.target.tagName != "A") {
alert('123');
}
// Also possible if conditions:
// - evt.target.id != "ancherComplaint"
// - !$(evt.target).is("#ancherComplaint")
});
$("#ancherComplaint").click(function () {
alert($(this).attr("id"));
});
Stopping the event propagation from the anchor click listener
→ jsFiddle
$("#ancherComplaint").click(function (evt) {
evt.stopPropagation();
alert($(this).attr("id"));
});
As you may have noticed, I have removed the following selector part from my examples:
:not(#ancherComplaint)
This was unnecessary because there is no element with the class .expandable-panel-heading which also have #ancherComplaint as its ID.
I assume that you wanted to suppress the event for the anchor. That cannot work in that manner because both selectors (yours and mine) select the exact same DIV. The selector has no influence on the listener when it is called; it only sets the list of elements to which the listeners should be registered. Since this list is the same in both versions, there exists no difference.
Try this
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
alert('123');
});
$('#ancherComplaint').click(function (event) {
alert($(this).attr("id"));
event.stopPropagation()
})
DEMO
Try following :
$('.expandable-panel-heading').click(function (e) {
if(e.target.nodeName == 'A'){
markActiveLink(e.target)
return;
}else{
alert('123');
}
});
function markActiveLink(el) {
alert($(el).attr("id"));
}
Here is the working demo : http://jsfiddle.net/JVrNc/4/
Change your jQuery code with this. It will alert the id of the a.
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
markActiveLink();
alert('123');
});
function markActiveLink(el) {
var el = $('a').attr("id")
alert(el);
}
Demo
You need to read up on event bubbling and for sure remove inline event handling if you have jQuery anyway
Test the click on the div and examine the target
Live Demo
$(".expandable-panel-heading").on("click",function (e) {
if (e.target.id =="ancherComplaint") { // or test the tag
e.preventDefault(); // or e.stopPropagation()
markActiveLink(e.target);
}
else alert('123');
});
function markActiveLink(el) {
alert(el.id);
}
I would have used stopPropagation like this:
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
alert('123');
});
$('#ancherComplaint').on('click',function(e){
e.stopPropagation();
alert('hiiiiiiiiii');
});
Try out this example, the onclick is still called from your HTML, and event bubbling is stopped.
<div class="expandable-panel-heading">
<h2>
<a id="ancherComplaint" href="#addComplaint" onclick="markActiveLink(this);event.stopPropagation();">ABC</a>
</h2>
</div>
http://jsfiddle.net/NXML7/1/
put your jquery function inside ready function for call click event:
$(document).ready(function() {
$("#ancherComplaint").click(function () {
alert($(this).attr("id"));
});
});
when click on div alert key
$(document).delegate(".searchbtn", "click", function() {
var key=$.trim($('#txtkey').val());
alert(key);
});

jQuery toggle multiple elements

I can not make this piece of code work:
$("a.expand_all").on("click",function(){
$(this).text('Hide');
$('.answer').each(function () {
$(this).slideDown(150, function () {
$(this).show();
});
});
}, function () {
$(this).text('Expand');
$('.answer').each(function () {
$(this).slideUp(150, function () {
$(this).hide();
});
});
});
I'm trying to collapse expend multiple divs, but nothing happens on click event. I 'm using latest jQuery 1.10.1
It looks to me like you're using jQuery's .on method incorrectly. That method has some overloads, but none of them (sensibly) takes two functions.
If I understand what you're trying to do correctly, you just want to toggle some answer elements when a <a> tag is clicked. What you really need to do is have some way of determining if your answers are expanded or not. There are multiple ways to do that, but I've chosen to use a data element:
<a class="expand_all" href="#" data-collapsed="true">expand</a>
<p class="answer">I'm an answer!</a>
<p class="answer">Another answer</a>
Then your JavaScript can be simplified thusly:
$('a.expand_all').on("click",function(){
if( $(this).data('collapsed') ) {
$(this).text('hide').data('collapsed','');
$('.answer').slideDown(150);
} else {
$(this).text('expand').data('collapsed','true');
$('.answer').slideUp(150);
}
});
I simplified some of your constructs as well. In particular, in your code:
$('.answer').each(function () {
$(this).slideDown(150, function () {
$(this).show();
});
});
The .each is unnecessary. Just applying a jQuery method is essentially equivalent to calling .each. You rarely need to use .each. So that simplifies to this:
$('.answer').slideDown(150, function () {
$(this).show();
});
Then, .slideDown shows the element before it starts, so there's no need to call .show a second time. So we can get rid of the callback, simplifying all of this to:
$('.answer').slideDown(150);
You can see all of this in action here:
http://jsfiddle.net/Jammerwoch/sRnkw/5/
Lastly, the reason I asked whether any of your elements are dynamically added is because if they are, the way you are attaching them won't work. That is, the jQuery selectors run once, and then don't get re-run when you add new elements. So you have to be more clever. That's described in the jsfiddle above. Let me know if you need more clarification on that point.
That doesn't look like valid event binding to me, having the two functions there.
HTML - I added a div wrapper for event delegation
<div class="expando_content">
<a class="expand_all" href="#">Expand</a>
<p class="answer">I'm an answer!</a>
<p class="answer">Another answer</a>
<p>Dynamically added "expand more" goes below...it won't work :(</p>
<div id="thing"></div>
</p>
</p>
</div>
JS - moved the toggling functionality inside one function.
$(".expando_content").on("click", ".expand_all", function () {
if (!$('.answer').is(':visible')) {
$(this).text('Hide');
$('.answer').each(function () {
$(this).slideDown(150, function () {
$(this).show();
});
});
} else {
$(this).text('Expand');
$('.answer').each(function () {
$(this).slideUp(150, function () {
$(this).hide();
});
});
}
});
$('<a class="expand_all" href="#">expand more</a>').appendTo($('#thing'));
jsFiddle

Why does the jQuery file upload stop working after first upload?

I'm using the jQuery File Upload plugin. I'm hiding the file input and activating it upon clicking a separate button. (See this fiddle.)
HTML:
<div>
<button class="browse">Browse</button>
<input id="upload" type="file" style="display: none;" />
</div>
JavaScript:
var element = $("#upload");
$(".browse").click(function () {
$("#upload").trigger("click");
});
element.fileupload({
add: function () {
alert("add");
}
});
Notice that if you press the button then select a file, the add method is activated and you'll get an alert. Do it again, and you'll get another alert.
Now, see this fiddle. The only difference is that I've changed the following line
$("#upload").trigger("click");
to
element.trigger("click");
Notice that now, the first time you click the button then select a file, the add method is activated and you get the alert (just like before), but if you do it again, the add method never activates.
What is causing this difference in behavior?
This can also be solved by setting replaceFileInput to false, as stated by the documentation. This is because the plugin recreates the input element after each upload, and so events bound to the original input will be lost.
It looks as though the scope of element is being lost / changed after the add function. Resetting it like below seems to work.
var element = $("#upload");
$(".browse").click(function () {
element.trigger("click");
});
element.fileupload({
add: function () {
alert("add");
element = $(this);
}
});
Fiddle
Try this one: http://jsfiddle.net/xSAQN/6/
var input = $("#upload");
$(".browse").click(function () {
input.trigger("click", uploadit(input));
});
function uploadit(input){
$(input).fileupload({
add: function () {
alert("add");
}
});
}
Although there is one more way:
just change to this:
var element = $("#upload");
$(".browse").click(function () {
$("#upload").click(); // <----trigger the click this way
});
element.fileupload({
add: function () {
alert("add");
}
});

Categories

Resources