Julian gave me a link to a cleaner way of making dialogs work. I recommend using that method instead of what's below.As I've mentioned several times, I'm currently working on a larger project that relies heavily on XPages technology.
One of the
widgets I felt the need for in this project is the
modal dialog box. Dojo has two inbuilt widgets that provides this functionality,
dijit.Dialog, and
dojox.widget.Dialog.
As
Julian Buss points out, you'll stumble onto a couple of big problems when using these widgets in XPages (out of the box). Server side events aren't triggered, and field values aren't posted to the server. I've used more time than I want to admit, trying to find out why server side events doesn't work. The answer is quite simple.
XSP.getFormActions that triggers server side code (partial-/full refresh) need to know which <form> to post. When an event is triggered, the DOM tree is traversed upwards until a form is found/the top of the tree is reached. If a form isn't found, the event is ignored. The dialog widgets in Dojo are moved to the bottom of <body>, outside any form tags.
Client side JS to "fix" XSP.findForm:
/*
Modifies XSP.findForm so server side events are fired correctly when
dojox/dijit dialogs are used.
- First try the native findForm-method to find the correct form
- Then try to find a parent element with the attribute form_id (used specifically in ccModalDialogWeb in this demoapp)
- If everything else fails, return the first form on the page.
*/
dojo.addOnLoad(function( el ){
var oldFn = XSP.findForm;
XSP.findForm = function( el ){
var form = oldFn.apply( this, arguments );
if( !form ){ // Look for element with form_id attribute
el = (typeof el === 'string' ) ? dojo.byId( el ) : el;
if( el && el.nodeName ){
while( el && el.nodeName !== 'BODY' ){
var formId = el.getAttribute( 'form_id' );
if( formId ){ // form_id found -> get form by id
form = dojo.byId( formId );
break;
}
el = el.parentNode;
}
}
}
return form || document.forms[0];
}
});
Only server side events from the the dojo dialog (/any other elements triggering server side events outside forms) are affected by this code. First the original XSP.getForm is tested (so that "standard" events arent't broken). If no form is found, the DOM tree is traversed upwards looking for an attribute, form_id, which can be added to one of the parent elements of the dialog content. If form_id is found, it's used to locate the correct form. If that also fails, the first form on the page is used. I use form_id in the demoapp. This is not a native attribute, so you have to generate this yourself.
getForm.getClientId(facesContext) returns the browser-id of the parent form.
The above code doesn't fix the problem with
fields being moved outside the form. In the demoapp, I've made a simple workaround for this (only for input-fields). Basically you have to clone the fields in the dialog, and copy them onto the correct form. Add an onChange event to the dialog fields, so that the clones get the correct value.
If you decide to implement the custom control in your own projects, and need workaround for other field types, let me know.
The demoapp contains a custom control that let's you open another custom control/xpage inside another XPage. If you use a custom control for the dialog, the custom control should have full access to the XPage that contains the dialog.
The interactive part of the demoapp is extremely simple. The "gold" is the custom control
ccModalDialog, and the client side script,
ccModalDialog.js.
Hopefully IBM implements a standard control for modal dialogs. It's not impossible to make perfect. It only requires time, knowledge and patience.
>> Download demoappShare and enjoy!