Jquery document.ready not triggered without alert - javascript

I'm facing this very weird issue that my function in document ready is not triggered, unless I put alert after the function. I found this out when I debug using the alert, and apparently everything was working fine. But when I removed the alert, function 'RaiseEvent' never get called.
Here's my HTML:
<script src="../Content/jquery.mobile-1.4.2/js/jquery.js"></script>
<script src="../Content/jquery.mobile-1.4.2/js/jquery.mobile-1.4.2.min.js"></script>
<script type="text/javascript" src="Scripts/hybrid.js"></script>
<script>
$(document).ready(function(){
//populate form
//alert('Calling POPULATE-FORM');
RaiseEvent('POPULATE-FORM');
//alert('After POPULATE-FORM');
});
</script>
The RaiseEvent function is retrieved from hybrid.js:
function RaiseEvent(eventName)
{
if (!eventName) eventName = '';
var qs = '';
var elms = document.getElementsByTagName('*');
for (var i = 0; i < elms.length; i++) {
if (elms[i].name) {
qs += (qs.length > 0 ? '&' : '') + encodeURIComponent(elms[i].name) + '=' + encodeURIComponent(elms[i].value);
}
if (elms[i].type == 'checkbox' && elms[i].checked)
qs += (qs.length > 0 ? '&' : '') +
'checked:' + encodeURIComponent(elms[i].name) + '=1';
}
location.href = 'xpostback:' + eventName + ':' + qs;
}
I've googled this issue and found few people facing this also Here but I followed his solution already to no avail.
Anyone facing the same issue or have any suggestions/advice what might go wrong?

I have some thoughts on your problem.
a) Callback function in ready()
From documentation handler is callback function which means that when DOM element is ready your function is beeing called. I suppose that is not the problem.
document.ready( handler );
b) Jquery.mobile
Fast googling told me that you could use different function. See pagecreated documentation.
$(document).on('pagecreated',function(){
RaiseEvent('POPULATE-FORM');
});
Also look here:
jQuery mobile $(document).ready equivalent
jQuery Mobile: document ready vs page events
c) Error in function RaiseEvent(eventName)
Even if your function works with alert this doesn't guarantee that you function is working properly. I had a lot of situations that in all modern browsers my code works but there was some bugs. Only Internet Explorer was so kind and throw me errors. I suggest running your code with JS debugger.
Summary
I would start from b) and then try to look at c). Good luck :)

Apparently there is another "document.ready" function in hybrid.js that caused inconsistent RaiseEvent calling. Probably because the asynchronous nature of Javascript, the RaiseEvent('POPULATE-FORM') get overlapped by the RaiseEvent('DOCUMENT-READY') in hybrid.js:
var readyStateCheckInterval = setInterval(function() {
if (document.readyState === "complete") {
RaiseEvent("DOCUMENT_READY");
Init();
clearInterval(readyStateCheckInterval);
}
}, 50);
Credits to #Barmar for helping me debugging the isssue!

Related

JavaScript or jQuery browser back button click detector

