Changing from .live to .on - javascript

I know .live was depreciated and recently I was updating a page and realized I was using .live I would like to switch to .on but do not understand what to change. Here is my current code:
//Script for Choosing which form to display
$("#email-button, #text-button").live('click',
function(){
//figure out what button was clicked.
if(this.id === "email-button"){
var btnA = $(this);
var btnB = $("#text-button");
var divA = $('#email-form');
var divB = $('#text-form');
}
else{
btnA = $(this);
btnB = $("#email-button");
divA = $('#text-form');
divB = $('#email-form');
}
//make sure it is not already active, no use to show/hide when it is already set
if(btnA.hasClass('dark_button_span')){
return;
}
//see if div is visible, if so hide, than show first div
if(divB.is(":visible")){
divB.fadeOut("slow", function(){
divA.fadeIn("slow");
});
}
else{//if already hidden, just show the first div
divA.fadeIn("slow");
}
//Add and remove classes to the buttons to switch state
btnA.addClass('dark_button_span').removeClass('light_button_span');
btnB.removeClass('dark_button_span').addClass('light_button_span');
}
);
I had assistance writing the above script and do not know what to change. Simply changing .live to .on doesn't work.
Any help would be greatly appreciated!
Thanks!

The syntax for on is
$("containerElement").on("click", "targetElement(s)", function(){ });
So in your case it could be
$("body").on("click", "#email-button, #text-button", function(){ });
But being more specific than body is a good idea.

$(document).on('click', '#email-button, #text-button', function() {
// Your code
});
Should do the trick. See http://api.jquery.com/live/ and http://api.jquery.com/on/.
However, since you're using IDs, you probably don't even need .live() or delegating .on(). So the way I'd write that would be simply:
function doButtons(btnA, btnB, divA, divB) {
btnA = $(btnA); btnB = $(btnB); divA = $(divA); divB = $(divB);
// Make sure it is not already active, no use to show/hide when it is already set
if (btnA.hasClass('dark_button_span'))
return;
// See if div is visible, if so hide, then show first div.
if (divB.is(":visible")) {
divB.fadeOut("slow", function (){
divA.fadeIn("slow");
});
}
else // If already hidden, just show the first div.
divA.fadeIn("slow");
// Add and remove classes to the buttons to switch state.
btnA.addClass('dark_button_span').removeClass('light_button_span');
btnB.removeClass('dark_button_span').addClass('light_button_span');
}
$('#email-button').click(function () {
doButtons(this, '#text-button', '#email-form', '#text-form');
});
$('#text-button').click(function () {
doButtons(this, '#email-button', '#text-form', '#email-form');
});

jQuery's .on doesn't use event delegation unless you provide it a selector. In the above code, .live listens for events at the document, but that's far too much bubbling. If we were to implement it with .on though we would do the following:
var handler = function( e ) {
console.log( "Clicked" );
};
$( document ).on( "click", "#email-button, #text-button", handler );
Again though, it isn't really all that wise to listen for events on the document; ideally you would pick an element just above your selector. So if #email-button and #text-button have a common parent, you should use that in place of document.

Related

How can I observe changes to my DOM and react to them with jQuery?

I have this function where I toggle a class on click, but also append HTML to an element, still based on that click.
The problem is that now, I'm not listening to any DOM changes at all, so, once I do my first click, yup, my content will be added, but if I click once again - the content gets added again, because as far as this instance of jQuery is aware, the element is not there.
Here's my code:
(function($) {
"use strict";
var closePluginsList = $('#go-back-to-setup-all');
var wrapper = $('.dynamic-container');
$('#install-selected-plugins, #go-back-to-setup-all').on('click', function(event) {
$('.setup-theme-container').toggleClass('plugins-list-enabled');
if ( !wrapper.has('.plugins-container') ){
var markup = generate_plugins_list_markup();
wrapper.append(markup);
} else {
$('.plugins-container').hide();
}
});
//Below here, there's a lot of code that gets put into the markup variable. It's just generating the HTML I'm adding.
})(jQuery);
Someone suggested using data attributes, but I've no idea how to make them work in this situation.
Any ideas?
You could just do something like adding a flag and check for it before adding your markup.
var flag = 0;
$('#install-selected-plugins, #go-back-to-setup-all').on('click', function(event) {
$('.setup-theme-container').toggleClass('plugins-list-enabled');
if ( !wrapper.has('.plugins-container') ){
var markup = generate_plugins_list_markup();
if(flag == 0){
wrapper.append(markup);
flag = 1;
}
} else {
$('.plugins-container').hide();
}
});
If you want to add element once only on click then you should make use of .one() and put logic you want to execute once only in that handler.
Example :
$(document).ready(function(){
$("p").one("click", function(){
//this will get execute once only
$(this).animate({fontSize: "+=6px"});
});
$("p").on("click", function(){
//this get execute multiple times
alert('test');
});
});
html
<p>Click any p element to increase its text size. The event will only trigger once for each p element.</p>

