I have a Display Error control on my XPage using this example:
Error Management in XPages
Here is the code:
<xp:td>
<xp:inputText value="#{document1.ac_Email}" id="ac_Email1"
style="width:250px">
<xp:this.validators>
<xp:validateRequired message="Email is a required field.">
</xp:validateRequired>
<xp:validateExpression
message="Email needs to be in this format: john#acme.com">
<xp:this.expression><![CDATA[#{javascript:value.match(/^([0-9a-zA-Z]+([_.-]?[0-9a-zA-Z]+)*#[0-9a-zA-Z]+[0-9,a-z,A-Z,.,-]*(.){1}[a-zA-Z]{2,4})+$/)}]]></xp:this.expression>
</xp:validateExpression>
</xp:this.validators>
</xp:inputText>
</xp:td>
<xp:td>
<xp:message id="message1" for="ac_Email1"></xp:message>
</xp:td>
If the email is not formatted correctly -- using the validateExpression -- the display error message appears correctly. If the field is empty, a pop-up message (in Firefox) appears. Based on the example and what I coded, the display error control message should appear, not the pop-up message.
I am confused since I have two other fields on the form that, when empty, work correctly -- the required field message appears in the display error control to the right of the field. Is it because there are 2 validators on this field?
Thanks!
Related
I have been given an XPages project which I did not develop. The project has a OneUILayout that includes a Search Bar "facet". Is it possible to code a filter into the search bar facet so that retrieved records are omitted that have a field with a certain value. I have very little experience with XPages. The search results are output to a OneUI_searchpage.xsp where an edit box displays the search string then a dynamic View Panel shown the retrieved records. I have attached the source code for these two items below. Thank you
<xp:label value="Search String:" id="label1"></xp:label>
<xp:inputText id="inputText1" value="#{param.search}"></xp:inputText>
<xp:panel id="maincontentpanel">
<xe:dynamicViewPanel rows="30" id="dynamicViewPanel1"
width="100%">
<xe:this.data>
<xp:dominoView viewName="ContractsFlatByYear"
var="view">
<xp:this.search><![CDATA[#{javascript:return
param.search;}]]></xp:this.search>
</xp:dominoView>
</xe:this.data>
</xe:dynamicViewPanel>
After some consultation with stwissel below, I amended the application to have a check box on the search results xpage with it checked by default and created an additional view for the same output. One view to show cancelled contracts and one to omit cancelled contracts. The relevant Xpage section now looks like as follows;
<xp:checkBox text="Omit Cancelled Contracts"
id="OmitCancelled" defaultChecked="true" checkedValue="True"
uncheckedValue="False" style="padding-left:5.0em" value="#
{viewScope.viewSel}">
<xp:eventHandler event="onchange" submit="true" refreshMode="partial"
refreshId="dynamicViewPanel1"></xp:eventHandler>
</xp:checkBox>
<xp:panel id="maincontentpanel">
<xe:dynamicViewPanel rows="30" id="dynamicViewPanel1"
width="100%" partialRefresh="true">
<xe:this.data>
<xp:dominoView var="view">
<xp:this.viewName>
<![CDATA[#{javascript:var cancelledYesNo = viewScope.viewSel
= getComponent("OmitCancelled").getValue();
if(cancelledYesNo == "True"){
viewName = "ContractsFlatByYear"}
else {
viewName = "ContractsFlatByYearandCancelled"}}]]>
</xp:this.viewName>
<xp:this.search><![CDATA[#{javascript:return param.search;}]]
></xp:this.search>
</xp:dominoView>
</xe:this.data>
</xe:dynamicViewPanel>
This appears to work but I have the check box onChange event to apply a partial refresh on the dynamicviewpanel but only refreshes when I click on the dynamicviewpanel itself
The search bar facet only captures what you want to search and sends it to the specified XPages for processing.
You have 2 options:
Alter the facet to send the additional condition to the search page
Alter the search function in the search page (the one the query gets posted to) to filter that (if it is static).
Be aware: filtering in code is not a security feature (in case you were intending that). There's reader and author fields for that.
XPages in its core is JSF with some specialities around Domino. You might want to check out my article series on them.
Update
Based on the code snippet, your can get the desired result quite fast. Edit the view selection formula and add & conContractStatus <> "cancelled". You need to check first if that view is used elsewhere to show canceled contracts too. If that is the case, copy the view (eg add Active behind the name) and make the changes there.
Update 2
Your code doesn't return a value and you don't need to get to the component
<xp:this.viewName>
<![CDATA[#{javascript:return (viewScope.viewSel=="True") ? "ContractsFlatByYear" : "ContractsFlatByYearandCancelled";}]]>
</xp:this.viewName>
Let us know how it goes
This is a continuation of a previous question that I asked last week.
I have an XPage. On this XPage I have a repeater. In this repeater, I have a custom control that I am using to display the contents of its own datasource - a NotesXspDocument. This control is repeated 5 to 10 times, maybe up to 15 times. I do not want to make the user press on save for each and every repeated control, so I am using the submit button feature as described in the above linked question.
When the user presses the submit button, I am using the querySaveDocument and the postSaveDocument actions on the events tab (I also tried the properties with the same name in the Data tab with the same result). My issue is the following:
The validation is executed one control instance after another until the validation fails immediately saving the datasource before moving on to the next instance. When a NEW document is saved, it seems like the XspDocument is gone and the fields are emptied. I have checked, and I have set the datasource scope to view, as this behavior somehow resembles requestScope. As soon as I reload the page, the information is correctly presented.
I could use "context.reloadPage()" to just get the updated information, but this has the nasty side effect of removing all unsaved information (for example if validation failed on the xth line). How might I best go about solving/troubleshooting this issue? What should I be paying attention to? Has anyone else seen such a behavior?
I would love to call a validate function on all rows from the Containing XPage and then if all rows succeeded, then call the saveDataSources function. Any help is greatly appreciated!
A simple button outside your repeat control will do. I created this example:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:repeat id="repeat1" rows="30" value="#{javascript:4}">
<xp:panel id="dataPanel" disableOutputTag="true">
<xp:this.data>
<xp:dominoDocument var="document1" formName="Demo2">
</xp:dominoDocument>
</xp:this.data>
<xp:table>
<xp:tr>
<xp:td>
<xp:label value="Subject!" id="subject_Label1" for="subject1">
</xp:label>
</xp:td>
<xp:td>
<xp:inputText value="#{document1.Subject}"
id="subject1" required="true">
<xp:this.validators>
<xp:validateRequired
message="Say something">
</xp:validateRequired>
<xp:validateLength minimum="5"
message="Say 5 characters or more">
</xp:validateLength>
</xp:this.validators>
</xp:inputText>
</xp:td>
</xp:tr>
<xp:tr>
<xp:td>
<xp:label value="Color!" id="color_Label1" for="color1">
</xp:label>
</xp:td>
<xp:td>
<xp:comboBox value="#{document1.Color}"
id="color1" defaultValue="red">
<xp:this.validators>
<xp:validateExpression
message="We don't like red">
<xp:this.expression><![CDATA[#{javascript:value != "red"}]]></xp:this.expression>
</xp:validateExpression>
</xp:this.validators>
<xp:selectItem itemLabel="red"></xp:selectItem>
<xp:selectItem itemLabel="yellow"></xp:selectItem>
<xp:selectItem itemLabel="green"></xp:selectItem>
<xp:selectItem itemLabel="blue"></xp:selectItem>
<xp:selectItem itemLabel="white"></xp:selectItem>
<xp:selectItem itemLabel="black"></xp:selectItem>
</xp:comboBox>
</xp:td>
</xp:tr>
</xp:table>
</xp:panel>
</xp:repeat>
<xp:messages layout="table" style="color:red" id="messages1">
</xp:messages>
<xp:button value="Save?" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" immediate="false" save="true"></xp:eventHandler>
</xp:button>
</xp:view>
It will not save any of the data unless all validations are satisfied and it will not remove any entered data either. Don't get into the way what XPages does automatically (you also don't brush a cat against her fur). Your validation should happen in the validator and let the data source be saved by the button. As you see: no Query/Post event code is needed here.
I really don't get what you're trying to do so I'll just comment on a piece.
If you want data to survive a context.reloadPage() I think you would need to bind your controls to sessionScope. ViewScope is probably wiped out during the reload but sessionScope should still be available.
Good Luck!
I'm using the Extension Library and XPages to build a web based workflow application. One feature is to prompt a dialog and select the next approver before submitting it forward.
For new documents, the dialog appears, and it also appears when in read mode. It never opens for a saved document. I need it to work in SSJS, though the dialog does open in CSJS. Here is some of the code:
xpMain.xsp contains two custom controls: ccButtons and ccWFloDialogs.
ccButtons "Submit" button:
getComponent('dlgNextOwner').show();
ccWFloDialogs "dlgNextOwner" dialog:
<xe:dialog id="dlgNextOwner" title="Select Supervisor">
<xe:formTable id="ftDlgNextOwner" formTitle="Select Supervisor"
formDescription="You may select a different supervisor."
disableErrorSummary="true">
<xp:this.facets>
<xe:formRow id="formRow1" xp:key="footer" for="txtWFloNextOwner"
labelWidth="125px">
<xp:inputText id="txtWFloNextOwner" style="width:200px"
value="#{viewScope.nextOwner}">
</xp:inputText>
<xe:namePicker id="npNextOwner" dialogTitle="Select Supervisor"
for="txtWFloNextOwner">
<xe:this.dataProvider>
<xe:dominoNABNamePicker addressBookSel="all-public"></xe:dominoNABNamePicker>
</xe:this.dataProvider>
</xe:namePicker>
</xe:formRow>
</xp:this.facets>
</xe:formTable>
</xe:dialog>
In CSJS, I can use the following code and it successfully opens the dialog:
XSP.openDialog("#{id:dlgNextOwner}");
I'm also using Mark Hughes' picklist from the extension library, and if I remove the panel which contains the control and data source, the dialog shows up in SSJS! The code is in a custom control, although, if it's directly in the XPage, the problem is the same. Here is the code for the panel:
<xp:panel
id="vendorDiv">
<xp:this.data>
<xp:dominoView
var="nvVend"
viewName="V_Vend"
ignoreRequestParams="true"
databaseName="other/lookupdb.nsf"
startKeys="#{javascript:viewScope.srchVend}">
</xp:dominoView>
</xp:this.data>
<xe:formTable
id="ftGetVendor"
disableErrorSummary="true"
labelPosition="above">
<xe:formRow
id="frVendor"
for="cfVendorName"
label="Name of the Vendor:">
<xp:text
escape="true"
id="cfVendorName"
value="#{currentDocument.VendorName}"
style="width:200px">
</xp:text>
<xc:viewpicklist
rowsPerPage="15"
buttonImage="./add.png"
tableClass="tablecellgreen"
headerClass="headerclass"
rowClass="odd, even"
searchBar="false"
searchButtonText="Search"
searchButtonClass="button2"
searchBarClass="headerclass"
pagerStyleFirst="navbutton1"
pagerStylePrevious="navbutton2"
pagerStyleCurrent="navbutton4"
pagerStyleNext="navbutton2"
pagerStyleLast="navbutton3"
typeAheadBar="true"
select="Column"
onReturn="Set Scope Value"
bottomBarClass="bottomround headerclass"
cancelButtonText="Cancel"
cancelButtonClass="button2 floatthisright"
type="Single Value"
finishButtonText="Finish"
finishButtonClass="button2 floatthisright"
multiSelectButtonAddImg="./add.png"
multiSelectButtonRemoveImg="./delete.png"
picklistButtonClass="button"
openDialogWith="Link"
picklistLinkImg="./add.png"
multiSelectLinkAddImg="./add.png"
multiSelectLinkRemoveImg="./delete.png"
selectWith="Link"
clearSearchImg="./cross.png"
SelectCellWidth="30px"
dialogID="dlgVend"
dialogTitle="Select a Vendor"
dialogWidth="80%"
refreshID="vendorDiv"
ssjsSelectFunction="getVendorInfo"
varName="viewScope.vendorInfo"
datasrc="nvVend"
selectColumn="4"
linkImg="./add.png"
typeAheadVar="viewScope.srchVend">
<xc:this.viewColumn>
<xp:value>0</xp:value>
<xp:value>1</xp:value>
<xp:value>2</xp:value>
<xp:value>3</xp:value>
</xc:this.viewColumn>
</xc:viewpicklist>
</xe:formRow>
<xe:formRow
id="frVendorStatus"
for="cfVendorStatus"
label="Vendor Registration Status:">
<xp:text
escape="true"
id="cfVendorStatus"
value="#{currentDocument.VendorStatus}">
</xp:text>
</xe:formRow>
<xe:formRow
id="frVendorCountry"
for="cfVendorCountry"
label="Country Name:">
<xp:text
escape="true"
id="cfVendorCountry"
value="#{currentDocument.VendorCountry}">
</xp:text>
</xe:formRow>
</xe:formTable>
</xp:panel>
The requested vendor information populates the fields, without any problem or errors. However, something here seems to prevent dialogs from opening up using SSJS.
Can anyone see anything obvious I'm missing? The data source is in the panel, ignoreRequestParams is true (otherwise it doesn't work).
The main data source is in the entire XPage context. I tried to add the ccWFloDialog custom control outside the main panel, and change the data source to the panel, but that didn't work.
Any ideas?
Forget the dialog for now. This is probably data source related. Suggest you get it working just on the xpage first. With visible fields. then maybe use the rendered property to get it working on the xpage similar to how the dialog would appear. Once you have that working then you should be good to apply to dialog. This idea is to just take the dialog out of the equation first to make sure it works normally.
Instead, I decided to open the dialogs using CSJS, instead of SSJS. I've changed some of logic, and will have a bit more to do to finish this part of the project. Thanks to all!
I am taking an existing Lotus Notes database and converting to Xpages. There is one of those tables containing 3 multi-value fields, with New Line as the seperator and the "Add New", "Modify" and "Delete" buttons controlling how the data is entered and removed. The customer would like the XPage to look as similar to the Notes GUI as possible, and I was thinking I would use the dijit dialog box to do the add new line and figure out the delete and modify. But from what I can tell, the dialog box can only be used on client-side and the data input into the dialog box can't be brought down onto the Xpage. Is this true? I was thinking I would use an editable field within a repeat, but I also couldn't that working properly.
Basically, it the solution has to show the multi-value fields for past documents and also be able to allow users to edit those older document...plus work similar/exactly the way as in the past when creating new docs.
Thanks in advance for any help I can get on this as it seems a ton easier than I am probably making it out to be.
I just wanted to update after the solution below, which appears to be an excellent way to solve this problem. However, as an admitted XPages novice, I am really struggling with the application of this concept. This is what I have, and it obviously isn't working.
Logically, this sounds like a great solution. However, I am no xpages expert and I simply can't get this working properly even to get started. Anything at all that would make this easier for me to even get started would be a big help. I'm not one to usually look for "the answer"...I'm just having difficulty getting a handle on this Multi-value field table issue. Thanks again in advance...here's what I wrote that is coming up with a 500 error. "A" is the multi-value field name.
<xp:table>
<xp:tr>
<xp:td>
<xp:repeat id="repeat1" rows="30" var="rowdata">
<xp:this.value><![CDATA[#{javascript:document1.getItemValue("A")}]]></xp:this.value>
<xp:tr id="valueRow">
<xp:td>
<xp:text
value="#{javascript: return rowdata[i]}" />
</xp:td>
<xp:eventHandler event="onclick" submit="false"
refreshMode="partial" execMode="partial" execId="valueRow"
immediate="true">
<xp:this.action>
<![CDATA[#{javascript:document1.getItemValue("A")}]]>
</xp:this.action>
</xp:eventHandler>
</xp:tr>
</xp:repeat>
</xp:td>
</xp:tr>
</xp:table>
I would say do the following
Create a repeat control which will extract the data from the multi value fields and print them read only. The repeat control will generate a tr structure with a event handler bound to it on the onclick event. something like this:
2 In the onclick event change the style of the tr clientside (using dojo) so people know they selected that row and set the id / identifier of that row in a scoped var
3 Above the repeat control add controls like add, remove, update. The add and update will open a dialog box and will read the data from the selected row ( or none if its a add action). The delete control will remove the data from the multiline value fields, save the document and refres the repeat control.
This should work.
Using 8.5.3 UP1 with the Hotfix for the multi-rich text control issue.
I am dynamically binding rich text controls that are within a custom control wrapped in a repeat control. The rich text controls render just fine, except that the image upload functionality does not work. If I click on the image upload, choose a file, and then click send to server, the image apparently never makes it there.
Here is my code:
The Repeat Control:
<xp:repeat id="rptSections" rows="99" repeatControls="false"
var="sections" indexVar="rptIndex" value="#{javascript:2}">
<xc:ccDynamicSections_2 rptIndex="#{javascript:rptIndex}">
<xc:this.fieldName><![CDATA[#{javascript:"contentRT"+rptIndex}]]></xc:this.fieldName>
</xc:ccDynamicSections_2>
</xp:repeat>
The custom control:
<xp:inputRichText id="inputRichText1" value="#{document1[compositeData.fieldName]}" >
</xp:inputRichText>
I'm pretty sure if I can find a way to bind the rich text controls at run time I can make this work. I tried to do this and it appears to work on the page but when I go to save the document I get a error such like "Could not save the document NEW_79 NotesException: Object has been removed or recycled"
Bind after page load attempt:
<xp:repeat id="rptSections" rows="99" repeatControls="false"
var="sections" indexVar="rptIndex" value="#{javascript:2}">
<xp:text escape="true" id="computedField1">
<xp:this.value><![CDATA[#{javascript:var application = facesContext.getApplication();var scopedField = 'content'+rptIndex;var valueBinding = application.createValueBinding( '#{document1.' + scopedField + '}');getComponent("inputRichText1").setValueBinding('value', valueBinding );"test"+rptIndex}]]></xp:this.value>
</xp:text>
<xp:inputRichText id="inputRichText1"></xp:inputRichText>
</xp:repeat>
Any help is appreciated.
I think you should set repeatControls to true. Or else it will fail to correctly bind to your datasource. See this page too.