Could someone please share experience / code how we can detect the browser back button click (for any type of browsers)?
We need to cater all browser that doesn't support HTML5
The 'popstate' event only works when you push something before. So you have to do something like this:
jQuery(document).ready(function($) {
if (window.history && window.history.pushState) {
window.history.pushState('forward', null, './#forward');
$(window).on('popstate', function() {
alert('Back button was pressed.');
});
}
});
For browser backward compatibility I recommend: history.js
In javascript, navigation type 2 means browser's back or forward button clicked and the browser is actually taking content from cache.
if(performance.navigation.type == 2) {
//Do your code here
}
there are a lot of ways how you can detect if user has clicked on the Back button. But everything depends on what your needs. Try to explore links below, they should help you.
Detect if user pressed "Back" button on current page:
Is there a way using Jquery to detect the back button being pressed cross browsers
detect back button click in browser
Detect if current page is visited after pressing "Back" button on previous("Forward") page:
Is there a cross-browser onload event when clicking the back button?
trigger event on browser back button click
Found this to work well cross browser and mobile back_button_override.js .
(Added a timer for safari 5.0)
// managage back button click (and backspace)
var count = 0; // needed for safari
window.onload = function () {
if (typeof history.pushState === "function") {
history.pushState("back", null, null);
window.onpopstate = function () {
history.pushState('back', null, null);
if(count == 1){window.location = 'your url';}
};
}
}
setTimeout(function(){count = 1;},200);
In case of HTML5 this will do the trick
window.onpopstate = function() {
alert("clicked back button");
}; history.pushState({}, '');
You can use this awesome plugin
https://github.com/ianrogren/jquery-backDetect
All you need to do is to write this code
$(window).load(function(){
$('body').backDetect(function(){
// Callback function
alert("Look forward to the future, not the past!");
});
});
Best
In my case I am using jQuery .load() to update DIVs in a SPA (single page [web] app) .
Being new to working with $(window).on('hashchange', ..) event listener , this one proved challenging and took a bit to hack on. Thanks to reading a lot of answers and trying different variations, finally figured out how to make it work in the following manner. Far as I can tell, it is looking stable so far.
In summary - there is the variable globalCurrentHash that should be set each time you load a view.
Then when $(window).on('hashchange', ..) event listener runs, it checks the following:
If location.hash has the same value, it means Going Forward
If location.hash has different value, it means Going Back
I realize using global vars isn't the most elegant solution, but doing things OO in JS seems tricky to me so far. Suggestions for improvement/refinement certainly appreciated
Set Up:
Define a global var :
var globalCurrentHash = null;
When calling .load() to update the DIV, update the global var as well :
function loadMenuSelection(hrefVal) {
$('#layout_main').load(nextView);
globalCurrentHash = hrefVal;
}
On page ready, set up the listener to check the global var to see if Back Button is being pressed:
$(document).ready(function(){
$(window).on('hashchange', function(){
console.log( 'location.hash: ' + location.hash );
console.log( 'globalCurrentHash: ' + globalCurrentHash );
if (location.hash == globalCurrentHash) {
console.log( 'Going fwd' );
}
else {
console.log( 'Going Back' );
loadMenuSelection(location.hash);
}
});
});
It's available in the HTML5 History API. The event is called 'popstate'
Disable the url button by following function
window.onload = function () {
if (typeof history.pushState === "function") {
history.pushState("jibberish", null, null);
window.onpopstate = function () {
history.pushState('newjibberish', null, null);
// Handle the back (or forward) buttons here
// Will NOT handle refresh, use onbeforeunload for this.
};
}
else {
var ignoreHashChange = true;
window.onhashchange = function () {
if (!ignoreHashChange) {
ignoreHashChange = true;
window.location.hash = Math.random();
// Detect and redirect change here
// Works in older FF and IE9
// * it does mess with your hash symbol (anchor?) pound sign
// delimiter on the end of the URL
}
else {
ignoreHashChange = false;
}
};
}
};
Hasan Badshah's answer worked for me, but the method is slated to be deprecated and may be problematic for others going forward. Following the MDN web docs on alternative methods, I landed here: PerformanceNavigationTiming.type
if (performance.getEntriesByType("navigation")[0].type === 'back_forward') {
// back or forward button functionality
}
This doesn't directly solve for back button over the forward button, but was good enough for what I needed. In the docs they detail the available event data that may be helpful with solving your specific needs:
function print_nav_timing_data() {
// Use getEntriesByType() to just get the "navigation" events
var perfEntries = performance.getEntriesByType("navigation");
for (var i=0; i < perfEntries.length; i++) {
console.log("= Navigation entry[" + i + "]");
var p = perfEntries[i];
// dom Properties
console.log("DOM content loaded = " + (p.domContentLoadedEventEnd -
p.domContentLoadedEventStart));
console.log("DOM complete = " + p.domComplete);
console.log("DOM interactive = " + p.interactive);
// document load and unload time
console.log("document load = " + (p.loadEventEnd - p.loadEventStart));
console.log("document unload = " + (p.unloadEventEnd -
p.unloadEventStart));
// other properties
console.log("type = " + p.type);
console.log("redirectCount = " + p.redirectCount);
}
}
According to the Docs at the time of this post it is still in a working draft state and is not supported in IE or Safari, but that may change by the time it is finished. Check the Docs for updates.
suppose you have a button:
<button onclick="backBtn();">Back...</button>
Here the code of the backBtn method:
function backBtn(){
parent.history.back();
return false;
}

Javascript Error : $ is not a function

I am facing a weird problem here :
In firebug i see this error :
$ is not a function
_handleEvent() in pro.js
e = load
var handlers = this.events[e.type], el = $(this);
The full function is defined as follows :
_handleEvent : function(e) {
var returnValue = true;
e = e || Event._fixEvent(window.event);
var handlers = this.events[e.type], el = $(this);
for (var i in handlers) {
el.$$handleEvent = handlers[i];
if (el.$$handleEvent(e) === false) returnValue = false;
}
return returnValue;
}
Can you guys kindly help me out here and figure out why is this error being thrown here. It's not related to jquery, i guess.
NOTE : It gives the error : $(this ) is not a function in IE
I think you've either not loaded jQuery correctly or you are executing this code before the inclusion of jQuery. Or you might be using jQuery's noConflict-mode, http://api.jquery.com/jQuery.noConflict/, in which case you'd need to replace $() by jQuery().
Also, make sure you execute this code either at document load or, even better, when jQuery is loaded:
$(document).ready(function() {
// your code goes here
});

