XSP JSF FacesContext addMessage does not always work - jsf

I have a JSF page where the user is entering several information. When the user submits the data it is first validated and if the submission is succesful the user should get a FacesMessage also.
I have a custom control for a menubar which I am using in every single page:
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xc="http://www.ibm.com/xsp/custom">
<xp:panel>
<xp:this.facets>
<!-- Some Logos and stuff -->
<xp:panel xp:key="contentFacet">
<xp:callback facetName="contentContainer"></xp:callback>
</xp:panel>
</xp:this.facets>
</xp:panel>
</xp:view>
The menu is then used the following way:
<xc:cc_layout_main><xp:this.facets>
<xp:panel xp:key="contentContainer">
<xc:cc_content_form></xc:cc_content_form></xp:panel>
</xp:this.facets></xc:cc_layout_main>
The cc_content_form uses this control:
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:messages id="messages1" styleClass="test" layout="table"
errorClass="alert-warning" fatalClass="alert-danger"
infoClass="alert-info" warnClass="alert-warning" showDetail="true"
showSummary="true" disableTheme="false" globalOnly="false">
</xp:messages>
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[
// Validierungs Nachrichten entfernen
var delayMs = 750;
$('body')
.on('click', function(event){
x$('#{id:messages1}').delay(delayMs).fadeOut(500);
})
.on('keyup', function(event){
x$('#{id:messages1}').delay(delayMs).fadeOut(500);
})
]]></xp:this.value>
</xp:scriptBlock>
</xp:view>
In the submit function I am using this in the validation function:
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "error", "some error"));
This call is wrapped in a helper class method with a singletone pattern so it can be used from all pages. For the validation messages this works just fine but further down in the valdiation method before I return the actionResult "xsp-success" it does not work. No message shows up, I do not get any Exception.
Can anybody help on this?

Turns out I messed up the NavigationRules ... Its working just fine

Related

xpages, save all documents in a repeat panel

I'm trying out a simple xpage that fetches a parent document (form fParent) and a few child documents (form fChild) via view vChildren. I can get the children as read only via a normal view control but these are read-only and I'd like to bind the children to documents so the save/submit button makes changes to both the parent and child documents.
In the repeat control, I'm binding the variable rowData to a DocumentCollection object which I'm assuming is iterated over and returns a Document object for each item (this seems to work as the xpage displays the correct number of custom controls). I understand from the HCL documentation that in order for the save action to be able to make changes to the child documents I need to add a document data source which I have done in the custom control.
The issue I have is that document2 in the custom control is picking up the parent form data and not the child form data (the note IDs for each child are the same as the parent which makes me think this is the case).
What am I doing wrong? Code below and thanks in advance.
xPage for the parent
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xc="http://www.ibm.com/xsp/custom">
<xp:this.data>
<xp:dominoDocument formName="fParent" var="document1" />
<xp:dominoView
var="view1" viewName="vChildren"
categoryFilter="#{document1.Key}">
</xp:dominoView>
</xp:this.data>
Name
<xp:inputText id="inputText2" value="#{document1.Name}"></xp:inputText>
<xp:br></xp:br>
Key 
<xp:text escape="true" id="computedField1" value="#{document1['Key']}">
</xp:text>
<xp:br></xp:br>
<xp:repeat id="repeat1" rows="30" var="rowData">
<xp:this.value><![CDATA[#{javascript:
var key = currentDocument.getItemValueString("key");
return database.getView('vChildren').getAllDocumentsByKey(key);}
]]>
</xp:this.value>
<xc:ccChildDoc></xc:ccChildDoc>
</xp:repeat>
<xp:button id="button1" value="Save" save="true" type="submit"></xp:button>
</xp:view>
Custom control for each child document
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" binding="#{rowData}">
<xp:this.data>
<xp:dominoDocument
formName="fChild" var="document2"
action="editDocument" computeWithForm="both"
documentId="#{javascript:rowData.getNoteID();}">
</xp:dominoDocument>
</xp:this.data>
<xp:panel>
Note id: 
<xp:text escape="true" id="computedField1" value="#{javascript:document2.getNoteID();}">
</xp:text>
<xp:br></xp:br>
Comment 
<xp:inputText id="inputText1" value="#{document2.Comment}" readonly="false">
</xp:inputText>
<xp:br></xp:br>
Field2 
<xp:inputText id="inputText2" value="#{document2.Field2}" readonly="false">
</xp:inputText>
<xp:br></xp:br>
<hr />
</xp:panel>
</xp:view>
Try adding ignoreRequestParams="true" to your data source for the child document.
This parameter tells XPages to ignore the documentId parameter in the URL for the child document data source and the child data source should then use documentId="#{javascript:rowData.getNoteID();}".

