JS BIN Attempt
Attempting to follow along with the example, but it doesn't seem to work. A little confused, as it is Mozilla.
Mozilla
As #Xaerxess mentions, you need to call the "setupButtons" function when the DOM is ready for manipulation; typically one does that by adding an event handler to the window "load" event, which happens when the page is entirely loaded (which is what the jQuery idiom $(document).ready(function(){...}); does.
Try adding this snippet to the end of your existing <script> element to accomplish that goal using plain JavaScript, no jQuery needed:
window.onload = function() { setupButtons(); };
Another typical way of doing this is to use the element.addEventListener function; the difference is that you can add multiple event callbacks this way and they won't overwrite each other:
window.addEventListener('load', function() {
setupButtons();
}, false);
You didn't call setupButtons function on page load, only defined it. If you include jQuery, add:
$(document).ready(setupButtons);
in you script tag and it'll work.
Related
I use window.onload() to create a new div with text inside it. It works if I add it to a button (onclick) but it will not fire when I am using it with window.onload(). I have to other window.onload in the same js file that works well.. Any idea how I can fix this and what the problem might be?
My code:
function addDate() {
var addDiv = document.createElement('div');
addDiv.innerHTML = "test";
document.getElementById('date').appendChild(addDiv);
}
window.onload = addDate();
1)The way you're binding, you can have just one method attached to an event. You need to add an event listener for what you want.
window.addEventListener("load", function() { alert("hello!");});
Setting directly a method to the onload event will replace any previously attached method. But if you use listeners instead, you can have many of them bound to an event.
2)If you comment out the onload in your external file, when the document.getElementsByClassName("bar") is called, your document isn't ready yet, then, it will return 0 items.
3)Use the addEventListener as I explained in the first point. If you apply this in both places, it will work like a charm.
if you want more info on window.onload check it out here
When you say "I have to other window.onload in the same js file" I'm assuming you mean "I have two other...", and that would be the problem right there.
If you say:
window.onload = doThis;
window.onload = doThat;
Only doThat gets called. Also, notice... no parentheses! It's window.onload = doThat, NOT window.onload = doThat().
If you use:
window.addEventListener('load', addDate);
Then you can get the function to be called, and not mess up other functions being called.
I would suggest you use a library such as jQuery to do JavaScript work. It's much easier to deal with problems like those. The initialization makes use of the ready function.
$(document).ready(function() {
addDate()
});
You can add as many ready() calls as you need (one per script).
Under the hood, as mentioned by others, it will use window.addEventListener(<event name>, <inline function>). So we added a little bit of code, things will be a tad bit slower, but you're going to have code that works much faster.
Thanks everyone, the problem was that I was using window.onload two times in my code. And the solution, as you all said, was to use window.addEventListener instead. I also removed the parantheses.
So for anyone else getting the same problem, use window.addEventListener to trigger the code instead. Like:
window.addEventListener('load', databaseToNewElement);
window.addEventListener('load', addDate);
I am using an infinite scroll plugin which uses ajax.
When the 'next page' is loaded via ajax, all other ajax related scripts that are on the next page do not work. I have been told that I have to use 'delegated events'(ie change $(id).click() to $(document).on) - problem is that means editing multiple plugins and changing dozens of function calls.
Is there any way I can avoid changing everything to $(document).on and do something cool with the infinite scroll?????
I'd much rather modify the infinite scroll plugin rather than modifying other ajax related plugins to make them fit.
Unfortunately you have very few options here, and switching to delegated events is by far the best of them.
The problem is that your old code was assigning behaviour to "particular elements" when what it should really have been doing is creating page-wide responses to "certain types of actions".
I see 3 possibilities, and only one of them is guaranteed to work.
Run any scripts that are needed on new pages each time a new page is loaded. The downside here being that unless you are careful about also "tearing down" between content loads you will have behaviours repeating or colliding with each other (eg: double popups, broken animations).
Encapsulate the dynamic areas in <iframe>s. Depending on your architecture this may or may not be possible, and certainly won't be easy to integrate with some kind of infinite scrolling plugin which already expects a certain page structure.
Bite the bullet and fix the crappy code.
Loading scripts inside your ajax loaded content is a bad way to start with anyway. What you need is event delegation to attach itself to any dynamically added elements.
$("body").on("click", ".yourclass", function() {
//This function will run for every element with `yourclass` class you load via ajax
});
If you must keep using .click() then you must have a function you can call on the new content to re-hook the events every time you add more content to the page.
e: though it is worth noting that a change from .click to .on can often be handled by a properly structured find/replace
Event delegation is the correct solution. The issue is that the HTML elements on the "next page" were not part of the DOM when the page loaded. Therefore, if you did something like:
$(function() {
$('#some-element-on-the-next-page').click(function() {
foo();
});
});
Your handler did not bind.
I wouldn't attach the events to $(document). I would attach them to the closest parent which is available when the DOM loads. For example, the body tag or the fixed width wrapper which is the first child of the body (assuming your layout uses this type of structure.)
Make sure that the element that you attach to is not emptied with .empty() or repopulated with .html() as that will break the binding. Attaching the delegated handlers lower down on the DOM tree will give you better performance since the events will not have to bubble all the way up to the document node to fire your methods.
You shouldn't need to rewrite all of your functions and plugins, just the bindings to the events that fire them.
I typically use the module pattern and de-couple my method definitions from the click handlers. All of my methods are defined in the outer closure. I'll have a "document ready" section where I bind user events like clicks.
For example:
var myModule = (function() {
var public = {};
public.foo = function() {
// do something cool here
};
// document ready
$(function () {
$('#site-container').on('click', '.js-foo', function() {
public.foo();
});
});
return public;
})();
If you need to change the bindings in the future you will only need to change the call inside the document ready section.
I only need to check that the page is loaded (without dynamic objects that might be modified after page appears fully)
I know JQuery's function: "ready()"
Will this function be relevant in the described-above case?
Is there another / better way?
window.onload isn't a jQuery function, it's a DOM event.
If using jQuery the best way to check whether the page is loaded is to handle the ready event which can be done in various ways
Shortest
$(function() {
// DOM initialized
});
Short
$.ready(function() {
// DOM initialized
});
Longer
$(document).ready(function() {
// DOM initialized
});
Longest
jQuery(document).ready(function() {
// DOM initialized
});
Just to mention that you have an alternative to jQuery' methods . You can use pure JavaScript solution:
window.addEventListener("load", function load(event){ // defining load event listener
window.removeEventListener("load", load, false); //remove listener, no longer needed
// window is loaded , you can use its DOM
},false);
This way is good in cases when you , for example , have small/lightweight pages and to load external libraries/frameworks is absolutely unnecessary .
I created a simple javascript that uses jquery.tools.min.js library.
My javascript looks like this:
function testFunction() {
$("img").click(function() {
alert("Handler for .click() called.");
});
console.log("what's up?");
}
$(testFunction);
So when I try it on a simple HTML page, I get my alert message when I click on an Image.
I added the exact same javascript in my GWT application.
When the application loads I see the console.log message, but nothing ever happens when I click on any image on my app.
Why is that so ? Is it because the testFunction() doesn't apply to the dynamically created images ? Or is it because the event was overriden by GWT ?
Thank you.
EDIT
I tried recalling my function after I create my content:
public native final void recallFunction() /*-{
$wnd.console.log('again1');
$wnd.testFunction();
$wnd.console.log('again2');
}-*/;
I can see my log messages but no click event is fired.
EDIT 2:
When I run :
$("img").click(function() {
alert("Handler for .click().");
});
or
testFunction();
directly in Firebug's console, the event is correctly attached to my images!!
I tried also calling testFunction() in the window's onload event but with no better luck.
I assume you include jQuery library itself and it is 1.7 or later.
If your images do not exist in the DOM when at the time testFunction is defined use "on()".
function testFunction() {
$("img").on('click',function() {
alert("Handler for .click() called.");
});
console.log("what's up?");
}
When using jQuery in JSNI code, you must use $wnd.jQuery or $wnd.$ instead of $. See also this question on Google Groups.
Instead of Writing JSNI over Jquery you can easily start of with gwtquery http://code.google.com/p/gwtquery/
You will benefit from actually from both Jquery approach and also GWT performance optimization .
GwtQuery benefits over Jquery -
http://manolocarrasco.blogspot.in/2011/01/gwtquery-css-selectors-performance.html
jQuery vs GQuery Benchmark
Also if it is only nice scroll you are trying to achieve you can take a look -
GWT CustomScrollPanel example
and
Custom Scrollbar in GWT
Are you adding any other event listeners (in gwt) to the image in question?
There can only be one on-click handler, and if you are setting them in both enviros, you will run into hurt.
Gwt-Query, as mentioned in another comment, is kind enough to delegate back to gwt internal events (since it knows the syntax for event handlers).
You may want to use firebug object inspection on your image.
Try console.log($("img")) and see what you get.
Look for __listener variable on your images; that's the gwt listener. Check out DOMImplStandard ~line 200 to see what happens when you sink an event in gwt.
I'm not sure how jquery attaches events, but I did see this in the mozilla spec:
"If multiple identical EventListeners are registered on the same EventTarget with the same parameters, the duplicate instances are discarded. They do not cause the EventListener to be called twice, "
https://developer.mozilla.org/en/docs/DOM/element.addEventListener
This is actually a bigger question because I know there are several ways to solve this problem but I will try to sum it up.
What I try to do: I am using this jQuery plugin to upload files via Flash http://www.uploadify.com/. However, the element #fileInput that I supposed to bind this function to is a live element which is generated after the page loaded: $('#fileInput').uploadify(). The reason #fileInput is a live element is because I use FancyBox to popup a DIV and this FancyBox basically just "cloned" the inner html of the DIV.
What happened: When I clicked "BROWSE" to upload a file, there is no progress bar for upload. The reason is because the Uploadify could not bind to live elements.
Questions:
1. I tried to replace bind() with live() in uploadify code but that did not work because bind() allows to pass [data]. The LiveQuery plugin http://docs.jquery.com/Plugins/livequery does not have the same syntax as bind() either. Is there anything similar to bind but works for live elements?
If I don't try to replace bind() function and keep uploadify code the same. Does anyone know how to change code in FancyBox so that it WILL NOT make a clone to generate live elements? I know this is a hard question too.
Note: FancyBox site seems dead --> http://www.visual-blast.com/javascript/fancybox-jquery-image-zooming-plugin/
Thank you very much!
You might consider changing the FancyBox code to support calling a callback function after it clones the HTML. Then, put the uploadify() call in the callback function.
You could overload the live method, making it support data as the second parameter:
jQuery.fn.live = (function(_live){
return function( type, data, fn ) {
var _fn;
if ( jQuery.isFunction(fn) ) {
_fn = function(e) {
e.data = data;
return fn.call( this, e );
};
}
return _live.call( this, type, _fn || fn || data );
};
})(jQuery.fn.live);
Replacing all instances of bind(...) with live(...) should now work.
Note: you'll have to put the overloaded method above everything else.
From my experience , the only way I have found to do this is by using livequery
It has a similar syntax, and in your case to bind uploadify on a live element, you would use
$('#fileInput').livequery(function(){
$(this).uploadify();
})
Livequery accepts functions without events, and executes them everytime there is a change in the DOM
How is the element generated? If its fetched from the server using jQuery you can use a more hackish way of fixing it, simply put jQuery runs eval() on any script tags it runs into so you could just put:
<script type='text/javascript'>
$(function(){
$('#fileInput').uploadify();
});
</script>
In the fetched html and it'll bind it on load instead of trying to watch over it live. Bonus points, if you fetch the html again it'll be unbound.