Friday, May 7, 2010

XPages: Severe bug in the partial event hijacker

Update 11.10.2010 Found another bug. onComplete can sometimes be a string. Fixed.

For the life of me, I couldn't understand why the onStart/onError/onComplete events didn't fire for partial refreshes. Today it suddenly dawned on me. It was because of my partial event hijacker.

The previous version overwrote the onStart/onError/onComplete events. Below is the fixed code. Sorry if you've used the hijacker and suffered the same fate as me.

function hijackAndPublishPartialRefresh(){
// Hijack the partial refresh
XSP._inheritedPartialRefresh = XSP._partialRefresh;
XSP._partialRefresh = function( method, form, refreshId, options ){
// Publish init
dojo.publish( 'partialrefresh-init', [ method, form, refreshId, options ]);
this._inheritedPartialRefresh( method, form, refreshId, options );
}

// Publish start, complete and error states
dojo.subscribe( 'partialrefresh-init', function( method, form, refreshId, options ){
if( options ){ // Store original event handlers
var eventOnStart = options.onStart;
var eventOnComplete = options.onComplete;
var eventOnError = options.onError;
}

options = options || {};
options.onStart = function(){
dojo.publish( 'partialrefresh-start', [ method, form, refreshId, options ]);
if( eventOnStart ){
if( typeof eventOnStart === 'string' ){
eval( eventOnStart );
} else {
eventOnStart();
}
}
};

options.onComplete = function(){
dojo.publish( 'partialrefresh-complete', [ method, form, refreshId, options ]);
if( eventOnComplete ){
if( typeof eventOnComplete === 'string' ){
eval( eventOnComplete );
} else {
eventOnComplete();
}
}
};

options.onError = function(){
dojo.publish( 'partialrefresh-error', [ method, form, refreshId, options ]);
if( eventOnError ){
if( typeof eventOnError === 'string' ){
eval( eventOnError );
} else {
eventOnError();
}
}
};
});
}

14 comments:

Anonymous said...

I've tried to add the script, but when I click on the "Next" link of a pager (that should do a partial refresh on a view), the view won't refresh at all (it keeps stuck on the first page).
Have I missed something?
thanks in advance, Simone

Tommy Valand said...

As far as I've tested, the script doesn't affect any other code (after the bugfix).

If you remove the function, the pager works?

Anonymous said...

Yes... I need to do some operations before changing the page of view entries, and I really hope the script can work!
Simone

Tommy Valand said...

Are there any javascript errors on the page?

I'd throw in an alert/console.log (if you're using firebug), to see what happens.

I'm going away for the weekend, so I can't be of any more help until sunday or monday.

Anonymous said...

I use firebug, but it doesn't show errors.

I've only added a script block at the top of the xpage with your hijack script.
I have also added another script block with the XSP.addOnLoad command to call the hijack function

Simone

Anonymous said...

I've tested again the script, but still don't work.
Have you any other clue?
Thanks, Simone

Tommy Valand said...

It's hard to say without having access to the page/code.

Could be several things. For me, it works flawlessly. I've put it in a client side script library, but that shouldn't make much difference.

Anonymous said...

The code is quite simple, I've just created a view panel and added the script to test the functionality.

[?xml version="1.0" encoding="UTF-8"?]
[xp:view xmlns:xp="http://www.ibm.com/xsp/core"]
[xp:br][/xp:br]
[xp:scriptBlock]
[xp:this.value][![CDATA[XSP.addOnLoad("hijackAndPublishPartialRefresh()");]]][/xp:this.value]
[/xp:scriptBlock]
[xp:inputText id="inputText1"][/xp:inputText]
[xp:br][/xp:br]
[xp:viewPanel rows="2" id="viewPanel1" viewStyle="width:100.0%"
var="dataRow"]
[xp:this.facets]
[xp:pager partialRefresh="true" layout="Previous Group Next"
xp:key="headerPager" id="pager1"]
[/xp:pager]
[/xp:this.facets]
[xp:this.data]
[xp:dominoView var="allmen" viewName="allmen"][/xp:dominoView]
[/xp:this.data]
[xp:viewColumn columnName="Fullname" id="viewColumn1"]
[xp:viewColumnHeader value="Fullname"
id="viewColumnHeader1"]
[/xp:viewColumnHeader]
[/xp:viewColumn]
[xp:viewColumn columnName="Email" id="viewColumn2"]
[xp:viewColumnHeader value="Email" id="viewColumnHeader2"][/xp:viewColumnHeader]
[/xp:viewColumn]
[xp:viewColumn columnName="DOB" id="viewColumn3"]
[xp:viewColumnHeader id="viewColumnHeader3" value="DOB"][/xp:viewColumnHeader]
[/xp:viewColumn]
[/xp:viewPanel]
[xp:br][/xp:br]
[/xp:view]

Note: in the addOnLoad part I've inserted all the function script
- Simone

Tommy Valand said...

Just to be sure.. You've written it like this?

dojo.addOnLoad(function hijackAndPublishPartialRefresh(){..code..});

Anonymous said...

Uh, no! I've written:
XSP.addOnLoad(function hijackAndPublishPartialRefresh(){..code..});
- Simone

Tommy Valand said...

I think they work more or less the same, so that's probably not the problem.

Is the code formatted properly when you view source in the browser?

Have you tried adding a "subscription" to the page?

E.g.
dojo.subscribe( 'partialrefresh-start', null, function( method, form, refreshId ){
alert('Partial refresh for ' + refreshId + ' started.' );
} );

Anonymous said...

I've tried to add the subscription, using another addOnLoad just after the call to the hijack function.
During page load, the script is 'loaded', but don't work.
- Simone

Tommy Valand said...

I've made a small demoapp for you, using your code snippet as an example. This works on localhost.

Let me know how it works out :)

Anonymous said...

I've tried to use your example, and it works!
But, looking the code I haven't found important differences with my test page.
Strange...
Thank you!
- Simone