jquery - why do i need live() in this situation? - javascript

I have a somewhat odd situation. I understand the premise of the live() and bind() functions, yet in a situation where i believe i dont need them, i seemingly do. I will explain.
I made an autosuggest in jquery. I included autosuggest.js at the top of my page. I then have an input field.
The basis of the JS works around:
$(".autosuggest").keyup(function()
{
}
This works - on keyup, my function executes etc as expected - i dont need to use live() or bind() as the input field is on the page from the get go...
Now.. I have also made a 'star rater' esque script.
I have various elements (which are styled), and on hover they are restyled...
$('.rating li').mouseover(function() {
}
does NOT work, YET
$('.rating li').live('mouseover',function() {
}
DOES.
Why do i need to use 'live' in this situation, when i dont in the case of the autosuggest?
Thanks

The only thing I can imagine that would cause this is a lack of a domready event. This should work:
$(function () {
$('.rating li').mouseover(function() {
}
});

the .ratings li isn't parsed yet when you have .mouseover() not working.
You can wrap it in $(document).ready(function() {...}); or use .live() (which creates the binding for any currently parsed at that point in the script and any elements added in the future).

Did you put $('.rating li').mouseover(function() {
}
in $(document).ready(function() {....} ?
Even if you include a .js file, if the elements in the page ('rating li') are not loaded, the bind will not be made.

Without seeing more of you code, it's difficult to say for sure. But my guess would be that your script is running before the pageload completes. try wrapping your bindings (and anything else that depends on particular dom elements to exist) with a call to $(document).ready(...).
something like this:
$(document).ready( function() {
$('.rating li').mouseover(function() {
// whatever
});
$(".autosuggest").keyup(function() {
// whatever else
});
});
If that's not it, then post more of your code, and we'll dig in further.
good luck.

Related

Javascript onclick fires on page load

Just starting out with front end development here, but despite my assuredly poor practices I've been enjoying things a lot. Basically I'm trying to add an onclick function to an element when the page loads. It was working fine as:
$("li a:contains('Search')").ready(function(){
$("li a:contains('Search')").on("click", function(){
$("li a:contains('Search)").text("test")});
});
But my programmer spidey-senses were strongly activated by the quite frankly gross state of this code, so I tried to refactor and my thought for the easiest first-step refactoring was this:
function replaceWithSearch(element){
element.text("test");
}
$("li a:contains('Search')").ready(function(){
$("li a:contains('Search')").on("click", replaceWithSearch($("li a:contains('Search')")));
});
However, when I changed to that, the onclick function now launches immediately. Is there a way to force the function to only be evaluated when called as a callback? I would prefer to have the function be reusable, also if you have any other comments on refactoring my code or best practices I would be very glad to hear them. Again, just starting out with Javascript and I would love to build some good practices.
Optimized code:
$(document).ready(function() {
$("li a:contains('Search')").bind("click", function() {
$(this).text("test");
});
});
If you prefer to use a function, proper way is:
$(document).ready(function() {
$("li a:contains('Search')").bind("click", replaceWithSearch);
});
And in the function you don't have to use argument:
function replaceWithSearch(){
$(this).text("test");
}
Live test case.
If your elements are created after page load, use the .on() like this:
$(document).on("click", "li a:contains('Search')", replaceWithSearch);
Updated fiddle.
Wrap the handler in a function like:
$("li a:contains('Search')").ready(function(){
$("li a:contains('Search')").on("click", function() {replaceWithSearch($("li a:contains('Search')"))});
});
That way, the handler is defined and associated with the click event, rather than executing immediately.

jquery .live() and .append()

So I'm currently using .append() to add a feature to all of the posts on a webpage, but when additional posts are loaded on the page, the appended features aren't included in the new content — I'm trying to come up with a way to make sure all of the new content has the appended feature too.
$(this).append('<div id="new_feature></div>');
Something like this?
$(this).live().append('<div id="new_feature></div>');
Maybe there's a way to make it constantly appending in a loop perhaps?
There is DOMNodeInserted event:
$('button').click(function() {
$('#appendme').append($('<div class="inner">').text(Math.random()));
})
$('#appendme').on('DOMNodeInserted','.inner',function() {
console.log(this);
});
DEMO
update: this seems not works in IE, try propertychnage event handler also ($('#appendme').on('DOMNodeInserted,propertychange') but i not sure, have no IE to check this right now.
update2: Domnode* seems deprecated according to mdn, they tell to use MutationObserver object instead
update3: seems here is no very crossbrowser solution for MutationEvents, see this answer, so my suggestion would be use code above, if event supported and fallback to setTimeOut or livequery option.
update4:
If you depend only on .append() you can patch jQuery.fn.append() like this:
jQuery.fn.append=function() {
return this.domManip(arguments, true, function( elem ) {
if ( this.nodeType === 1 || this.nodeType === 11 ) {
this.appendChild( elem );
$(elem).trigger('appended');
}
});
};
$('button').click(function() {
$('#appendme').append($('<div class="inner">').text(Math.random()));
})
$('#appendme').on('appended','.inner',function() {
console.log(this);
});
DEMO2
may be more correct is to spoof jQuery.fn.domManip like here
jQuery documentation:
Use of the .live() method is no longer recommended since later versions of jQuery offer better methods that do not have its drawbacks.
You can use setTimeout() function that can check for new <div>s every n milliseconds.
$(function(){
setInterval("Check4NewDivs();",1000);
});
So say this is a div with class="comment newdiv", so when it appears on the page for the first time, it has the class newdiv that will let the function know it was just dynamically created.
function Check4NewDivs(){
$(".comment .newdiv").each(function(){
$(this).append('<div class="new_feature"></div>').removeClass("newdiv");
});
}
It's append not appened.
live is a deprecated event handler. It's not used this way. use on instead.
http://api.jquery.com/live/
So, the following code will run when you click selector.
$(document).on('click', 'selector', function() {
$(this).append('<div id="new_feature></div>');
});
No, there is no standard way to do it like that. There was a proposal of the events that would be fired whenever the DOM elements are inserted etc., but you cannot rely on that.
Instead rely on either:
(preferably) callbacks - just invoke function ensuring existence of such appended snippets, whenever you pull something (but after you successfully pull it from server and insert into DOM, not sooner), or
constant checks - like using in setInterval() or setTimeout(), but this would be unnecessary processing and you will never get instant append, unless you will perform processing-heavy checks all the time,
use the on load function:
$(item).on('load',function(){
$(this).append('<div id="new_feature"></div>');
});
This will add append the item as a callback once the item has been loaded. I would also choose some sort of dynamic ID creator rather than always append stuff with the same ID, but thats just me.
you must bind to an element that already exists on the page. i have written an example where i make appended content live.
DEMO on JSFiddle
HTML
<div id="container">
<div id="features">
</div>
<br />
<a href='#' id='clickme'>click me to add feature</a>
</div>
JS
$(function() {
$('#clickme').on('click', function(e) {
$('#features').append('<div class="new_feature">new feature</div>');
});
$('#features').on('click', '.new_feature', function() {
alert('i am live.');
});
});

Why does my "plugin" execute only once?

This is my first attempt to write a jQuery plugin, this one is supposed to fade out the body, switch class, then make the body reappear and let the user switch class back. Unfortunately at this point it can't switch class more than once. How to fix it?
(function($) {
$.fn.flashClass= function(classId, element){
element="body"; //overriden for testing purpose
$(this).click(function() {
$(element).fadeOut("slow", function() {
$(element).toggleClass(classId);
});
$(element).fadeIn("slow", function() {
$(element).scrollTop(height);
});
});
};
})(jQuery);
EDIT:
At the end of the day, It turned out that I've pasted the wrong snippet with scrollTop callback of undefined variable height. After removing it and switching .click to .on , function works like a charm. However I am still interested why it worked only once.
Try the live() or on(), like following :
$(this).on('click',function() {...
Instead of
$(this).click(function() {...

not work class .numeric after add new input. what do i do?

why after add new input, class .numeric (normal number formatting) in js code not worked?
This way for normal number formatting is right?
What is your suggestion?
i not want use of plugin.
DEMO
$("input:text.numeric").keyup(function () {
$val = $(this).val().match(/[0-9]/g).reverse().join("").match(/[0-9]{1,3}/g).join(",").match(/./g).reverse().join("");
$(this).val($val)
})
With respect
If you add something to the page after it is done loading you will need to use the live() function on your scripts to make them work on the new data.
If you do something like:
$('#container').append('<div class="clickme">The text goes here</div>');
or
$('#container').load('script.php');
...they are both considered adding to the page.
Using live(), your code would become:
$("input:text.numeric").live('keyup', function () {
$val = $(this).val().match(/[0-9]/g).reverse().join("").match(/[0-9]{1,3}/g).join(",").match(/./g).reverse().join("");
$(this).val($val)
});
Read more here: http://api.jquery.com/live/
You need a future-proof event observer. Since the keyup bind is assigned to existing nodes, any nodes you create afterwards will not be bound to that event. You need to use live or delegate
Change
$("input:text.numeric").keyup(function () {
to
$("input:text.numeric").live('keyup',function () {
or
$('.find_input').delegate('input:text.numeric','keyup',function () {
delegate() is much more resource-friendly than live() but you need to know the parent ahead of time. In your example, I'd recommend it.
Working demo: http://jsfiddle.net/AlienWebguy/zgWr3/4/
Use the delegate()[docs] method to bind the handler to the .column container.
Example: http://jsfiddle.net/zgWr3/3/
$('.column').delegate("input.numeric:text",'keyup',function () {
$val = $(this).val().match(/[0-9]/g).reverse().join("").match(/[0-9]{1,3}/g).join(",").match(/./g).reverse().join("");
$(this).val($val)
});
This way, any "input.numeric:text" elements inside of .column will invoke the handler irrespective of when they're added to the DOM.
I also changed the selector around a little. Seems more understandable to me.

"#button_1" isn't affected by .click() or .hover()

Probably a rookie mistake, but my #button_1 ID isn't affected by the click() or hover() jQuery effects.
If someone could take a quick look at my JSFiddle, it would be greatly appreciated.
It's probably pretty obvious, but I want #button_1 to act as every other button. :)
Again, I suspect it's a pretty stupid mistake, something that I've overlooked.
Don't repeat so much code , try this and its working
Try line by line , its throwing error in somewhere in the code and breaking the bind events.
you have some error in hover or so , remove everything and have bind events, they are work.
You know this right ,when line 1 breaks in documentready , all bindings below may not get binded.
$(document).ready( function () {
$('#button_1,#button_2').click(function() {
alert('Handler for .click() called.');
});
});
Might I suggest condensing that code a little, to something closer to:
$('a div[class^="button"]').click(
function(e){
e.stopPropagation(); // prevent the click bubbling to the parent 'a' element
$('.button_active')
.removeClass('button_active')
.addClass('button_normal');
$(this).addClass('button_active').removeClass('button_normal');
});
JS Fiddle demo.
Edited in response to question from the OP:
Just to add, [the Fiddle updated by the OP to include the above code] actually sets "button_hover" as the class instead of "button_active", any idea why that would be?
Yep; that's in response to the specificity of the CSS selectors, I add and remove classes as needed in response events (rather than repeatedly checking for whether or not button_hover is set). As the element ends up with class="button_normal button_hover", and the order of the css (I think) places greater emphasis on the later-declared class, button_hover is maintained. It's late, and I'm a bit tired, but that's sort of (in a nutshell) what's happening.
The following demo incorporates everything (I think) that you need, and, coupled with revised CSS selectors, should do as you want:
$('a div[class^="button"]').hover(
function(){
$(this).addClass('button_hover').click(
function(e){
e.preventDefault();
$('.button_active')
.addClass('button_normal')
.removeClass('button_active');
$(this).addClass('button_active').removeClass('button_hover');
});
},
function(){
$(this).removeClass('button_hover');
});
CSS:
.button_active,
.button_normal.button_active { background: #000; }
.button_normal.button_hover { background: #ff0; }
.button_normal { background: #d89; }
JS Fiddle demo.
References:
attribute-begins-with (^=) selector.
e.stopPropagation().
removeClass().
addClass().

Categories