How to remove class after it been added

So I need a little bit of help. I'm playing around with addClass and removeClass and I can't seem to remove a class after it's set. What I basically want is:
When someone clicks an h3, it adds to its parent div class
When someone clicks a div with added class, class needs to be removed
First step I got out of way and it's working
$(function(){
$('div h3.itemTitle').on('click', function(){
$(this).parent().addClass('active').siblings().removeClass('active');
});
});
Now when I define:
$(function(){
$('div.active').on('click', function(){
$(this).removeClass('active');
});
});
It does nothing, as if it doesn't see classes. It sets only those set in onload...
Help, anyone?
The child element "h3.itemTitle" already had a click event listener on it and the parent can't actually capture the click event.
Your $('div.active').on('click', ...) never actually fires because you click the h3 not the div.
I recommend this approach: http://jsfiddle.net/c3Q6Q/
$('div h3.itemTitle').on('click', function () {
// saves time not to write $(this).parent() everything so i store in a _parent var
var _parent = $(this).parent();
if (_parent.hasClass('active')) {
_parent.removeClass('active');
} else {
_parent.addClass('active').siblings().removeClass('active');
}
});
Try
$('body').on('click','div.active', function(){$(this).removeClass('active');});
Instead of
$('div.active').on('click', function(){$(this).removeClass('active');});
I would go with this way:
$('div').on('click', function(e){
var el = e.target;
if($(el).is('h3') && $(el).hasClass('itemTitle')){
$(this).parent().addClass('active').siblings().removeClass('active');
}else if($(el).is('div') && $(el).hasClass('active')){
$(this).removeClass('active');
}
});
Not sure why every is talking about elements generated outside of the initial DOM load.
Here's a JSFiddle showing that it works: http://jsfiddle.net/H25bT/
Code:
$(document).ready(function() {
$('.itemTitle').on('click', function() {
$(this).parent().addClass('active').siblings().removeClass('active');
});
/* $('.parent').on('click', function() {
$(this).removeClass('active');
}); */
$('.clicky').on('click', function() {
$(this).parent().removeClass('active');
});
});
The reason it's not working for you is that if you put the removeClass click event on the parent div itself, clicking on the child text causes a conflict with which click handler to use, and it won't work out. Code works fine if you don't assign the click to the parent div itself.

Stop element from disappearing when clicked

I'm writing a simple jQuery plugin that will dynamically place a div under a text box whenever it has focus. I've been able to get the position just about right in all the browsers.
I have to attach two event handlers as well on the focus and blur events of the textbox. And it works okay, but the problem is that the div that has been placed under the textbox closes even when we click on it. Now it makes sense why it would so happen, it's because the textbox loses focus, but is there a way I can stop it from happening?
I tried attaching this to the blur event handler -
if($(mainElem).is(":focus")) return;
where mainElem is the div that is shown below the textbox.
Here is a jsFiddle to illustrate the problem.
You are not going to be able to use the blur event if you want to place "clickable" elements in the div that shows. One way to solve this is to bind your event listener to a more global element like the document and then filter out the targets.
Here is a code sample:
$(document).on('click', function (e) {
var targetEl = e.target,
parent = $(e.target).parents()[0];
if (relElem[0] === targetEl || self[0] === targetEl || self[0] === parent) {
$(mainElem).show();
} else {
$(mainElem).hide();
}
});
Here is an update to your fiddle: http://jsfiddle.net/9YHKW/6/
This is a fiddle that I threw together for a project a while back: http://jsfiddle.net/MYcZx/4/
While it is not based off of your fiddle (and I do apologize) I believe that the functionality is much the same as what you're looking for. My example does not include input fields, but rather spans that hold the values. And while I'm not managing focus/blur, you could add a tabIndex attribute to the spans and then add a trigger on focus that would open the menu.
var $sub = $('.subscription');
$sub
.on('click', '.remove', function() {
$(this).parent().remove();
})
.on('click', 'li', function(e) {
var $this = $(this),
$parent = $this.parent(),
$options = $parent.children('li'),
$value = $parent.siblings('.value'),
isMulti = $parent.hasClass('multi'),
values = [];
if(!isMulti) {
$options.removeClass('active');
}
$this.toggleClass('active');
$options.filter('.active').each(function() {
values.push($(this).text());
});
$value.text(values.join(', ') || 'select');
$value[(values.length ? 'add' : 'remove') + 'Class']('set');
});
var $clone = $sub.clone(true);
$('.new')
.on('click', function() {
$(this).before($clone.clone(true));
});

