Run js when document is changed? - javascript

I tried looking for the answer, and this is my first post, so bear with me if I mess up in some way.
Basically my problem is this: I'm writing an extension for Chrome that uses jQuery. I have another extension that makes a timed $.ajax() request every 10 seconds. I need to find a way to run my code every time that timed ajax request and its callback function completes. Setting a timer for my own script can be done, although that's rather half-assed and doesn't work as well.
The problem can be illustrated thus:
//extension 1
function timedFunc() {
setTimeout(doStuff, 10000);
};
timedFunc();
//extension 2
//code to be run every time doStuff completes
I feel like there may be a very elementary solution to this problem but I appreciate the help.

There is (was) an event called DOMSubtreeModified.
But it has been deprecated so at tho moment there are really only workarounds available.
Why is the DOMSubtreeModified event deprecated in DOM level 3?
I can't advise on using this event as it hasn't even been implemented in all browsers.
But what you can do (easily) is just trigger you own event with all your ajax call!
Example:
fire your event when (any) ajax call completes:
$(document).ajaxComplete(function() {
$(document).trigger('domChanged');
}
and listen to it:
$(document).on('domChanged',function() {
alert("i changed the DOM tree!");
});
btw:
taken that you just want to react to ajax calls compleing... just use the .ajaxComplete() event:
http://api.jquery.com/ajaxComplete/

i didn't really understand what you are trying to say but i did understand your question in the title so here is my modest answer:
// a global variable for the documents content
var content=document.documentElement.innerHTML;
// return true if the document content has changed
function documentChanged(){
return content==document.documentElement.innerHTML;
}

Related

What If document.ready won't work

Every JavaScript developer sooner or later faced with case when page elements unavailable in document.onready event. It's happens because onready fired to soon, especially when most of the page parts loaded dynamically (with AJAX). I work with Drupal 7 now. Drupal does not provide Ajax callback, it's seems to be you need to write custom callbacks.
And my question is: what is the most appropriate solution for that case?
Usually I apply
jQuery(document).ready(function(){
setTimeout(function tmr(){
//Wait for any or task specific element will be available
if (jQuery('.bxslider').length) {
//Code here
do_code();
} else
setTimeout(tmr, 1000);
}, 10);
Or better write a callback? Or no different at all?
Attach your js behaviors like this:
Drupal.behaviors.nameOfYourModule= {
attach: function (context, settings) {
// your code here
}
};
This way your code will be executed on every request including AJAX requests.
For more information see this blog post on the subject.

Is there any overhead to having multiple $(document).ready with jQuery 1.8.1

I have code like this:
$(document).ready(function () {
$('.accessLink')
.bind('click', accessLinkClick);
$('#logoutLink')
.click(function (e) {
window.location = $(this).attr('data-href')
});
});
Functionality for each part of my site is divided into a number of small files and when the site is deployed these are mimified and joined up.
Each of these small files which number up to ten wait on $(document).ready. Can anyone tell me if there is much overhead in doing this. Splitting my code into functional areas has meant the code looks easy to maintain but I am just wondering about overhead now that I am using jQuery 1.8.1
Update:
Based on the answers I started to code like this:
$(document).ready(function () {
accessButtons(); // login, register, logout
layoutButtons();
themeButtons(); // theme switcher, sidebar, print page
});
with each function then coded as:
function accessButtons() {
$('.accessLink')
.bind('click', accessLinkClick);
$('#logoutLink')
.click(function (e) {
window.location = $(this).attr('data-href')
});
};
Here's the difference between 10 $(document).ready() calls versus one that then calls 10 initialization functions.
With the 10 calls, you get:
10 calls to $(document).
10 calls to the .ready() method.
One event listener for the DOM ready event
When the DOM ready event fires, it then cycles through an array of callbacks and calls each callback passed to .ready().
If you have one $(document).ready() that then called all 10 of your initialization functions, you would have this:
1 call to $(document).
1 call to the .ready() method.
One event listener for the DOM ready event
When the DOM ready event fires, it then calls your one ready handler.
Your ready handler then calls the 10 initialization function calls.
So, the difference is approximately the time it takes to construct 9 extra jQuery objects and make 9 extra .ready() method calls. In extreme cases this could be noticeable, but it is unlikely that you would see a difference in practice.
If the code needs to be executed in order, then they should in the same dom ready callback function, otherwise, you could divide them into different dom ready callback.
Only use the .ready() function to wrap all code that needs to be run once ALL other code is loaded and once the page is ready. If you have any libraries that can run on their own and do not need to do anything with the DOM then you shouldn't need to put them into a ready call.
Performance goes down when using many $(document).ready() calls, but it doesn't seem to be too bad, and on some browsers it doesn't seem to affect performance very much at all. The linked page has test results for several popular browsers when using $() to modify a large DOM.
Due to the performance issue, I personally create separate functions for each page. So instead of having $(document).ready() run multiple times, you just fire a function on each page. This way, i tend to generally have $(document).ready() only run twice, once for globals, then once for the particular page.
function ContactForm() {
$(function () {
// Contact form page specific stuff.
});
}
In my View (by the sounds of your question, im assuming you're using MVC), what i do is add the following:
#section scripts {
#Scripts.Render("~/bundles/ContactForm")
<script type="text/javascript">ContactForm();</script>
}

Halt JavaScript execution without locking up the browser

Are you able to halt JavaScript execution without locking up the browser? The way you would normally halt execution is to do an infinite while()-loop, but in the case of FireFox, it locks up the browser until the loop has ended.
What's your take on this?
I am trying to override window.confirm() to implement my own dialog using HTML. I am doing this so I don't have to change existing code (it's a pretty big code-base).
I need to be able to halt execution to allow user-input; to in turn return a boolean like the standard confirm function does:
if (confirm("..."))
{
// user pressed "OK"
}
else
{
// user pressed "Cancel"
}
Update
To my knowledge; this cannot be done using setTimeout() or setInterval() since these functions execute the code thats given to them asynchronously.
confirm() prompt() and alert() are special functions--they call out of the JavaScript sandbox into the browser, and the browser suspends JavaScript execution. You can't do the same thing, since you need to build your functionality into JavaScript.
I don't think there's a great way to drop in a replacement without doing some restructuring along the lines of:
myconfirmfunction(function() {
/* OK callback */
}, function() {
/* cancel callback */
});
Either use callbacks or make your code Firefox-only. In Firefox with support for JavaScript 1.7 and higher, you can use the yield statement to simulate your desired effect. I have created a library for this purpose called async.js. The standard library for async.js includes a confirm method, which can be used as such:
if (yield to.confirm("...")) {
// user pressed OK
} else {
// user pressed Cancel
}
You cannot stop the event thread in JavaScript, so instead you have to work around the problem, usually by using callback functions. These are functions that are run at a later time, but can be passed around like any other object in JavaScript. You might be familiar with them from AJAX programming. So, for example:
doSomeThing();
var result = confirm("some importart question");
doSomeThingElse(result);
Would be converted into:
doSomeThing();
customConfirm("some importart question", function(result){
doSomeThingElse(result);
});
where customConfirm now takes a question and passes the result to the function it takes as an argument. If you implement a DOM dialog with a button, then connect an event listener to the OK and CANCEL buttons, and call the callback function when the user clicks on one of them.
There is an extension to the JavaScript language called StratifiedJS. It runs in every browser, and it allows you to do just that: halting one line of JavaScript code without freezing the browser.
You can enable Stratified JavaScript e.g. by including Oni Apollo ( http://onilabs.com/docs ) in your webpage like:
<script src="http://code.onilabs.com/latest/oni-apollo.js"></script>
<script type="text/sjs"> your StratifiedJS code here </script>
Your code would look like this:
var dom = require("dom");
displayYourHtmlDialog();
waitfor {
dom.waitforEvent("okbutton", "click");
// do something when the user pressed OK
}
or {
dom.waitforEvent("cancelbutton", "click");
}
hideYourHtmlDialog();
// go on with your application
the way you normally halt execution should hardly ever be an infinite while loop.
break up your work into parts, that you call with SetTimeout
change this:
DoSomeWork();
Wait(1000);
var a = DoSomeMoreWork();
Wait(1000);
DoEvenMoreWork(a);
to this:
DoSomeWork();
setTimeout(function() {
var a = DoSomeMoreWork();
setTimeout(function() {
DoEvenMoreWork(a);
}, 1000);
}, 1000);
I don't think there's any way to reasonably re-create the functionality of confirm() or prompt() in your own JavaScript. They're "special" in the sense of being implemented as calls into the native browser library. You can't really do a modal dialog of that sort in JavaScript.
I have seen various UI libraries that simulate the effect by putting an element on top of the page, that looks & acts like a modal dialog, but those are implemented using async callbacks.
You will have to modify the existing library, rather than replacing window.confirm.
I tried using tight looping for this. I needed to slow down a native event (which AFAIK is the only use case for a synchronous wait that can't be re-architected asynchronously). There are lots of example loops out there that claim not to lock up the browser; but none of them worked for me (the browser didn't lock up, but they prevented it from doing the thing I was waiting for in the first place), so I abandoned the idea.
Next I tried this - storing and replaying the event, which seems to be impossible cross-browser too. However depending on the event and how flexible you need to be, you can get close.
In the end I gave up, and feel much better for it; I found a way to make my code work without having to slow down the native event at all.

JScript Wait function

I have a function written in JScript (Not javascript) I need to suspend until a certain global variable becomes true.
The global variable is changed to true when another function is called after an ajax response:
function(req, event, data) {
globalVariable = true;
}
When I try to loop until the variable is true:
while (globalVariable!= true) {
}
I go into a busy waiting and the callback function is never called.
Some suggested the use of WScript.wait() but my app doesn't seam to know WScript.
SetTimeout() also won't help because it's asynchronic call and won't suspend my original function.
Any other suggestion?
Some more information regarding my question:
I want my script to call 2 functions:
waitWhileAjaxIsNotCompleted();
doSomthingElse();
I want the waitWhileAjaxIsNotCompleted() to click a button that submits an ajax request (implemented by A4J) and terminate upon the ajax completion.
In order for me to know when does tha ajax completed, I registered a function as a listener that will be awaken when the ajax completes. This function changes a globalVariable value.
My waitWhileAjaxIsNotComplete() goes into an infinite loop, waiting for the glovalVariable value to change. When it does change (After the listener has awaken), I can end the function ad continue with the doSomthingElse() function.
You can see more on the implementation on: QTP Web extensibilty toolkit and ajax
I can't remember what the heck I used
a few months ago since I don't use
Jscript anymore (not enough time)...
But I am currently looking in my
program to see if I still have the
script saved. I did the exact same
thing a few months back.
I'll post the code once I've found
it...
Sorry about that. I can't seem to find the code snippet. I must have deleted it... Typical of me though.
So, the only thing that I can think of until a better solution is available it to enter your code into an infinite loop, and simply break; out of it once the GlobalVariable returns true.
I hope this helps. I'm going to keep at it until I can either find the snippet or come up with a much better answer.

How to check if page is postback within reserved function pageLoad on ASP.NET AJAX

I'm looking for a way to check within pageLoad() if this method is raised during load event because of a postback/async postback or because of being loaded and access the first time.
This is similar to Page.IsPostback property within code behind page.
TIA,
Ricky
One way you could do that is to wire up an Application.Load handler in Application.Init, then have that handler unbind itself after running:
Sys.Application.add_init(AppInit);
function AppInit() {
Sys.Application.add_load(RunOnce);
}
function RunOnce() {
// This will only happen once per GET request to the page.
Sys.Application.remove_load(RunOnce);
}
That will execute after Application.Init. It should be the last thing before pageLoad is called.
#Darren: Thanks for the answer. I had tried to create pageLoad with event argument ApplicationLoadEventArgs as parameter (see below). However according to this:
The load event is raised for all postbacks to the server, which includes asynchronous postbacks.
As you have indicated, the isPartialLoad property does not cover all postback scenarios. It'll be nice if the event argument also contain isPostback property.
function pageLoad(sender, arg) {
if (!arg.get_isPartialLoad()) {
//code to be executed only on the first load
}
}
#mmattax: I'm looking for property that can be called from client-side (javascript).
What you can do is wire up to the load event of the Sys.Application class. you can then use the isPartialLoad property of the Sys.ApplicationLoadEventArgs class. I believe that would let you know if you are in a async postback or not.
To know if you are in a post back, you'll have to handle that in server side code and emit that to the client.
You could have a hidden input that you set to a known value on the server side if it's a postback/callback - and your javascript could check that value.
That said, I really hope that there's a client-only solution for this.
Edit: #mmattax - I believe he's looking for a client-side solution - the JavaScript equivalent of that.
You can still use Page.IsPostback during an async call.
Application.Init is probably a more appropriate event to use, if you only want the code to execute on the first load.
#Dave Ward: This normally would work. However, the code is to attach event on behavior object. Because the creation of behavior object happens during Application.Init, attaching to that event will lead to unpredictable behavior.
It will be nice if there is PostInit event.
#Dave Ward:
The use of RunOnce method works perfectly. This solve my problem without having the workaround to check first if handler already exist before attaching to an event.
I'll mark your answer as an accepted answer. Thanks again.
Here's our Ajax equivalent to isPostback which we've been using for a while.
public static bool isAjaxRequest(System.Web.HttpRequest request)
{//Checks to see if the request is an Ajax request
if (request.ServerVariables["HTTP_X_MICROSOFTAJAX"] != null ||
request.Form["__CALLBACKID"] != null)
return true;
else
return false;
}

Categories

Resources