GetElementById of ASP.NET Control keeps returning 'null'

I'm desperate having spent well over an hour trying to troubleshoot this. I am trying to access a node in the DOM which is created from an ASP.NET control. I'm using exactly the same id and I can see that they match up when looking at the HTML source code after the page has rendered. Here's my [MODIFIED according to suggestions, but still not working] code:
ASP.NET Header
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
<script type="text/javascript">
$(document).ready(
var el = document.getElementById('<%= txtBox.ClientID %>');
el.onchange = alert('test!!');
)
</script>
</asp:Content>
ASP.NET Body
<asp:TextBox ID="txtBox" runat="server"></asp:TextBox>
Resulting Javascript & HTML from above
<script type="text/javascript">
$(document).ready(
var el = document.getElementById('MainContent_txtBox');
el.onchange = alert('test!!');
)
</script>
...
<textarea name="ctl00$MainContent$txtBox" id="MainContent_txtBox"></textarea>
I can only assume that the script is loading before the control id has been resolved, yet when I look at the timeline with Chrome's "Inspect Element" feature, it appears that is not the case. When I created a regular textarea box to test and implement the identical code (different id of course), the alert box fires.
What on earth am I missing here? This is driving me crazy >.<
EDIT: Wierd code that works, but only on the initial page load; firing onload rather than onchange. Even jQuery says that .ready doesn't work properly apparently. Ugh!!
$(document).ready(function() {
document.getElementById('<%= txtBox.ClientID %>').onchange = alert('WORKING!');
})
Assuming the rendered markup does appear in that order, the problem is that the element doesn't yet exist at the time your JavaScript is attempting to locate it.
Either move that JS below the element (preferably right at the end of the body) or wrap it in something like jQuery's document ready event handler.
Update:
In response to your edits, you're almost there but (as others have mentioned) you need to assign a function to the onchange event, not the return result of alert(). Something like this:
$(document).ready(function() {
// Might as well use jQuery to attach the event since you're already using
// it for the document ready event.
$('#<%= txtBox.ClientID %>').change(function() {
alert('Working!');
});
});
By writing onchange = alert('Working');, you were asking JavaScript to assign the result of the alert() method to the onchange property. That's why it was executing it immediately on page load, but never actually in response to the onchange event (because you hadn't assigned that a function to run onchange).
Pick up jQuery.
Then you can
$(function()
{
var el = document.getElementById('<%= txtBox.ClientID %>');
el.onclick() { alert('test!!'); }
});
Other answers have pointed out the error (attempting to access DOM nodes before they are in the document), I'll just point out alternative solutions.
Simple method
Add the script element in the HTML below the closing tag of the element you wish to access. In its easiest form, put it just before the closing body tag. This strategy can also make the page appear faster as the browser doesn't pause loading HTML for script. Overall load time is the same however, scripts still have to be loaded an executed, it's just that this order makes it seem faseter to the user.
Use window.onload or <body onload="..." ...>
This method is supported by every browser, but it fires after all content is loaded so the page may appear inactive for a short time (or perhaps a long time if loading is dealyed). It is very robust though.
Use a DOM ready function
Others have suggested jQuery, but you may not want 4,000 lines and 90kb of code just for a DOM ready function. jQuery's is quite convoluted so hard to remove from the library. David Mark's MyLibrary however is very modular and quite easy to extract just the bits you want. The code quality is also excellent, at least the equal of any other library.
Here is an example of a DOM ready function extracted from MyLibrary:
var API = API || {};
(function(global) {
var doc = (typeof global.document == 'object')? global.document : null;
var attachDocumentReadyListener, bReady, documentReady,
documentReadyListener, readyListeners = [];
var canAddDocumentReadyListener, canAddWindowLoadListener,
canAttachWindowLoadListener;
if (doc) {
canAddDocumentReadyListener = !!doc.addEventListener;
canAddWindowLoadListener = !!global.addEventListener;
canAttachWindowLoadListener = !!global.attachEvent;
bReady = false;
documentReady = function() { return bReady; };
documentReadyListener = function(e) {
if (!bReady) {
bReady = true;
var i = readyListeners.length;
var m = i - 1;
// NOTE: e may be undefined (not always called by event handler)
while (i--) { readyListeners[m - i](e); }
}
};
attachDocumentReadyListener = function(fn, docNode) {
docNode = docNode || global.document;
if (docNode == global.document) {
if (!readyListeners.length) {
if (canAddDocumentReadyListener) {
docNode.addEventListener('DOMContentLoaded',
documentReadyListener, false);
}
if (canAddWindowLoadListener) {
global.addEventListener('load', documentReadyListener, false);
}
else if (canAttachWindowLoadListener) {
global.attachEvent('onload', documentReadyListener);
} else {
var oldOnLoad = global.onload;
global.onload = function(e) {
if (oldOnLoad) {
oldOnLoad(e);
}
documentReadyListener();
};
}
}
readyListeners[readyListeners.length] = fn;
return true;
}
// NOTE: no special handling for other documents
// It might be useful to add additional queues for frames/objects
else {
if (canAddDocumentReadyListener) {
docNode.addEventListener('DOMContentLoaded', fn, false);
return true;
}
return false;
}
};
API.documentReady = documentReady;
API.documentReadyListener = documentReadyListener;
API.attachDocumentReadyListener = attachDocumentReadyListener;
}
}(this));
Using it for your case:
function someFn() {
var el = document.getElementById('MainContent_txtBox');
el.onclick = function() { alert('test!!');
}
API.attachDocumentReadyListener(someFn);
or an anonymous function can be supplied:
API.attachDocumentReadyListener(function(){
var el = document.getElementById('MainContent_txtBox');
el.onclick = function() { alert('test!!');
};
Very simple DOM ready functions can be done in 10 lines of code if you just want one for a specific case, but of course they are less robust and not as reusable.

ready state problem with ajax and jquery

i have the following problem. I'm trying to load a set of tab loading dinamically with jQuery.
When I get the new contents (via POST) the tabs() function abort and don't build the
tabs. I'm using this functions:
$(document).ready(function() {
var array_with_alias_id = $.getJSON("/getAliasForMatchAll/", null,
function (data){
array = data.aliases_id;
load(array);
});
$("#next_left").click(function(){next_left()});
//load(array_with_alias_id);
});
function next_left(){
if(j >= array.length-1){
var l = j
} else {
var l = j+=1;
}
$("#alias_id_left").val(list_left[l]);
$("#merge_alias_id_left").val(list_left[l]);
$.post("/visor/",{"alias_id":list_left[l],"position":"L"},
function(data){
$("#tabsL").html(data).ready(function(){
$("#tabsL").tabs();
});
});
}
I think that my problem is an ajax problem and i have read this [0],
but i can't give with the solution.
The function next_left() it works only one time. I think that the document for
this function is ready, but when i load the tabs it doesnt work
(i think that tab call the method abort, because if i see the html with firebug
it change, but not all).
Any clue?
[0]http://docs.jquery.com/Tutorials:AJAX_and_Events
Try replacing $("#next_left").click(function(){next_left()}); with:
$("#next_left").live('click', function(){next_left()});
People on IRC helped me.
I have now changed the function after the .POST to this:
function next_left(){
if(j >= array.length-1) {
var l = j
}
else {
var l = j+=1;
}
$("#alias_id_left").val(list_left[l]);
$("#merge_alias_id_left").val(list_left[l]);
$.post("/visor/",{"alias_id":list_left[l],"position":"L"},
function(data) {
$("#tabsL").html(data).tabs("destroy").tabs();
});
}
They correctly advised me that the ready function applies to the document and does not work how I used it. I hope the fixed code I posted here aids others.

Converting Some Code to jQuery

Hey guys, I have some code that I found that I would rather use as jQuery instead of direct JavaScript. Hopefully you guys can help me convert it:
var sub = document.getElementById('submit');
sub.parentNode.removeChild(sub);
document.getElementById('btn-area').appendChild(sub);
document.getElementById('submit').tabIndex = 6;
if ( typeof _some_var != 'undefined') {
document.getElementById('some-textarea').value = _some_var;
}
document.getElementById('something').style.direction = 'ltr';
The reason I want to do this is because FireFox is telling me that sub is null when it is used on the second line. This happens because that code runs before the the submit button appears. So naturally I would like to use jQuery for the purpose of running the code after everything is ready. Yes, I know it's possible to do that in direct JavaScript as well, but I would rather have jQuery either way.
Thanks!
There's absolutely no need to use jQuery for this purpose. Assuming you do not already have a load event handler:
window.onload = function() {
// your code
};
Or throw it right before the end body tag, or to be more specific anywhere in the source after the submit button - there's nothing really dirty about it.
<script src="your-code.js"></script>
</body>
However, a quick jQuery rewrite..
$(function() {
$('#submit').appendTo('#btn-area').attr('tabIndex', 6);
if ( typeof yourVar != 'undefined' ) {
$('#textarea').val( yourVar );
}
$('#something').css('direction', 'ltr');
});
Did not test.
Here it is:
var sub_html = $('#submit').html();
$('#submit').html('');
$('#btn-area').html(sub_html);
$('#submit').attr('tabindex', 6);
if(typeof _some_var != 'undefined')
{
$('#some-textarea').val(_some_var);
}
$('#something').css('direction', 'ltr');

Categories

Resources