Trouble with handling attachments in Xpages

I am trying to write a fileUpload/fileDownload custom control with a Bootstrap like look. I am fairly happy with the look (see below).
However, I am getting very inconsistent behavior. I would very much like the user to be able to click the delete button and the attachment is removed and the repeat control is refreshed. In a similar fashion if the user selects "Upload" I think the attachment should be uploaded to the document and the repeat control refreshed as well.
I am storing the attachments in a single document that is separate from the main document [it is stored in a separate db from the code].
I am using the js fileInput library with the upload control.
I am using a repeat control to roll my own file download viewer.
The code works some of the time, but not always. When the page fails I get this error message (see below).
Any suggestions would be greatly appreciated.
Context Path: /scoApps/OTM1/OTM1.nsf
Page Name: /xpTest.xsp
javax.faces.FacesException
at com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:106)
at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:210)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:96)
at com.ibm.xsp.controller.FacesControllerImpl.execute(FacesControllerImpl.java:256)
at com.ibm.xsp.webapp.FacesServlet.serviceView(FacesServlet.java:228)
at com.ibm.xsp.webapp.FacesServletEx.serviceView(FacesServletEx.java:157)
at com.ibm.xsp.webapp.FacesServlet.service(FacesServlet.java:160)
at com.ibm.xsp.webapp.FacesServletEx.service(FacesServletEx.java:138)
at com.ibm.xsp.webapp.DesignerFacesServlet.service(DesignerFacesServlet.java:103)
at com.ibm.designer.runtime.domino.adapter.ComponentModule.invokeServlet(ComponentModule.java:576)
at com.ibm.domino.xsp.module.nsf.NSFComponentModule.invokeServlet(NSFComponentModule.java:1335)
at com.ibm.designer.runtime.domino.adapter.ComponentModule$AdapterInvoker.invokeServlet(ComponentModule.java:853)
at com.ibm.designer.runtime.domino.adapter.ComponentModule$ServletInvoker.doService(ComponentModule.java:796)
at com.ibm.designer.runtime.domino.adapter.ComponentModule.doService(ComponentModule.java:565)
at com.ibm.domino.xsp.module.nsf.NSFComponentModule.doService(NSFComponentModule.java:1319)
at com.ibm.domino.xsp.module.nsf.NSFService.doServiceInternal(NSFService.java:662)
at com.ibm.domino.xsp.module.nsf.NSFService.doService(NSFService.java:482)
at com.ibm.designer.runtime.domino.adapter.LCDEnvironment.doService(LCDEnvironment.java:357)
at com.ibm.designer.runtime.domino.adapter.LCDEnvironment.service(LCDEnvironment.java:313)
at com.ibm.domino.xsp.bridge.http.engine.XspCmdManager.service(XspCmdManager.java:272)
Caused by: java.lang.IllegalArgumentException
at javax.faces.model.ListDataModel.getRowData(ListDataModel.java:141)
at com.ibm.xsp.component.UIRepeatContainer.addIndexedDataContext(UIRepeatContainer.java:173)
at com.ibm.xsp.component.UIRepeatContainer.getDataContexts(UIRepeatContainer.java:86)
at com.ibm.xsp.util.DataPublisher.getDataContextList(DataPublisher.java:349)
at com.ibm.xsp.util.DataPublisher.revokeControlData(DataPublisher.java:271)
at com.ibm.xsp.component.UIDataPanelBase.revokeControlData(UIDataPanelBase.java:319)
at com.ibm.xsp.component.UIDataPanelBase.processDecodes(UIDataPanelBase.java:334)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1177)
at com.ibm.xsp.component.UIRepeat.processDecodes(UIRepeat.java:526)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1177)
at com.ibm.xsp.component.UIDataPanelBase.processDecodes(UIDataPanelBase.java:331)
at javax.faces.component.UIForm.processDecodes(UIForm.java:166)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1177)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1177)
at javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.java:343)
at com.ibm.xsp.component.UIViewRootEx._processDecodes(UIViewRootEx.java:1438)
at com.ibm.xsp.component.UIViewRootEx.processDecodes(UIViewRootEx.java:1399)
at com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:98)
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xc="http://www.ibm.com/xsp/custom">
<xp:this.data>
<xp:dominoDocument var="document1" databaseName="scoApps\OTM1\OTM1Data.nsf" formName="attachment" action="editDocument" documentId="349CDB2FB259D5D3862581090076AC50" />
</xp:this.data>
<script src="fileinput/js/fileinput.js" type="text/javascript" />
<link href="fileinput/css/fileinput.min.css" media="all" rel="stylesheet" type="text/css" />
<xp:scriptBlock id="scriptBlockInitFile">
<xp:this.value><![CDATA[$(document).ready(
function() {
$('input[type=file]').fileinput({
previewFileType: "image",
browseClass: "btn btn-primary",
browseLabel: "Browse...",
browseIcon: '<i class="glyphicon glyphicon-plus"></i>',
removeClass: "btn btn-danger",
removeLabel: "Delete",
removeIcon: '<i class="glyphicon glyphicon-trash"></i>',
uploadClass: "btn btn-info",
});
}
);]]></xp:this.value>
</xp:scriptBlock>
<xp:div themeId="container" style="width:800px">
<xp:br />
<xp:fileUpload id="fileUpload1" value="#{document1.attachments}">
<xp:this.attrs>
<xp:attr name="multiple" value="true" />
<xp:attr name="data-show-preview" value="false" />
</xp:this.attrs>
</xp:fileUpload>
<xp:br />
<xp:button value="Save Changes" id="button1" styleClass="btn btn-primary">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete" disableValidators="true">
<xp:this.action>
<xp:actionGroup>
<xp:save />
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:div>
<xp:repeat rows="30" id="attrepeat" first="0" var="att" indexVar="attachmentIndex">
<xp:this.facets>
<xp:text disableTheme="true" xp:key="header" escape="false">
<xp:this.value><![CDATA[<table class="table table-striped table-bordered table-hover"><col width="150"><col width="450"><th>File Name</th><th style="text-align:right">Delete</th>]]></xp:this.value>
</xp:text>
<xp:text disableTheme="true" xp:key="footer" escape="false">
<xp:this.value><![CDATA[</table>]]></xp:this.value>
</xp:text>
</xp:this.facets>
<xp:this.value><![CDATA[#{javascript:var bckDoc = document1.getDocument()
var attachments:java.util.Vector = session.evaluate("#AttachmentNames",bckDoc);
attachments}]]></xp:this.value>
<xp:tr>
<xp:td>
<xp:link escape="true" id="link1" target="_blank" text="#{javascript:att.toString();}">
<xp:this.value><![CDATA[#{javascript:var tmpStr:String;
var str:String;
var bckDoc = document1.getDocument()
var attachments:java.util.Vector = session.evaluate("#AttachmentNames",bckDoc);
tmpStr = attachments.toString;
tmpStr
var bckDoc = document1.getDocument()
var attachments:java.util.Vector = session.evaluate("#AttachmentNames",bckDoc);
tmpStr = attachments.elementAt(0);
var unid = "349CDB2FB259D5D3862581090076AC50"
var dbPath = "scoApps/OTM1/OTM1.nsf/"
var dbDataPath = "scoApps/OTM1/OTM1Data.nsf/"
var url = "http://localhost/";
url += dbPath;
url += "/xsp/.ibmmodres/domino/OpenAttachment/";
url += dbDataPath + "/";
url += unid
url += "/" + "attachments" + "/";
url += tmpStr;
url}]]></xp:this.value>
<xp:image id="image1" rendered="false">
<xp:this.url><![CDATA[#{javascript:var pdfImage = 'pdf.gif';
//if(attachment.indexOf("pdf")> 0)
return pdfImage; }]]></xp:this.url>
</xp:image>
&#160;
</xp:link>
</xp:td>
<xp:td style="text-align:right">
<xp:button value="Delete" id="button2" styleClass="btn btn-danger">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:function removeAttachment(targDB,doc_Url,fileName,docUnid2) {
//passing parameters by reference
var docUrl:String= doc_Url;
var targetDB:NotesDatabase = session.getDatabase(session.getCurrentDatabase().getServer(),targDB);
var attachmentName:String =fileName;
//deducing the document's unid from the document's url
//docUrl=#Left(docUrl,"?");
//var docUnid=#RightBack(docUrl,"/");
print (docUnid2);
//setting the handle to the document
var docContext:NotesDocument=targetDB.getDocumentByUNID(docUnid2);
if (docContext==null) {
viewScope.CodeError="Either the UNID is invalid or the target db does not contain the doc or both";
return;
}
//getting the handle to the concerned attachment
var embObj:NotesEmbeddedObject=docContext.getAttachment(attachmentName);
if (embObj==null) {
viewScope.CodeError="No attachment is found by the name "+ attachmentName;
return;
}
//remove the attachment
embObj.remove()
docContext.save(true,false);
}
var fleNme = att.toString();
print (fleNme);
removeAttachment("scoApps/OTM1/OTM1Data.nsf","http://localhost/scoApps/OTM1/OTM1.nsf//xsp/.ibmmodres/domino/OpenAttachment/scoApps/OTM1/OTM1Data.nsf//349CDB2FB259D5D3862581090076AC50/attachments/ITReport.xlsx",fleNme,"349CDB2FB259D5D3862581090076AC50");}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:td>
</xp:tr>
</xp:repeat>
</xp:view>
It's failing in the ApplyRequestValues phase, something related to running code for rows within the repeat. I've had that before in a Data View with using the caching was ID only. The key is identifying which component's code is failing (the value of the repeat, the link, the image or the button - if it's a component, which property) and whether it needs to run in that phase. It may not.
Looking at the stack trace, the "caused by" bit failing on getRowData() implies it might be a problem with value of the repeat, but I'm not totally sure. It could be one of the repeat's child components that's failing.
If it's a read-only bit of code, it could be wrapped in an if (view.isRenderingPhase()) block. Just make sure you output something valid for other phases! E.g. for a rendered property, set the result for other phases to true (I've missed that before and caused myself problems!)
If it's because the document datasource has not been initialised at that phase, wrapping everything in a Panel may solve the problem, by associating the dominoDocument datasource to be a child of the Panel, which may encourage it to be better re-initialised during the restoreView phase. This is a total stab in the dark, but I know during page load a dominoDocument datasource gets loaded at a different time when it's a child of a Panel as opposed to a child of the XPage itself.

