Subscribe via Feed

Saving One out of Many Data Sources on an XPage and How to Create a New Document On Each Submission

Jeremy Hodge, Aug 17, 2009 12:33:16 PM

Over on Julian's Blog, he asked a question on how to submit only one data source out of multiple ones on an XPage, and then create a new document for that data source so that the next submission will create yet another new document. I put together a quick sample for him, but thought I'd detail it more here for everyone.

First, a quick description of the back end of the design. I created three documents, "Form 1", "Form 2", and "Form 3" ... each with a single uniquely named field. Then I created three views, one for each form, that displayed only that form, and the first column had the appropriate field for each form.

Now, we can create the XPage. Drop three panels on the form, and name them updateRegion1, updateRegion2, and updateRegion3 respectively. In each panel, and a view component, based on each of the respective views for each form.

You should have an XPage that so far looks similar to this:

Now, at the bottom of each of the updateRegionX panels, lets add another panel. for this panel, define a data source that is a new document of each panel's document (Form 1 for updateRegion1, Form 2 for updateRegion2, etc) called "documentX", again replacing the X with the form number, i.e. document1, document2, etc....

After you define the panel's data sources, add a field inside the new panel, binding it to that panel's datasource and the associated form's unique field, and add a button labeled "Save Form X", replacing X with the appropriate form number. You should have something like this:

At this point, you could set a simple action to "save document" to submit a single data source, or "save data sources" to submit all three. However, we want to be able to independantly submit each data source, update just that view, AND create a new document for that data source, so when it gets submitted again, it will submit as a new document.

So here's what you do. Select the button "Save Form 1", go to the Events tab, and change the "Server Options" to "Partial Update", and select "updateRegion1" for the IDs. Change the Server actions to "Script Editor" and enter the following lines of code:

document1.save();
document1.getDocument().replaceItemValue("FieldA", "")

The first line saves the document, and the second line clears the value of FieldA... This is important because in the next step, we'll tell the xPage to create a new document everytime the form is submitted, however, it won't clear the values of the previous submission... This line does that (if you had more fields, you'd add a line for each field you wan't to clear.) Here's a screen shot of the server event:

Ok, now here's the hidden gem to make this all work. Back on the panel where we created the document1 data source. Go to All Properties, and expand Data > data > dominoDocument and change the scope to "request"

Now, everytime the form is submitted, a new document is created. Repeat this for each of the other updateRegions. Then, just to prove there isn't any other trickery going on, or to make sure it isn't saving the other data sources when we save the a single source, add one more button to the bottom of the XPage labeled "Full Refresh, No Document Save" ... on the Events for that button, change the Server Options to "Full Update", and check the "Do not validate or update data" checkbox. That way you can force the page to refresh, and see that no other documents are getting created or saved.

Here's what it should look like on the web, after a bit of data has been created:

Now, if you've gotten this far and have been following along, and creating the database as you go, my apologies, because you can download the full working sample here.

 

UPDATE: Apparently the post/query events do not get called if you use document1.save(), so if you need them to run, change back from "Script Editor" to "Simple Actions" on your button, and an action group, add a "Save Document" action, followed by an "Execute Script" action to clear out your fields, as below:



23 responses to Saving One out of Many Data Sources on an XPage and How to Create a New Document On Each Submission

Thomas Adrian, October 30, 2010 9:18 AM

I just discovered that even if your data sources is within a custom control and these custom controls are not rendered they are still submitted.


Daniele Grillo, June 18, 2010 11:49 AM

In the classic domino solution I user the dojo.io.iframe.send(kw)....

How I can reproduce this in Xpages environment?

this is my code that I use in Dojo normal with Domino classic web:
---------------------------------------------------
var kw = {
method: "post",
handleAs: "text",
form: document.forms["_NotesNameForm"],
handle: function(data,ioArgs){
dojo.byId('MexStatus').innerHTML = "Send Completed!";
}};
dojo.io.iframe.send(kw); //Send the form in ajax mode withfile upload in backend
---------------------------------------------------


Jeremy Hodge, June 17, 2010 2:59 PM

Ok, granted ... "bug" might be semantically incorrect ... howabout "unexpected behavior/behaviour?" :) Yes, the iframe is required to complete it, however, from the end users perspective, if IBM is going to include an upload control in the XSP controls, and is going to promote the use of partial refreshes, and has already created extended dojo controls for other functionality, wouldn't it make sense for them to do the same thing in this case as well?


Matt White, June 17, 2010 2:28 PM

@Jeremy / @Daniele,

My understanding is that this is not a "bug" with XPages as such. Basically it is not currently possible to post a file attachment over AJAX, you either have to use Flash or a virtual iFrame solution if you don't want the entire page to refresh. As far as I know there is nothing that IBM can do about this at the moment.

Matt


Jeremy Hodge, June 17, 2010 2:25 PM

Known bug with 8.5.1 ... partial refreshes will not post an upload from an upload control. Upload controls require a full refresh. I know its on the dev teams's radar, But not sure when it will be addressed.


Daniele Grillo, June 17, 2010 2:21 PM

I try to insert an UploadControl after inputbox....
But when save the document don't attach the document in the final document...
Have you any suggest?


Sean Cull, September 29, 2009 10:49 AM

Jeremy,
when you use the aimple action to "Save Document" why does it only save the "relevant" documet and not all 3

is it because the button is inside the panel or because the button does a partial refresh on just the relevant panel ? or some equally mysterous xpage vodoo ?


Jeremy Hodge, August 23, 2009 3:40 PM

Yep, the idea behind it is you are identifying that panel as the target for the partial refresh, and only that element (and any elements contained within it) gets refreshed. The key is really the onchange event of the combo box that is set up to do a partial refresh of the panel.


