Stuck on dijit dialogs again

  • Lotus support thinks my dijit dialog code is preventing server-side actions from firing. it’s conceivable, so I’m back to square on on dojo/dijit dialog usage. I’m searching here and the web and finding exactly the same resources I found three months ago, which aren’t illuminating the issue any further.

  • Here’s what I’m doing. I have buttons that pop dialogs to get one or more bits of data from the user. If the user clicks “Cancel”, simply hide the dialog and do nothing. If the user clicks “Ok”, put the one or more bits of data in known fields on the current XPage, then save it. Sounds simple.

  • I’m using a saveDocument simple action to perform the save because that’s the only way I know to get postSaveDocument to fire, which is critical. If I do a client-side submit() I never see pSD go off, or I’d use that.

  • So of necessity the button is a mix of CS & SS - the CS makes sure the dijit dialog has been created, doing that if it’s not there for some reason, then it does a show() on the dialog and it’s done. The SS is the saveDocument simple action.

  • The problem is the CS does not block for the dialog. Instead the code runs through to the show() and keeps on going so it’s impossible to return true or false to allow or deny the save. So if I default to false it never saves, and if I default to true it runs the save immediately, which dismisses the dialog.

  • I can only deduce I’m missing something trivially simple, yet countless hours of research have somehow missing it with alarming consistency. Could some toss me a clue?

Thanks for your time…

Subject: I’ll waddle in …

Hasn’t Jeremy Hodge done this sort of thing in the XPages Blog?http://www.xpagecontrols.com/xpagesblog.nsf/XPages-Compatible-Dojo-Dialog-Reusable-Component.xsp

It sounds like you want to do something similar except he’s launching his dialog from a link.

His [OK] button does a saveDocument like you’re doing & a partial refresh. Maybe the trick is in his client-side code with the “return true”.

// this client side script will run before the partial refresh executes. Here

// we will move the contents of the partial refresh back to the proper place,

// and destroy the dialog so that it can be garbage collected, and the

// registry will not prevent it from getting re-created on the next user-edit.

var dialog = dijit.byId(‘sampleDialogEditor’);

var editRegion = dojo.query(‘[id$=“editDocumentRegion”]’, dialog.containerNode)[0];

dojo.style(editRegion, { display: ‘none’ });

dojo.query(‘[id$=“refreshDocumentRegion”]’)[0].appendChild(editRegion);

dialog.hide();

dialog.destroy(false);

// instruct the partial refresh to continue to save the document.

return true;

I haven’t tackled this sort of thing yet … I will need to soon, so hoping I can follow Jeremy’s method.

Sorry I couldn’t be more help.

Subject: Thanks Judy…

  • It’s amazing what one can miss when searching. I find stuff there all the time, but don’t recall ever seeing this. (shrug) Appreciate the pointer. I’ll give this a go tomorrow…

Subject: I must be missing something…

  • I’ve fiddled with this all day, and I can’t get it to work. In particular:
  1. The dialog XPage source doesn’t have an id= attribute. The way one normally seems to set up a dojo dialog is by using an id. I don’t see how this works.

  2. I see references to editDocumetRegion and refreshDocumentRegion, but those don’t exist anywhere, not even on the page source of the working sample.

  3. I thought perhaps the partialrefresh on the link produces data used to build the dialog, and the elements I can’t find are part of that data. But I did a packet capture of the interaction between the browser and the sample page, and saw no such data. It could have been there but not in clear text … something was obviously returned.

  4. When I try to use ZetaOne’s dialog wrapper using a tag’s id, it tosses and error and won’t create the dialog. I’m thinking this has something to do with the fact that the sample doesn’t have an id. (grin)

Could someone point me in the right direction? Thanks!..

Subject: Maybe a simple example might help …

I’m not sure if what I did will be equivalent to your scenario, but I’ll lay it out for you. You might need to deconstruct your solution to the bare minimum then build up its complexity.

I have a document opened in EDIT mode, very simple, just an XPage for attachments. That XPage has the usual settings set to allow dijit.Dialogs to work – dojoParseOnLoad=true & dojoTheme=true & a dojoModule Resource of “dijit.Dialog” & the client-side JS script library included as a Resource. (Actually, you might not need all of that on your XPage if you put it on your custom control.)

And, a button that will show the dialog:

<xp:button id=“button1” value=“Add Attachment”

	styleClass="lotusBtnAction" style="margin-left:10px">

	<xp:eventHandler event="onclick" submit="false">

		<xp:this.script><![CDATA[	dijit.byId('attachDialogBox').show();]]></xp:this.script>

	</xp:eventHandler>

</xp:button>

Pretty standard fare.

Then my custom control that contains the dialog – I initially set up a Data source so I could bind the fields to edit boxes, etc. then removed the Data source at the end.

I have a [Save] & [Cancel] button & am showing the “X” top-right default button on the dialog:

The SAVE button is just a regular “Button” – not sure why I ended up with an action group in there, probably not necessary:

<xp:button id=“button1” styleClass="lotusBtnAction"value=“Save”>

<xp:eventHandler event=“onclick” submit="true"id=“eventHandler1” immediate=“false” save="false"refreshMode=“complete”>

<xp:this.script><![CDATA[dijit.byId("attachDialogBox").hide();]]></xp:this.script>

<xp:this.action>

	<xp:actionGroup>

		<xp:saveDocument></xp:saveDocument>

	</xp:actionGroup>

	</xp:this.action>

</xp:eventHandler>

</xp:button>

And, the CANCEL button is a “Cancel” button & just returns to the underlying document:

<xp:button value=“Cancel” id="button2"styleClass=“lotusBtnAction”>

<xp:eventHandler event=“onclick” submit="true"refreshMode=“norefresh” id=“eventHandler2” immediate=“true” save=“false”></xp:eventHandler>

</xp:button>

At the bottom of the control I’ve got a script block to load the dialog:

<!-- Script to load dialog box. Calls function in dialog javascript library -->

<xp:scriptBlock id="scriptBlock1" type="text/javascript">

	<xp:this.value><![CDATA[dojo.addOnLoad(function(){

dialog_create('attachDialogBox','Attachment ...');

// hide the "x" button on the dialog box title bar	//dojo.style(dijit.byId('attachDialogBox').closeButtonNode,'display','none');

}

); ]]></xp:this.value>

</xp:scriptBlock>

In action, when the dialog pops up you can see the initial Description on the underlyiing document & my new additions in the dialog.

Then when the [Save] is clicked the fields on the underlying document are updated – the Description & my new attachment is showing:

The only difference to your situation is you have the data source defined on your dialog & you want to run some postSaveDocument code when the [Save] button is clicked.

In my actual implementation I’m doing something very much like that except I call my Dialog from a different opened document & am creating a brand new Attachment doc & am running the postSaveDocument agent – it seems to be working. The only thing you need to remember if you’ve got multiple data sources is to set “ignoreRequestParms” to “true” on the one in your dialog/custom control.

Subject: I’m still a no-go at this station…

  • First off, I greatly appreciate your time and effort, Judy. One would think with all that input I could make this work. Sadly I have not.

My button to show the dialog looks like this:

<xp:button value=“eDocs Comment” id=“Comment” title=“Upload a comment to eDocs” icon=“/actn130.gif” styleClass=“actionBarBtn”>