duplicate items in Document after saving in a bean

I experience strange but reproduceable behaviour with an XPage which saves its values through a java bean. After copyAllItems to an document there are two richtext items in the document. First is empty, second is filled as expected.
This is my Xpage:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xc="http://www.ibm.com/xsp/custom">
<xp:this.data>
<xp:dominoDocument var="docDataSource" formName="test"></xp:dominoDocument>
</xp:this.data>
<xp:div id="test">
<xp:fileUpload id="fileUpload1" value="#{docDataSource.test}"></xp:fileUpload>
</xp:div>
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="test">
<xp:this.action><![CDATA[#{javascript:registration.testCopyAllItems(docDataSource);}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
This is my java bean method:
public void testCopyAllItems(DominoDocument docDataSource) throws NotesException{
Document docUser = database.createDocument(); // <- get any database
docDataSource.getDocument(true).copyAllItems(docUser, true);
docUser.save();
}
This is the result in the document:
Does anyone have a hint on what could cause the trouble?
This seems to be a "normal" behaviour and I have seen it a lot working with RichtText fields. It shouldn't matter. Notes can deal with a RichText field constisting of more than one item.
As a workaround,
delete the RichText field after copyAllItems() with removeItem() and
copy it with copyItem() separately.
This should result in one item only.

XPage fileDownload1 control becomes editable on page full refresh?

Why fileDownload1 control becomes editable (delete file attachment icon appears next to fileDownload control) when I just refresh the page. Here is my code where I use a button to refresh the page (just for the example)
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete"></xp:eventHandler>
</xp:button>
<xp:this.data>
<xp:dominoDocument var="document1" formName="myXpage"
databaseName="${javascript:sessionScope.SUPPORT_DB_FILE}"
action="openDocument">
</xp:dominoDocument>
</xp:this.data>
<xp:fileDownload
id="fileDownload1"
rows="30"
displayLastModified="false"
displayType="false"
displayCreated="false"
hideWhen="true"
allowDelete="true"
value="#{document1.MyBodyRTF}">
</xp:fileDownload>
I tried to replicate what you're describing, but am having trouble doing so. I created a new XPage and modeled it after your sample code.
Notable differences:
I never see the trash icon
I had to compute the UNID of some document with an attachment in the appropriate field
I set both the DB name and UNID in beforePageLoad
I noticed an interesting change in the UI behavior (see animated gif below)
I'm not sure what you're running into without having more source code to be able to view, but I can confirm that what I tried doesn't reproduce the result you're describing.
XPage source:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view
xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.beforePageLoad><![CDATA[#{javascript:sessionScope.myDbName = database.getFilePath();
var vw:NotesView = database.getView("SomeForms");
var first:NotesDocument = vw.getFirstDocument();
sessionScope.myFirstDoc = first.getUniversalID();
first.recycle();
vw.recycle();}]]></xp:this.beforePageLoad>
<xp:this.data>
<xp:dominoDocument
var="document1"
action="openDocument"
formName="SomeForm"
databaseName="${javascript:return sessionScope.myDbName;}"
documentId="${javascript:return sessionScope.myFirstDoc;}" />
</xp:this.data>
<xp:fileDownload
rows="30"
id="fileDownload1"
displayLastModified="false"
value="#{document1.SomeAttachments}" />
<xp:button
value="Refresh"
id="button1">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete" />
</xp:button>
</xp:view>

Xpages Dynamic dojo dialog control

I have a list of products (created using a repeat control) and wish to click on a particular product and bring up a dialog with further information about that particular product. I don't really want to generate dijit.dialog thing for every single product on that page, so how can I do this dynamically possibly using AJAX and partial refresh.
A similar non xpages example can be seen here: http://www.replacementkeys.co.uk/window?dir=asc&limit=12&mode=grid&order=position - where you hover over an image and a quick view button comes up, which then dynamically loads the content for that product.
Any ideas would be truly appreciated.
We build the dialog outside the repeat control and then the action that launches or shows it also sets a viewScope variable that is used UNID for the data source in the dialog. Just make sure you refresh the contents of the dialog as you open it...
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xe="http://www.ibm.com/xsp/coreex">
<xp:this.data>
<xp:dominoView var="promptView" viewName="dlgBoxes">
</xp:dominoView>
</xp:this.data>
<xp:panel>
<xp:repeat id="repeat1" rows="30" value="#{promptView}" var="promptEntry">
<xp:panel tagName="div">
<xp:text escape="true" id="computedField1" value="#{promptEntry.dlgName}">
</xp:text>
 
<xp:button value="details" id="button1">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:
var pe:NotesViewEntry = promptEntry;
viewScope.put("dlgDocUnid", pe.getUniversalID());
getComponent("dialog1").show();
}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:panel>
</xp:repeat>
</xp:panel>
<xe:dialog id="dialog1" keepComponents="false" partialRefresh="true">
<xe:this.title><![CDATA[#{javascript:
var unid = viewScope.get("dlgDocUnid");
if(!unid) return "";
var doc:NotesDocument = database.getDocumentByUNID(unid);
return doc.getItemValueString("dlgName");}]]></xe:this.title>
<xp:panel>
<xp:this.data>
<xp:dominoDocument var="dlgDoc" formName="dlgBox" action="openDocument">
<xp:this.documentId><![CDATA[#{javascript:viewScope.get("dlgDocUnid");}]]></xp:this.documentId>
</xp:dominoDocument>
</xp:this.data>
<xp:text escape="true" id="computedField2" value="#{dlgDoc.Title}">
</xp:text>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:text escape="true" id="computedField3" value="#{dlgDoc.dlg}">
</xp:text>
</xp:panel>
</xe:dialog>
</xp:view>
Happy coding
/Newbs
You can combine your repeat control with the Extension Library dialog control in order to be able to launch a dialog when the user clicks on the individual row. Chris Toohey has created an excellent article called Popup Dialog Forms from Views in XPages that demonstrates this.

Resources