Adding two click events to the same button only works once

Basically I'm trying to make a button be able to handle editing of an element. I want it so that when I click on the Edit button, it changes the text to Save Changes and adds a class which will then bind the button to another click event so that when they click Save Changes, it'll alert "Saved!" and change the text back to Edit. It does this perfectly once. If you continue to try to do it, it simply won't add the class or change the text anymore.
Here is a demo on jsfiddle
The code:
$(function() {
$button = $('button[name="edit"]');
$button.on('click', $button, function() {
var $that = $(this);
$that.text('Save Changes');
$that.addClass('js-editing');
if ($that.hasClass('js-editing')) {
$that.off('click').on('click', $that, function() {
alert('Saved!');
$that.text('Edit');
$that.removeClass('js-editing');
});
}
});
});​
Try this http://jsfiddle.net/bpD8B/4/
$(function() {
$button = $('button[name="edit"]');
$button.on('click', $button, function() {
var $that = $(this);
if($that.text()=='Edit'){
$that.text('Save Changes');
$that.addClass('js-editing');
}
else{
alert('Saved!');
$that.text('Edit');
$that.removeClass('js-editing');
}
});
});
You never add back the original handler after calling off(), which removes it.
That being said, it might be easier to have two buttons, with appropriate click handlers, and then use hide() and show() to alternate which one is available. To the end user it should look and act exactly the same, and to you it will be a lot less of a headache to code.
Example: http://jsfiddle.net/VgsLA/
I think in the end, this code is more robust and manageable.
This is just a logic problem. And with $that.off('click').on('click', $that, function() { you are delegating to itself, which is not how you should do it.
Here is a solution using your code:
$(function() {
$button = $('button[name="edit"]');
$button.on('click', $button, function() {
var $that = $(this);
if ($that.hasClass('js-editing')) {
alert('Saved!');
$that.text('Edit');
$that.removeClass('js-editing');
} else {
$that.text('Save Changes');
$that.addClass('js-editing');
}
});
});​
Demo

Update dynamic html attribute

What im trying to do is when the p inherits the class "active" that div.test will print the link rel correctly.
Currently if the page loads without the class assigned to the p tag, it will not. How can I make it happen when the p tag inherits the class "active" the link printed in div.test will get the rel printed correctly?
$(document).ready(function(){
var relvar = $('p.active').attr('rel');
$("div.test").html("<a rel='"+ relvar +"'>hello</a>");
$("p").click(function () {
$(this).toggleClass("active");
});
});
I am not sure what you asking. Are you saying that you would like this code:
var relvar = $('p.active').attr('rel');
$("div.test").html("<a rel='"+ relvar +"'>hello</a>");
To be run whenever the <p> element changes classes? If so, there is no "onchangeclass" event or anything like that, but you could actually create your own event to handle this:
$('p').bind('toggleActive', function() {
if($(this).hasClass('active')) {
var relvar = $(this).attr('rel');
$("div.test").html("<a rel='"+ relvar +"'>hello</a>");
}
}).click(function() {
$(this).toggleClass('active').trigger('toggleActive');
});
Check this code in action.
This is actually kind of roundabout - it would be simplest to just do the logic in the click handler itself. The main advantage of moving it to its own event is that if you then need to do this elsewhere in the code you can keep that logic separate and just "trigger" it as you need.
Not quite sure if this is what you are going for, but can you not handle it in the click code?
$(document).ready(function() {
$('p').click(function() {
$(this).toggleClass('active');
if ($(this).hasClass('active')) {
relvar = $(this).attr('rel');
$('div.test').html("<a rel='" + relvar + "'>hello</a>");
} else {
$('div.test').html("<a>hello</a>");
}
});
});
As far as I know, you will have to bind to some event in order for it to check and see if it needs to update the div.

Categories