Subscribe via Feed

XPages Compatible Dojo Dialog Reusable Component

Jeremy Hodge, Apr 9, 2010 2:21:25 PM

As many have pointed out in the past, the handy dojo.Dialog can cause XPage developers a little bit of an issue because the widget moves itself in the DOM tree to just inside the tag, and thus outside the tag generated by Domino. This is a critical issue for Domino for two reasons:

1. All items nodes that are going to be submitted to the server to be processed, updated, saved etc need to be within the Form element

2. Partial refreshes are dependant upon the the form element being a parent Node to any element that is going to be partially refreshed. This is partially because the XSP object traverses up the dom tree until it finds the form tag to determine the URL it needs to use to submit the partial refresh. If it can't find the URL, it doesn't know where to go.

Now, you may have heard some of hub-bub about "how dare dojo" it's so "evil", how dare it move elements, blah blah blah ... The move is for a very good reason, to ensure the dialog can be seen. If the dialog box is within a fixed size element and you go to show the dialog, it is relagated to the display size of that element. And thats NOT what a modal dialog is supposed to do right? It should prevent interaction on the whole body, and the only way for this to be properly accomplished, in ALL circumstances, is to make sure the dialog's domNode is a direct child to the body.

Since an XPage creates its element directly underneath the body, and the form tag has no defined size, we can simply fix this by moving the domNode for the dialog box in one more level, inside the form's node.

There are some solutions on this out in the blogosphere about how to handle this. Mostly around querying dialog's domNode during onLoad and moving it back within the form tag ... then, conceptuallym you'd have full XPages functionality within the Dialog box again. There can be a problem with this however ... when created, the Dialog defers some setup to the first time it is shown, and as such, can again move the domNode back out to the Body, defeating your initial move, and rendering any partial refresh actions, field updates, etc within the Dialog again lost.

The solution I came up with was to create a simple "Domino Compatible" Dojo Dialog box class that handled moving the domNode back within the form after it is initally created, and again during the initial show() if it gets moved. Here it is, free for all to use...

To use the class you just substitue com.ZetaOne.widget.Dialog in place of dijit.Dialog, then you can use it just like you would dijit.Dialog, either through a new com.ZetaOne.widget.Dialog() or dojoType="com.ZetaOne.widget.Dialog" ...

Here is the code. Either copy it to your reusable javascript library (for requireFromNsf()) or create a file named Dialog.js in the ${DOMINO_DATA_ROOT}/Domino/js/Dojo-1.3.2/com/ZetaOne/widget/ folder if you want to use it with dojo.require, or if you want to use it as a Dojo Module in an XPage Resources.

dojo.provide('com.ZetaOne.widget.Dialog');
dojo.require('dijit.Dialog');
(function(){
        dojo.declare("com.ZetaOne.widget.Dialog", dijit.Dialog, {
                postCreate: function(){
                    this.inherited(arguments);
                    dojo.query('form', dojo.body())[0].appendChild(this.domNode);
                },
                _setup: function() {
                    this.inherited(arguments);
                    if (this.domNode.parentNode.nodeName.toLowerCase() == 'body')
                        dojo.query('form', dojo.body())[0].appendChild(this.domNode);                
                }                
        })
}());

Happy Coding!



12 responses to XPages Compatible Dojo Dialog Reusable Component

Art, June 21, 2011 12:15 AM

Hi Jeremy,

I finally found some time to look at dijit.TooltipDialog and here is my solution (code below).
It is based on your idea just customized for this widget.
I tested it for the html markup, not sure about behaviour when widget is created programmatically.

Cheers

Art


dojo.provide('xsp.TooltipDialog');
dojo.require('dijit.TooltipDialog');
(function(){
dojo.declare("xsp.TooltipDialog", dijit.TooltipDialog, {
onOpen: function() {
this.inherited(arguments);
if (this.domNode.parentNode.parentNode.nodeName.toLowerCase() == 'body'){
dojo.query('form', dojo.body())[0].appendChild(this.domNode.parentNode);
}
}
})
}());


Jeremy Hodge, March 12, 2011 7:04 PM

Hi Art, Yes, the same approach should work. The same issues are at work here, and the same fix should be applied.


Art, March 11, 2011 2:22 AM

Hi Jeremy,

Best approach so for. I was also trying to use dijit.TooltipDialog for the same purpose, but I think it is the same issue as with the dijit.Dialog. Do you know if your solution can also be applied to dijit.TooltipDialog widget?

TIA


Muhammad Sabir, January 8, 2011 1:24 AM

Love it... Thank you sooo much... I have spent days trying to find a solution..
I wanted a Dialog box to create new documents or to edit an existing one (by clicking on a link within an Xpage view control)...

I have tried all other approaches but nothing worked in editing an existing document -- they work for new docs though.

Thanks again. You rock!


ps, December 22, 2010 1:21 PM

Any chance someone could post an nsf with an example. I am having some trouble with this.


Lenni Sauve, July 22, 2010 4:31 PM

Hi Jeremy!

I have just mailed it to you. I may have not included enough code in the above, because I wasn't sure what to send.

I'm using an 8.5.1 client.

Thanks so much for your help!


Jeremy Hodge, July 22, 2010 3:56 PM

@Lenni - Looks like your source code has been hacked up ... there seems to be missing code between the <xp:this.rendered> and the CDATA tag ... the context.reloadPage() is not useful in an <xp:this.rendered> ... and then the next few lines close off an event handler, but there is no corresponding opening tags ... that will cause your first error about the XML not opening and closing with the same entity.

