I wrote a little pager which removes and rewrites content. I have a function called after loading the page, it shall be executed after changing the page as well. Because I do not wat to implement the function twice (on initialisation and after changing the page) I tried bind()/live() and a simple function.
The function looks like this:
jQuery('.blogentry').each(function (){
jQuery(this).click(function(){
//Clicking on the element opens a layer, definitely works - I tested it
});
});
It is executed after initialisation, for executing it after page changes as well I tried the following:
jQuery('.nextPage, .prevPage').click(function changePage(){
// Changing page and rewriting content
showEntry();
});
//...
showEntry();
//...
function showEntry(){
jQuery('.blogentry').each(function (){
jQuery(this).click(function(){
//Clicking on the element opens a layer, definitely works - I tested it
});
});
}
But the function is not executed if put inside a function (lol) and called via showEntry();
Afterwards I tried to bind the function...
jQuery('.nextPage, .prevPage').click(function changePage(){
// Changing page and rewriting content
jQuery('.blogentry').bind("click", showEntry);
});
//...
jQuery(this).click(function showEntry(){
//Clicking on the element opens a layer, definitely works - I tested it
});
Did not work either. Code after the bind()-line would not execute as well.
I thought maybe it's a problem to bind to an event function, if an event is already given via the parameter so i also tried this:
jQuery('.nextPage, .prevPage').click(function changePage(){
// Changing page and rewriting content
jQuery('.blogentry').bind("click", showEntry);
});
//...
function showEntry(){
//Clicking on the element opens a layer, definitely works - I tested it
});
}
No success at all. Maybe I cannot call the function from inside the function regarding to the bind()? Maybe I just do not understand the bind()-function at all? I also tried the live() function since it seemed to fit better, as I am rewriting the content all the time. But it had the same effect: none...
The simplest way to implement this should be
jQuery('.blogentry').live('click', function() { /* onclick handler */ });
This should bind the function to every blogentry on the page at the moment of the call and all the blogentries that are added to the page later on.
Additional notes:
In $(foo).each(function() { $(this).click(fun); }); the each is unnecessary - $(foo).click(fun); is enough.
$(foo).bind('click', fun); is functionally equivalent to $(foo).click(fun) - it does not matter which one you use.
You can use delegate or bind. don't call the function like that, just create a delegate with .blogentry and it should update even after you load a new page via ajax. It will automatically do this.
$("#blogcontainer").delegate(".blogentry", "click", function(){ //open layer });
This should work for you
$(body).delegate(".blogentry", "click", function(){
showEntry();
});
alternaltivly you can use event delegation
$(document).ready(function () {
$('#blogcontainer').click( function(e) {
if ( $(e.target).is('.blogentry') ) {
// do your stuff
}
});
});
hence, no need to bind each blogentry at creation or reload, and it's (slightly) faster.
Related
I'm using infinite-scroll, a plugin that replaces the standard pagination by fetching new pages through ajax.
The problem with this is that jquery functions don't register the new posts, causing functions like these:
jQuery(document).ready(function($) {
$('.vote-a, .vote-b').click(function() {
//do stuff
});
$('.vote-b').click(function() {
//do other stuff
});
});
to stop running. To solve this, the plugin provides callback, and let's you include codes that you'd like to be called whenever a new page is loaded.
What I did was simply putting the code above there. It worked but I ended up with several instances of the same code.
So the question is how do I solve this? One way I can think of is destroying/removing the old instance with each callback.
Or somehow reinitiliaze/restart/invoke the function.
You can register the click events at a root level instead of by finding the individual elements and assigning a click event to them.
https://api.jquery.com/on/
and the older method
https://api.jquery.com/live/
jQuery(document).ready(function($) {
$(document).on('click', '.vote-a, .vote-b', function() {
//do stuff
});
$(document).on('click', '.vote-b', function() {
//do other stuff
});
});
I want to make function working only on page with specified element.
I have search page, search fields and results are in search-block div.
I want to bind function to this block, so function will not work on other pages (without <div id='search-block>...</div>)
I have next js code atm:
$(document).ready(function()
// instructions for another page (handlers for some links)
$(function(){
setInterval(findSomething,1000);
});
});
It working fine on page with search-block div, but it works fine on the other pages too. Browser tries to run this function on all other pages. I don't need this.
I tried jquery bind, but it now worked for me, don't know why :(
$("#search-block").bind(function(){
setInterval(findSomething,1000);
});
How I can bind handler to speciges too.fied block?
Instead of bind you have to check for the length of that elem:
$(document).ready(function(){
if($('#search-block').length > 0){ // <---checks the availability
setInterval(findSomething,1000);
}
});
Bind is always used with an event to bind to:
$( "#foo" ).bind( "mouseenter mouseleave", function() {
});
if you want to execute that only when the block is available on the page, use this:
if ($('#search-block').length) {
setInterval(findSomething,1000);
}
This checks the number of times #search-block is found on the page and if it is not 0(false) it executes the code.
Does anyone happen to know IF and HOW I could re-call all on-load event handlers? I'm referencing some .js files that I DON'T have control over, and these .js libraries do their initialization in $(document).ready(), and unfortunately don't provide any easy function to re-initialize.
I'm currently trying to replace a large div block with content from an ajax call, and so I have to re-initialize the external libraries. So, it would be nice just to call $(document).ready() in order to re-initialize EVERYTHING.
So far, I've tried this on the ajax call:
success: function(data) {
alert('1'); // Displays '1'
$('#content').html(data);
alert('2'); // Displays '2'
$(document).ready();
alert('3'); // Does not display
}
Calling $(document).ready(); fails quietly too. JavaScript console shows no errors. Does anyone know if this is possible (without modifying javascript library files)?
Since you asked how to do it without modifying the external JS files, I'll answer that way. I've traced through the .ready() function in jQuery in the debugger and it appears that the root function that gets called when the page is ready is this:
jQuery.ready();
But, it appears you cannot just call it again to accomplish what you want because it appears that when it fires the first time, it unbinds from the functions that were previously registered (e.g. forgetting them). As such, calling jQuery.ready() manually a second time does not retrigger the same function calls again and I verified that in the debugger (breakpoint was only hit once, not second time).
So, it appears that you cannot solve this problem without either changing the jQuery implementation so it doesn't unbind (to allow multiple firings) or changing each piece of ready handler code to use your own events that you can fire as many times as you want.
I did something like:
// When document is ready...
$(function(){
onPageLoad();
});
function onPageLoad(){
// All commands here
}
Now I can call this function anytime I need.
A simple way to achieve this is just to invent your own event like this:
$(document).bind('_page_ready', function() { /* do your stuff here */});
Then add this:
$(function() { $(document).fire('_page_ready'); }); // shorthand for document.ready
And last, whenever you need to run it again you simply call this:
$(document).fire('_page_ready');
[Edit]
If you really can't edit the external script-files I've made a jsFiddle that makes what you want to do possible, you can take a look at the code here: http://jsfiddle.net/5dRxh/
However, if you wan't to use this, it's important that you add this script RIGHT AFTER you include jQuery, like this:
<script src="jquery.js" type="text/javascript"></script>
<script>
//script from jsFiddle (only the plugin part at the top).
</script>
<!-- All the other script-files you want to include. -->
You can trigger document.ready second time if you change entire body content:
$('body').html($('body').html())
I don't think that this can be done since jquery unbinds the ready event after it is executed. From the source:
// Trigger any bound ready events
if ( jQuery.fn.trigger ) {
jQuery( document ).trigger( "ready" ).unbind( "ready" );
}
You can do this simple.
Make a function:
function REinit() {
/// PLACE HERE ALL YOUR DOC.READY SCRIPTS
}
Place just the Reinit() function inside doc.ready:
$(document).ready(function(){
REinit();
});
then after an ajax action just call
REinit();
I think it is straight forward to just change the ready event to pjax success
Change it from:
$(document).ready(function() {
// page load stuff
});
To:
$(document).on('ready pjax:success', function() {
// will fire on initial page load, and subsequent PJAX page loads
});
This will be what you want, just hold the ready event until you are really ready.
https://api.jquery.com/jquery.holdready/
Or, try this:
jQuery.extend ({
document_ready: function (value) {
$(document).ready (value);
$(document).ajaxComplete (value);
}/* document_ready */
});
And instead of defining a function by saying:
$(document).ready (function () { blah blah blah });
say:
jQuery.document_ready (function () { blah blah blah });
Explanation:
Any function loaded to "document_ready" will be automatically loaded into both "$(document).ready ()" and "$(document).ajaxComplete ()" and will fire under both circumstances.
I just had the problem that my ajax code only worked if it gets called by the $(document).ready(function(){}); and not in a regular function, so I couldn't wrap it.
The code was about loading a part of my page and because of some loading errors I wanted it to be called again after a timeout.
I found out that the code doesn't have to be in the $(document).ready(function(){}); but can be run by it and can also be called by itself.
So after I read many solutions from different pages now I've got this code mixed together:
$(document).ready(loadStuff);
function loadStuff(){
$.ajax({
type: "POST",
url: "path/to/ajax.php",
data: { some: data, action: "setContent"},
timeout: 1000, //only one second, for a short loading time
error: function(){
console.log("An error occured. The div will reload.");
loadStuff();
},
success: function(){
$("#divid").load("path/to/template.php"); //div gets filled with template
}
});
}
I'm placing content on my page through an ajax (post) request like so:
$("input#ViewMore").click(function() {
var data = { before: oldestDate, threadId: 1 };
$.post("/Message/More", data,function(html) {
$('tbody#posts').prepend(html);
return false;
},
"html");
return false;
});
with the html coming back looking something like:
<div id="comment">Message output Quote</div>
This is all working fine and dandy, everything appears as it should, no problems.
The problem occurs when I have an event hooked into the "quote" anchor that has been added through the ajax call. Specifically, a jQuery event on that anchor does not fire. Why?
For instance:
$("#quote).click(function() { ... });
Does nothing. Acts like there is no event on it. I know it is working on other anchors on the page that were not added through a ajax request, so there is not a code error there, plus if I refresh the page it will then fire correctly. Is there some reason that this is happening, do I need someway to reinitialize that event on the anchor tag somehow? Any ideas?
Working with jQuery 1.3.1 (didn't work with 1.2.6 either) so I believe it is my implementation not code itself.
You can use Events/live of jQuery 1.3, live will bind a handler to an event for all current - and future - matched elements.
When the new content is added to the page with Ajax you have to re-register all the events to those new elements.
Changed to
$('#quote').live("click", function() { ... }
and
$("input#ViewMore").live("click", function() { ... }
Doesn't seem to work
CMS's answer helped, but here's how it ended up:
The view more button event remained the same as it was outside of the AJAH request that added it:
$("input#ViewMore").click( function() { ... }
Elements that had events that were being added in and out of the AJAH request needed to use the live method:
$('#quote').live("click", function() { ... }
Works like a charm!
I'm using jQuery to wire up some mouseover effects on elements that are inside an UpdatePanel. The events are bound in $(document).ready . For example:
$(function() {
$('div._Foo').bind("mouseover", function(e) {
// Do something exciting
});
});
Of course, this works fine the first time the page is loaded, but when the UpdatePanel does a partial page update, it's not run and the mouseover effects don't work any more inside the UpdatePanel.
What's the recommended approach for wiring stuff up in jQuery not only on the first page load, but every time an UpdatePanel fires a partial page update? Should I be using the ASP.NET ajax lifecycle instead of $(document).ready?
An UpdatePanel completely replaces the contents of the update panel on an update. This means that those events you subscribed to are no longer subscribed because there are new elements in that update panel.
What I've done to work around this is re-subscribe to the events I need after every update. I use $(document).ready() for the initial load, then use Microsoft's PageRequestManager (available if you have an update panel on your page) to re-subscribe every update.
$(document).ready(function() {
// bind your jQuery events here initially
});
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function() {
// re-bind your jQuery events here
});
The PageRequestManager is a javascript object which is automatically available if an update panel is on the page. You shouldn't need to do anything other than the code above in order to use it as long as the UpdatePanel is on the page.
If you need more detailed control, this event passes arguments similar to how .NET events are passed arguments (sender, eventArgs) so you can see what raised the event and only re-bind if needed.
Here is the latest version of the documentation from Microsoft: msdn.microsoft.com/.../bb383810.aspx
A better option you may have, depending on your needs, is to use jQuery's .on(). These method are more efficient than re-subscribing to DOM elements on every update. Read all of the documentation before you use this approach however, since it may or may not meet your needs. There are a lot of jQuery plugins that would be unreasonable to refactor to use .delegate() or .on(), so in those cases, you're better off re-subscribing.
<script type="text/javascript">
function BindEvents() {
$(document).ready(function() {
$(".tr-base").mouseover(function() {
$(this).toggleClass("trHover");
}).mouseout(function() {
$(this).removeClass("trHover");
});
}
</script>
The area which is going to be updated.
<asp:UpdatePanel...
<ContentTemplate
<script type="text/javascript">
Sys.Application.add_load(BindEvents);
</script>
*// Staff*
</ContentTemplate>
</asp:UpdatePanel>
User Control with jQuery Inside an UpdatePanel
This isn't a direct answer to the question, but I did put this solution together by reading the answers that I found here, and I thought someone might find it useful.
I was trying to use a jQuery textarea limiter inside of a User Control. This was tricky, because the User Control runs inside of an UpdatePanel, and it was losing its bindings on callback.
If this was just a page, the answers here would have applied directly. However, User Controls do not have direct access to the head tag, nor did they have direct access to the UpdatePanel as some of the answers assume.
I ended up putting this script block right into the top of my User Control's markup. For the initial bind, it uses $(document).ready, and then it uses prm.add_endRequest from there:
<script type="text/javascript">
function BindControlEvents() {
//jQuery is wrapped in BindEvents function so it can be re-bound after each callback.
//Your code would replace the following line:
$('#<%= TextProtocolDrugInstructions.ClientID %>').limit('100', '#charsLeft_Instructions');
}
//Initial bind
$(document).ready(function () {
BindControlEvents();
});
//Re-bind for callbacks
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function() {
BindControlEvents();
});
</script>
So... Just thought someone might like to know that this works.
Upgrade to jQuery 1.3 and use:
$(function() {
$('div._Foo').live("mouseover", function(e) {
// Do something exciting
});
});
Note: live works with most events, but not all. There is a complete list in the documentation.
You could also try:
<asp:UpdatePanel runat="server" ID="myUpdatePanel">
<ContentTemplate>
<script type="text/javascript" language="javascript">
function pageLoad() {
$('div._Foo').bind("mouseover", function(e) {
// Do something exciting
});
}
</script>
</ContentTemplate>
</asp:UpdatePanel>
,since pageLoad() is an ASP.NET ajax event which is executed each time the page is loaded at client side.
My answer?
function pageLoad() {
$(document).ready(function(){
etc.
Worked like a charm, where a number of other solutions failed miserably.
I would use one of the following approaches:
Encapsulate the event binding in a function and run it every time you update the page. You can always contain the event binding to specific elements so as not to bind events multiple times to the same elements.
Use the livequery plug-in, which basically performs method one for you auto-magically. Your preference may vary depending on the amount of control you want to have on the event binding.
function pageLoad() is very dangerous to use in this situation. You could have events become wired multiple times. I would also stay away from .live() as it attaches to the document element and has to traverse the entire page (slow and crappy).
The best solution I have seen so far is to use jQuery .delegate() function on a wrapper outside the update panel and make use of bubbling. Other then that, you could always wire up the handlers using Microsoft's Ajax library which was designed to work with UpdatePanels.
When $(document).ready(function (){...}) not work after page post back then use JavaScript function pageLoad in Asp.page as follow:
<script type="text/javascript" language="javascript">
function pageLoad() {
// Initialization code here, meant to run once.
}
</script>
I had a similar problem and found the way that worked best was to rely on Event Bubbling and event delegation to handle it. The nice thing about event delegation is that once setup, you don't have to rebind events after an AJAX update.
What I do in my code is setup a delegate on the parent element of the update panel. This parent element is not replaced on an update and therefore the event binding is unaffected.
There are a number of good articles and plugins to handle event delegation in jQuery and the feature will likely be baked into the 1.3 release. The article/plugin I use for reference is:
http://www.danwebb.net/2008/2/8/event-delegation-made-easy-in-jquery
Once you understand what it happening, I think you'll find this a much more elegant solution that is more reliable than remembering to re-bind events after every update. This also has the added benefit of giving you one event to unbind when the page is unloaded.
FWIW, I experienced a similar issue w/mootools. Re-attaching my events was the correct move, but needed to be done at the end of the request..eg
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function() {...
Just something to keep in mind if beginRequest causes you to get null reference JS exceptions.
Cheers
pageLoad = function () {
$('#div').unbind();
//jquery here
}
The pageLoad function is perfect for this case since it runs on the initial page load and every updatepanel async postback. I just had to add the unbind method to make the jquery work on updatepanel postbacks.
http://encosia.com/document-ready-and-pageload-are-not-the-same/
My answer is based on all the expert comments above, but below is the following code that anyone can use to make sure on each postback and on each asynchronous postback the JavaScript code will still be executed.
In my case, I had a user control within a page. Just paste the below code in your user control.
<script type="text/javascript">
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(EndRequestHandler);
function EndRequestHandler(sender, args) {
if (args.get_error() == undefined) {
UPDATEPANELFUNCTION();
}
}
function UPDATEPANELFUNCTION() {
jQuery(document).ready(function ($) {
/* Insert all your jQuery events and function calls */
});
}
UPDATEPANELFUNCTION();
</script>
Update Panel always replaces your Jquery with its inbuilt Scriptmanager's scripts after every load. Its better if you use pageRequestManager's instance methods like this...
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(onEndRequest)
function onEndRequest(sender, args) {
// your jquery code here
});
it will work fine ...
Use below script and change the body of the script accordingly.
<script>
//Re-Create for on page postbacks
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function () {
//your codes here!
});
</script>
In response to Brian MacKay's answer:
I inject the JavaScript into my page via the ScriptManager instead of putting it directly into the HTML of the UserControl. In my case, I need to scroll to a form that is made visible after the UpdatePanel has finished and returned. This goes in the code behind file. In my sample, I've already created the prm variable on the main content page.
private void ShowForm(bool pShowForm) {
//other code here...
if (pShowForm) {
FocusOnControl(GetFocusOnFormScript(yourControl.ClientID), yourControl.ClientID);
}
}
private void FocusOnControl(string pScript, string pControlId) {
ScriptManager.RegisterStartupScript(this.Page, this.Page.GetType(), "focusControl_" + pControlId, pScript, true);
}
/// <summary>
/// Scrolls to the form that is made visible
/// </summary>
/// <param name="pControlId">The ClientID of the control to focus on after the form is made visible</param>
/// <returns></returns>
private string GetFocusOnFormScript(string pControlId) {
string script = #"
function FocusOnForm() {
var scrollToForm = $('#" + pControlId + #"').offset().top;
$('html, body').animate({
scrollTop: scrollToForm},
'slow'
);
/* This removes the event from the PageRequestManager immediately after the desired functionality is completed so that multiple events are not added */
prm.remove_endRequest(ScrollFocusToFormCaller);
}
prm.add_endRequest(ScrollFocusToFormCaller);
function ScrollFocusToFormCaller(sender, args) {
if (args.get_error() == undefined) {
FocusOnForm();
}
}";
return script;
}
Sys.Application.add_load(LoadHandler); //This load handler solved update panel did not bind control after partial postback
function LoadHandler() {
$(document).ready(function () {
//rebind any events here for controls under update panel
});
}
For anyone else in my situation, I was trying to get jquery document ready function to work for a DevExpress ASPxCallbackPanel and nothing above (to-date) worked. This is what did work for me.
<script>
function myDocReadyFunction(){ /* do stuff */ }
</script>
<dx:ASPxCallbackPanel ID="myCallbackPanel" ... >
<ClientSideEvents EndCallback="function(){ myDocReadyFunction();}">
</ClientSideEvents>
<PanelCollection ...>
</dx:ASPxCallbackPanel>