General Question

richardhenry's avatar

Ajax.PeriodicalUpdater — only update if the content has changed?

Asked by richardhenry (12692points) March 20th, 2008

I’m using the following code in conjunction with the Prototype library:

new Ajax.PeriodicalUpdater(‘activity’, ‘activity.output.php’, { method: ‘get’, frequency: 1, decay: 2, insertion: Insertion.Top });

and was wondering if there’s any way to prevent the PeriodicalUpdater from processing the update if the output hasn’t changed? It already decays nicely, but how can I prevent it from updating if there’s no change?

http://www.prototypejs.org/api/ajax/periodicalUpdater

Observing members: 0 Composing members: 0

15 Answers

andrew's avatar

It’s been a while since I’ve written in Prototype, but what if you bound your own method for the onSuccess for the PeriodicalUpdater (instead of using the helper methods for updating the DOM); you could check for data coming back, and if there were data, then call update yourself.

richardhenry's avatar

It’s not a case of there being data or not, it’s more a case of if the data from the last update is the same as this response, and if true: don’t make an update. Repeat until the response is not equal to the prior update: then, make an update. If the data from the last update is the same as this response… etc.

Any thoughts?

paulc's avatar

Do the same thing andrew just mentioned but keep a single buffer of the previous result and only act if its different.

richardhenry's avatar

Could I possibly have an example of this if it’s not too much trouble? I’m new to Javascript unfortunately. Even just linking me to the appropriate section in the Prototype manual would be helpful, thanks :)

paulc's avatar

Without brushing up on the prototype library I’d say add onComplete:function_reference to your options. So you’d need a function declared somewhere with the name “function_reference” or whatever you want. I don’t recall how prototype fires its callbacks but it may pass a reference to the object doing the callback in which case you could get the data out of it: function_reference(caller) { ... }

richardhenry's avatar

For me it seems really bizarre that there isn’t an option for Ajax.PeriodicalUpdater to only update the item if the content has changed, especially since it is already checking if this is true for the purpose of the decay. So what would the syntax be for onSuccess (as I understand it, you should use onSuccess for a PeriodicalUpdater as it never ‘completes’ as such)... something like:

new Ajax.PeriodicalUpdater(‘activity’, ‘activity.output.php’, { method: ‘get’, frequency: 1, decay: 2, insertion: Insertion.Top,
onSuccess: function(transport) {
if (transport.responseText == previousResponse) {
// do nothing
} else {
// do the update… how do i call that?
}
var previousResponse = transport.responseText;
},
});

As I say, I’m very new to Javascript (although Prototype helps) and am still trying to figure it out. Thanks

richardhenry's avatar

Or should I be doing something more like:

new Ajax.PeriodicalUpdater(‘activity’, ‘activity.output.php’, { method: ‘get’, frequency: 1, decay: 2, insertion: Insertion.Top });

Ajax.Responders.register({
onSuccess: function(){
// some code to determine if the update should take place
}
});

And how do I actually control when an update occurs? Thanks again :)

andrew's avatar

Do you have access to the php side of things? Perhaps an even better solution is to modify the server-side code.

Sidenote: This is exactly why we stopped using Prototype. All of the functionality is great, and really smart until you want to change something, then the whole thing goes to hell.

I’d say that you want to do something similar to what you proposed in 1, except you don’t want a insertion parameter (since you’ll be doing the inserting yourself), and you want to make sure that the previousResponse variable is global (or at least has scope outside the callback function, otherwise each time you run the updater you’ll lose the value). You’ll want to look at the element.update function, and figure out how to strip the text from the response (not too hard, if I remember).

I’d be happy to walk through this with you. Catch me in the chat or PM me.

adrianscott's avatar

The problem with Ajax.PeriodicalUpdater is that it’s an extension on a regular Ajax.Updater. Prototype is fantasic in a lot of ways, but sometimes you have to sit and scratch your head as to why they codeded something a certain way…

What happens when you call Ajax.PeriodicalUpdater is that its timer event (the thing that is executed when the time interval you’ve provided occurs) performs an Ajax.Updater event right away (effectively replacing the old content with the new) THEN it’ll check to see if the content is new or not and will adjust the decay value accordingly. This is dumb in my mind because it will lead to visual refreshes in some browsers (like IE).

I’ve had to resort to creating my own class based on the initial Ajax.PeriodicalUpdater which, instead of calling Ajax.Update in its timer event, it calls Ajax.Request with an onSuccess that will check to see if the old content is the same as the transport.responseText provided. Then I perform a Element.update with the new content only if it’s different. This way you can ensure that the object is only updated when there’s new info and not on every single timer event.

richardhenry's avatar

Would you mind showing me your code if it’s not too much trouble, it would be very useful. My current code is (which works just fine):

—-

Event.observe(window, ‘load’, periodicalUpdater);
var previousResponse = null;
var isUpdate = null;

function periodicalUpdater() {

new Ajax.Request(‘activity.updater.output.php’, {
method: ‘get’,
onSuccess: function(transport) {
if (previousResponse != transport.responseText) {
$(‘activity_content’).insert({ top: transport.responseText });
if (isUpdate) { Effect.SlideDown(‘new_activity’, { duration: 0.6 }); }
$(‘new_activity’).id = null; isUpdate = true; }
previousResponse = transport.responseText;
setTimeout(periodicalUpdater, 2000);
}
});

}

richardhenry's avatar

“THEN it’ll check to see if the content is new or not”

I fail to see why anyone would possible think this is a good idea, nevermind go out and actually code it that way! Thanks for the tips Adrian.

adrianscott's avatar

I’d love to, however I’ll have to wait until Tuesday to do so. The adjusted code is on my work computer and I won’t be in the office until then.

My recommendation would be to open up the actual Prototype.js file and see how they created the PeriodicalUpdater code. It’s good to learn how they did it, and you can just replicate what they did but change the timer event to use the Ajax.Request method instead.

I’ll check back on Tuesday if you still would like to see how my code works!

richardhenry's avatar

I would do anyway if it’s not too much trouble, it’s always useful for learning! Thanks :D

adrianscott's avatar

@richardhenry here you go, this is the code that I’m using. Simply copy and paste this into your prototype.js file and it should work for you (no promises!) As you can see it is very much based on the existing Ajax.PeriodicalUpdater with the changes I’ve suggested. Good luck!

Ajax.PassivePeriodicalUpdater = Class.create(Ajax.Base, {
initialize: function($super, container, url, options) {
$super(options);
this.onComplete = this.options.onComplete;

this.frequency = (this.options.frequency || 2);
this.decay = (this.options.decay || 1);

this.updater = { };
this.container = $(container);
this.url = url;

this.start();
},

start: function() {
this.options.onComplete = this.updateComplete.bind(this);
this.onTimerEvent();
},

stop: function() {
this.updater.options.onComplete = undefined;
clearTimeout(this.timer);
(this.onComplete || Prototype.emptyFunction).apply(this, arguments);
},

updateComplete: function(response) {
if (response.responseText == this.lastText) {
this.decay = this.decay * this.options.decay;
} else {
this.decay = 1;
this.container.update(response.responseText);
this.lastText = response.responseText;
}
this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
},

onTimerEvent: function() {
this.updater = new Ajax.Request(this.url, this.options);
}
});

richardhenry's avatar

I’ll give it a go, thanks very much!

Answer this question

Login

or

Join

to answer.

This question is in the General Section. Responses must be helpful and on-topic.

Your answer will be saved while you login or join.

Have a question? Ask Fluther!

What do you know more about?
or
Knowledge Networking @ Fluther