As for the other issues, what version of the notes client are you using, and can you email me the full source of your XPage so I can review it in full ?


Lenni Sauve, July 22, 2010 2:36 PM

Hi Jeremy!

This looks exactly what I'm trying to do, but I'm having a little problem and am hoping you can point me in the right direction. I want to use your Display Dialog button above a viewPanel, to allow a user to change a field on all of the selected documents.

I think my problem stems from the fact that I am using a dijit.Menu and want the button to be in that menu. No matter where I try to put the code for the editDocumentRegion panel, I receive the error "XML document structures must start and end within the same entity". Here is the top of my code for the menu:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" dojoParseOnLoad="true" dojoTheme="true">
<xp:this.resources>
<xp:dojoModule name="dijit.Menu"></xp:dojoModule>
<xp:dojoModule name="dijit.form.Button"></xp:dojoModule>
<xp:dojoModule name="dijit.Dialog"></xp:dojoModule>
<xp:dojoModule name="dijit.form.FilteringSelect"></xp:dojoModule>
<xp:dojoModule name="dojo.parser"></xp:dojoModule>
</xp:this.resources>

<!-- This starts the menu bar -->
<div class="menuBar">

<!-- This starts the expand/collapse button -->
<xp:div id="expand" dojoType="dijit.form.Button">
<xp:this.dojoAttributes>
<xp:dojoAttribute name="class" value="buttonh"></xp:dojoAttribute>
<xp:dojoAttribute name="iconClass" value="expandbuttonIcon">
</xp:dojoAttribute>
</xp:this.dojoAttributes>
<xp:this.rendered><![CDATA[#{ context.reloadPage()}">
</xp:executeScript>
</xp:this.action>
</xp:eventHandler>
</xp:div>


After all of the buttons, including the new one, I close the menubar div, then am trying to put the panel, with the dojoType of "com.ZetaOne.widget.Dialog", but it's at the <xp:this.script in the OK onclick event that I receive the error. And even if I remove that , I receive a message that the document can't be found if I try to preview what is there in the Notes client.

And that's the other thing - I'm trying to do this in the Notes client.

I also think there is something wrong with the way I have set everything up. While I followed your instructions, if I try to view the XPages-Compatible-Dojo-Dialog-Reusable-Component-Markup xpage using either Mozilla Firefox or IE, the OK and Cancel buttons display way above the edit box, before and after any buttons are clicked at all. No messages in the logs or on screen though. And if I try to view the XPages-Compatible-Dojo-Dialog-Reusable-Component xpage with either of those browsers or the Notes client I receive the error "Problem submitting an area of the page. 'com' is undefined. Submit the entire page?". However, if I go to the beta site that you indicated above, the button works perfectly. I didn't do anything to the xpagesblog.nsf database except to put it on the server, sign all the design elements with the server ID, and give it an ACL. I thought it would then use the script libraries inside of the database. When that didn't work, I had my Domino administrator put the file in the place indicated on the server, but there has been no change in what happens above.

So, in a nutshell, what do you think from the above that I'm doing wrong, and what should I do to correct it?

Thanks again so very much for your posts - they have been extremely helpful as I learn xPages!


Janko Stefancic, July 4, 2010 7:08 AM

Jeremy, thanks for this elegant solution.
I'm working on a XPages project and have been banging my head again the wall
because of this issue a few days now.

Thanks again


Dragon Chow, April 29, 2010 3:14 AM

Hi Jeremy,

Thanks for your working example of opening dijit.Dailog box programmatically. It worked perfectly when I open the dialog box from div markup and all buttons are active However, if I am trying to open an xpage in dialog box programmatically, the dialog box is opened and all fields are editable but all buttons are inactive. I am trying to open a selected document from a view panel to a dialog box so that I can change mode, edit, save and even add a new document too. The selected document is displayed in the opening dialog box but as i said, all buttons are not fire when clicked. Have you ever try to open an xpage in a dialog box from a column in view panel? Here is my code and hope that you can see what the issue causing all buttons inactive. Big thanks in advance.

dojo.require("dijit.form.Button");
dojo.addOnLoad(function(){
//first check if it's there so we don't create a duplicate
var dialog = dijit.byId("fieldProfileDialogId");
if (dialog) { dialog.destroyRecursive(); }
var url = "xpFormFieldProfile.xsp" + "?documentId=" + "#{
// create a "hidden" Dialog till calling show it
var dialog = new Com.ZetaOne.widget.Dialog({
title:"Field Profile",
href: url,
refreshOnShow: true,
preventCache: true
},
dojo.byId("fieldProfileDialogId")
);
// show the dialog box
dialog.show();
});


Jeremy Hodge, April 21, 2010 10:47 PM

Adam, I am working on an extended "samples" site for the XPages blog ... I took your question, and answered it with a sample there. Hope it helps.

Until I get a bit more done, and can get it put into the nav menu here, you can view the sample here:

http://beta219er.yellowbubble.org/xpagesblog.nsf/


Adam, April 21, 2010 6:47 PM

Than you so much for the informative post!

We've been struggling with trying to open up a dijit box in edit mode. Will this method help with that?

We've tried various method. In one method we can get it open but the buttons do not fire. In another method we have to load the document into the div tag and then use another button to actually show the div.

In short, we're trying to allow the user to pick a document from a data table column so that they can edit it directly in the dijit box. The problem that we're having is that we have to get the data source, load it and show the dijit box all in one step and this is difficult as you're going client to server to client. Are we missing something here? Any guidance that you could provide would be GREATLY appreciated.