<xp:eventHandler event="onclick">

	<xp:this.script><![CDATA[

dijit.byId(‘#{id:dlgWFNote}’).show();

	]]></xp:this.script>

</xp:eventHandler>

</xp:button>

I changed it based on your example. Originally it had:

return showMe(‘#{id:dlgWFNote}’, ‘Upload eDocs Comment’);

as the script. When I changed it to remove the return, the dialog was no longer “modal”, in that it would not wait for user input. It presented, stayed about a second, then auto-dismissed. If I’m real quick I can type something and click a button, but no matter what I do, the result is the same.

  • The custom control containing the dialog looks like this:

xp:this.resources

<xp:dojoModule name="dijit.Dialog" />

<xp:dojoModule name="dijit.form.Textarea" />

<xp:dojoModule name="dijit.form.Button" />

</xp:this.resources>

<xp:div id=“dlgWFNote” dojoType=“dijit.Dialog” style=“display:none;width:50%” title=“Upload comment”>

<xp:text value="Enter comment to be uploaded to eDocs:" style="display:block" />

<xp:inputTextarea id="dlgWFComment" value="#{Ticket.Comments}" style="min-height:10em;display:block;width:95%" />

<div style="text-align:center">

	<xp:button dojoType="dijit.form.Button" id="btnWFSend" value=" Add Comment" type="submit" icon="/actn010.gif">

		<xp:eventHandler event="onClick" submit="true" immediate="false" save="false" id="Accept" refreshMode="complete">

			<xp:this.action>

				<xp:saveDocument />

			</xp:this.action>

			<xp:this.script><![CDATA[

var xpAct=dojo.byId(“#{id:xpAction}”);

xpAct.value=“WFN:”+dojo.byId(“#{id:dlgWFComment}”).value+“]”;

alert(“xpAction: "”+xpAct.value+“"”);

dijit.byId(‘#{id:dlgWFNote}’).hide();

return true;

			]]></xp:this.script>

		</xp:eventHandler>

	</xp:button>

	&#160;-&#160;

	<xp:button dojoType="dijit.form.Button" id="btnWFCancel" value=" Cancel" type="button" onclick="dijit.byId('#{id:dlgWFNote}').hide();" icon="/actn011.gif" />

</div>

</xp:div>

xp:scriptBlock

<xp:this.value escape="false"><![CDATA[

dialog_create(“#{id:dlgWFNote}”, “Upload comment”);

]]></xp:this.value>

</xp:scriptBlock>

I added the dialog_create() at the bottom because you have it. If I put dojo.addOnLoad(dialog_create()) in the script block I get an error, but this straight dialog_create() seems to work. After putting that in, it did start running the CSJS (as indicated by the alert popping), and it does trigger some server-side activity, but only an afterRestoreView. It will not actually save, or run any save events on the data source.

I have tried every variation of immediate, save, and submit. The most I can get it to do is run afterRestoreView.

  • I do not have a data source associated with any dialog. There is only the data source on the XPage that the dialogs are on, which is named “Ticket”.

  • Here’s dialog_create() and show_me(), in an included client-side library:

function dialog_create(id, title1) {

var dialogWidget=dijit.byId(id);

if(dialogWidget && dialogWidget.destroyRecursive) dialogWidget.destroyRecursive(false);

dialogWidget=new dijit.Dialog(

	{title: title1},

	dojo.byId(id)

);

var dialog=dojo.byId(id);

dialog.parentNode.removeChild(dialog);

var form=document.forms[0];

form.appendChild(dialog);

dialogWidget.startup();

return dialogWidget;

}

/* Display a dijit dialog based on a Custom Control, creating it if necessary

 Based on a R8.5 Notes.net forum post by Lothar Mueller, and dijit web research

*/

function showMe(dlgName, dlgTitle) {

var dlg=dijit.byId(dlgName);

if(dlg) dlg.show();

else {

	dlg=dialog_create(dlgName, dlgTitle);

	if(dlg) dlg.show();

	else {

		alert(dlgName+" explicit create failed");

		return false;

	}

}

return true;

}

Previously I had this code at the bottom starting from the line “var dialog=…”

dojo.body().appendChild(dialogWidget.domNode);

dialogWidget.startup();	

return dialogWidget;	

which is based on xpagesblog dialog samples.

  • If I put the showMe() call back, it’s being typcially flakey. Before I replaced “return showMe(…)” with “dijit.byId(…).show()”, it would wait for user input. Now that I’ve put “return showMe()” back, it will no longer wiat for input. No matter what I do, it pops the dijit dialog and immediately dismisses it. Period. The only line I changed is the button to invoke the dialog, yet it’s behaving differently. This is the story of my entire XPages experience. Disastrous inconsistency.

  • The dialogs are all what should be painfully trivial things, like requesting some input and saving the document. In R-prior this would have taken minutes to build a Form, present it in a pop-up, and do a document.sumbit() to trigger WebQuerySave. Minutes.

I’d appreciate any input at all. Meantime I’m going to try the hokey pop-up window method. I’ve squandered so much time on what should be a cake walk that it’s not even remotely funny…

Subject: Ach, I feel your pain …

Responding via the web since I’m in the midst of work using a different ID & as you know, we can only have 1 instance of 8.5 running at a time anymore.

Okay, a couple of things I noticed. I don’t use “#(id:xxxDialog)” to refer to my dialogs; it doesn’t appear to be necessary. I do have a “dojo.onLoad” function in my custom control – you might have missed seeing it. I also don’t have any dojoType= declarations in my dialog or buttons; wonder if that’s causing you grief. Your CSJS code is more complex than what I’m using for the dialog_create; maybe try using the spartan version.

If you like, I can send you a stripped down version of my Db so you can test/compare. I was surprised at how easily mine worked 'cause I haven’t been successful with most things XPages-wise.

Subject: I’m game…

  • I’ll try what you suggest. I’m also stripping out all but two dialog launch buttons.

  • I don’t think I can use the hokey pop-up window because document.submit() has yet to run any server-side code for me, either. Still might wind up seeing what I can do. I need something.

  • If you could send a working sample I’d be eternally grateful. I’m under the impression my email is available via the forum somehow, as others have sent me email in direct response to posts I’ve made.

  • In case it’s not available on the forum: david punctuation gilmore a_t hq punctuation doe punctuation gov. Be sure to rename the file with a meaningless extension. The DoE filters “malicious” attachments, but a simple rename will let it in.

  • This should be fine as long as the sample is small. The DoE simply tosses out all email over a couple of megs, with the magic cutoff a moving target, and they didn’t used to bother telling anyone. Email simply vanished into the bit bucket, ne’er to return.

Thanks for your time…

Subject: The client-side JS for the dialog

I think I got this from Mark Hughes’ blog, not sure – definitely not my doings.

/**

  • Creates a dijit dialog box based on a div content

  • @param id div identifier

*/

function dialog_create(id, title1) {

// first check if the Dialog is there so we don’t create a duplicate

var dialogWidget = dijit.byId(id);

if( dialogWidget )

dialogWidget.destroyRecursive(true);

// create a new Dialog

dialogWidget = new dijit.Dialog(

{ title: title1, duration:600 },

dojo.byId(id));

// move the new Dialog inside the form tag

var dialog = dojo.byId(id);

dialog.parentNode.removeChild(dialog);

var form = document.forms[0];

form.appendChild(dialog);

dialogWidget.startup();

};