Lenni Sauve, August 23, 2009 3:15 PM

Jeremy - that worked perfectly! So I'm understanding both from your "Saving One Out of Many Data Sources..." above and the code that you posted for what I'm doing, that any time you want a piece of functionality to work independently of other functionality in your xpage, you need to stick it in a a panel all on its own. Which makes sense when I think about it.

Thanks so much for your help!


Jeremy Hodge, August 21, 2009 10:56 PM

Lenni, If I understand what you are trying to do, I believe this is what you are looking for. Take this code, and paste it into the source of a new XPage, replacing everything that is pre-generated. This example uses a form you'll have to create called "Sample" that has three fields, "Field1" "ComboField" and "ComboOther" ... Let me know if you have questions, or if I missed the mark on what you were looking for,


<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.data>
<xp:dominoDocument var="document1" formName="Sample"></xp:dominoDocument>
</xp:this.data>
<xp:panel id="otherPanel">
<xp:comboBox id="comboBox1" value="#{document1.ComboField}">
<xp:selectItem itemLabel="Option 1" id="selectItem1"></xp:selectItem>
<xp:selectItem itemLabel="Option 2" id="selectItem2"></xp:selectItem>
<xp:selectItem itemLabel="Other" id="selectItem3"></xp:selectItem>
<xp:eventHandler event="onchange" submit="true"
refreshMode="partial" id="eventHandler1" refreshId="otherPanel" immediate="true">
</xp:eventHandler>

</xp:comboBox>
<xp:panel
rendered="#{javascript:getComponent('comboBox1').getSubmittedValue() == 'Other' || getComponent('comboBox1').getValue() == 'Other'}">
Other:
<xp:inputText id="inputText1"
value="#{document1.ComboOther}" required="true">
<xp:this.validators>
<xp:validateRequired
message="You must provide a value for Other">
</xp:validateRequired>
</xp:this.validators></xp:inputText>
</xp:panel>
</xp:panel>

<xp:br></xp:br>
Field 1 :
<xp:inputText id="inputText2" required="true" value="#{document1.Field1}">
<xp:this.validators>
<xp:validateRequired
message="Field 1 Must Contain a Value">
</xp:validateRequired>
</xp:this.validators>
</xp:inputText>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:messages id="messages1"></xp:messages>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:button value="Submit" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" id="eventHandler3" immediate="false"
save="true">
</xp:eventHandler>
</xp:button>
</xp:view>


Lenni Sauve, August 20, 2009 8:20 PM

Hi Jeremy!

I was able to open it successfully now - thanks! And if you have any ideas at all about how I can do what I'm trying to, that would be wonderful! Thank you so much!


Jeremy Hodge, August 20, 2009 8:11 PM

Hi Lenni. I've re-posted the database, let me know if it works for you.

I'll try to put together an example of what I think you are trying to go for as well.


Lenni Sauve, August 20, 2009 7:46 PM

Hi Jeremy!

I am new to xPages and I'm struggling with the validation right now. I tried to download your sample, but it is locally protected. Can you post an unencrypted copy please?

I'm working with a drop-down field from which a selection is required. If the selection is "Other", then I want an "Other" text field displayed. There are 2 problems with this:

First, because when the document is new there is a default selection in the drop-down field, so the "Other" text field is hidden and is not rendered, so I can't do a partial update, just to have the update affect it. If I do a full update, this invokes every other server-side field validation, which I don't want. If I don't do an update, the "Other" text field isn't ever displayed because the selection made in the drop-down field isn't seen by the server.

I only want the field validation for the other fields to display when the "Save" button is clicked, to submit the entire xpage. BUT, I want to use the server-side validation because I like the way the errors display. I could put more code in each field advising it to wait until submission is occurring, but I wouldn't think I should have to do that. I mean what's the point of validation if it isn't elegantly done?!

I am hoping a copy of your database will give me some ideas about how I can achieve what I want to do. Thanks so much for your post - it is quite informative!


Jeremy Hodge, August 18, 2009 10:27 AM

Glad to be of help!


Julian Buss, August 18, 2009 7:05 AM

I just referenced your geat post in the xpageswiki: http://xpageswiki.com/web/youatnotes/wiki-xpages.nsf/dx/Work_with_datasources


Julian Buss, August 18, 2009 6:44 AM

works! Changing the button to the simple action "save document" works, the query/post events are executed. So, it seems that my problem is solved. Thank, Jeremy!


Julian Buss, August 18, 2009 5:38 AM

Jeremy,

thanks for the tip with the simple action, that seems to work. I'm about to try some more and will report in some minutes :-)


Jeremy Hodge, August 17, 2009 9:08 PM

@Julian .... I am curious ... could you still not get the querysave/postsave's to run after changing from document.save() to the simple action ?


Julian Buss, August 17, 2009 8:12 PM

mmmh.. perhaps I can move my scripts from querysave/postsave into the onclick of the button, before the save action and after it... but really, now I got to get some sleep first :-)


Julian Buss, August 17, 2009 8:06 PM

Jeremy, so that's a great post of yours, but does not solve my problem... or at least means some more workarounds... because in the querySave event I set some generic fields, which are not on the XPages (like createddatetime or createdby).
And in the postsave I run an agent... I will play more with that tomorrow... I just wonder why that usecase is such a big problem.


Jeremy Hodge, August 17, 2009 5:09 PM

@Julian ... It appears so, i've updated the blog entry on how to get the actions to run ....


Mark Hughes, August 17, 2009 4:24 PM

How in the world did you figure that out?

Man, i think some people have access to the development team or something...

Great tip ... :)


Julian Buss, August 17, 2009 3:12 PM

I just tried it... but it seems that with documentsource.save() the querysave event is not triggered... can you confirm that?