Trouble with handling attachments in Xpages - 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.

Related

Xpages: Refresh read only field on competition of DialogBox

My Xpage is in read mode. There is a Notes field with a "Add Notes" button. Click the button, user adds notes in dialogbox and clicks "Add Notes". The button does the work of adding the notes and saving the document.
I want to update the underlying notes field so the user will see their additions. How can I accomplish this?
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xe="http://www.ibm.com/xsp/coreex">
<xp:panel id="pnlAll">
<xp:this.data>
<xe:objectData saveObject="#{javascript:PCModel.save()}"
var="PCModel">
<xe:this.createObject><![CDATA[#{javascript:var pc = new com.scoular.model.PC();
var unid = sessionScope.get("key");
if (unid != null) {
pc.loadByUnid(unid);
sessionScope.put("key","");
viewScope.put("readOnly","Yes");
} else {
pc.create();
viewScope.put("readOnly","No");
}
viewScope.status = pc.status;
return pc;}]]></xe:this.createObject>
</xe:objectData>
</xp:this.data>
<xp:inputTextarea id="inputTextarea3" cols="1" rows="10"
disabled="true" value="#{PCModel.notes}">
</xp:inputTextarea>
<xp:br></xp:br>
<xp:button value="Add Notes" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:getComponent("dialogAddNotes").show()}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:br></xp:br>
<xp:div styleClass="modal fade" id="model1" role="dialog">
<xe:dialog id="dialogAddNotes" styleClass="modal-dialog"
title="Add Notes">
<xp:div style="margin-left:10.0px;margin-right:10.0px">
<xp:inputTextarea id="inputTextarea4" value="#{viewScope.addNotes}"
cols="1" rows="18">
</xp:inputTextarea>
</xp:div>
<xp:div styleClass="modal-footer">
<xp:button type="button" styleClass="btn btn-primary" id="button17"
value="Add Notes">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="dialogAddNotes">
<xp:this.action><![CDATA[#{javascript:var newLne = "\n";
var oldNte = PCModel.notes;
var usrNme:String = userBean.displayName;
var dte = session.createDateTime(#Now());
var lnkStr:String = "Notes added by " + usrNme + " at " + dte + newLne + newLne + viewScope.addNotes + newLne + newLne + oldNte;
var newNotes:String = lnkStr
PCModel.notes = newNotes;
PCModel.save();}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:div>
</xe:dialog>
</xp:div>
</xp:panel>
</xp:view>
You need to partially refresh the updated text area field called inputTextarea3 instead of the dialog.

Xpages-Setting Up the ViewScope from client-side javaScript (oncontextmenu)

I have a Xpages in which I have repeat control, Now I have the list of documents from a view. Onclick on the row is setting the viewScope Array with the Unid.
I have done this actually for the purpose of selecting the document and to keep track that which document is selected, I am successfull in doing that but the main purpose was, I wanted to obtain the UNID on right-Click context menu.
Now, Also the right click event is providing me the UNID in one text field. I have obtained this by using "oncontextmenu" attribute in a div tag.
<div oncontextmenu="javascript:
var a = document.getElementById('#{id:inputText1}').value;
document.getElementById('#{id:inputText2}').value=a;
return false;">
There is "inputText1" in each row with the default value UNID of the perticular row.
In above code I am getting the UNID from "inputText1" and setting it up to the "inputText2", So on right click I am successfully getting the UNID of the clicked row.
In futher case I have an idea that I can do any operation by using that UNID but instead of setting the UNID to the "inputText2", I want to set this UNID to viewScope not in "inputText2".
Basically my overall issue is that I want to set UNID which I am getting on right-click(oncontextmenu) to viewScope not in any text field("inputText2") using above client-side java script.
example code:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xe="http://www.ibm.com/xsp/coreex">
<xp:this.afterPageLoad><![CDATA[#{javascript:var myList = new java.util.ArrayList();
sessionScope.put("myList",myList);}]]></xp:this.afterPageLoad>
<xp:button value="Refresh" id="button3">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="repeat2">
</xp:eventHandler></xp:button>
<xp:repeat id="repeat2" rows="30" value="#{sessionScope.myList}"
var="listData">
<xp:text escape="true" id="computedField1">
<xp:this.value><![CDATA[#{javascript:listData+" , "}]]></xp:this.value>
</xp:text>
</xp:repeat>
<xp:inputText id="inputText2"></xp:inputText>
<xp:repeat id="repeat1" rows="30" var="rowData"
indexVar="repeatIndex" first="0" styleClass="abc">
<xp:this.value><![CDATA[#{javascript:var viewName = "Adressakten";
var v:NotesView = database.getView(viewName);
return v.getAllEntries();}]]></xp:this.value>
<xp:br></xp:br>
<div oncontextmenu="javascript:
var a = document.getElementById('#{id:inputText1}').value;
document.getElementById('#{id:inputText2}').value=a;
return false;">
<xp:inputHidden id="inputText1">
<xp:this.defaultValue><![CDATA[#{javascript:var doc:NotesDocument = rowData.getDocument();
return doc.getUniversalID();}]]></xp:this.defaultValue>
</xp:inputHidden>
<xp:div id="div1">
<xp:this.style><![CDATA[#{javascript:javascript:var keyCode = rowData.getDocument().getUniversalID();
var myArray = sessionScope.get("myList");
if(myArray.contains(keyCode))
return "border-color:rgb(192,192,192);border-style:solid;border-width:thin;height:42.0px;background-color:green;cursor:pointer;"
else
return "border-color:rgb(192,192,192);border-style:solid;border-width:thin;height:42.0px;background-color:rgb(255,255,128);cursor:pointer;"}]]></xp:this.style>
<xp:text escape="true" id="computedField2">
<xp:this.value><![CDATA[#{javascript:var doc:NotesDocument = rowData.getDocument();
return doc.getItemValueString('aTitel');}]]></xp:this.value>
</xp:text>
<br />
document Id:
<xp:text escape="true" id="computedField3">
<xp:this.value><![CDATA[#{javascript:var doc:NotesDocument = rowData.getDocument();
return doc.getUniversalID();}]]></xp:this.value>
</xp:text>
<xp:br></xp:br>
<xp:button value="Add" id="button1" rendered="false">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="computedField2">
<xp:this.action><![CDATA[#{javascript:var keyCode = rowData.getDocument().getUniversalID();
var myArray = sessionScope.get("myList");
if(!myArray.contains(keyCode)){
myArray.add(keyCode);
}}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:button value="Remove" id="button2" rendered="false">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:var keyCode = rowData.getDocument().getUniversalID();
var myArray = sessionScope.get("myList");
myArray.remove(keyCode)}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:var keyCode = rowData.getDocument().getUniversalID();
var myArray = sessionScope.get("myList");
if(!myArray.contains(keyCode)){
myArray.add(keyCode);
}
else{
myArray.remove(keyCode);
}}]]></xp:this.action>
</xp:eventHandler>
</xp:div></div>
<br />
</xp:repeat>
</xp:view>
It sounds like the JSON RPC Service from the Extension Library is what you need. That will allow you to run SSJS using a value passed from CSJS. It's covered on pages 351-3 of XPages Extension Library book and there may be examples in Extension Library Demo database.
I absolutely agree with the answer of Paul Stephen Withers, the best way to do this is using JSON RPC.
Here a JSON RPC working example:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xe="http://www.ibm.com/xsp/coreex">
<xe:jsonRpcService id="jsonRpcService1" serviceName="rpcService">
<xe:this.methods>
<xe:remoteMethod name="setUniqueID" script="sessionScope.put('sessionScopeVarTest', unid);">
<xe:this.arguments>
<xe:remoteMethodArg name="unid" type="string"></xe:remoteMethodArg>
</xe:this.arguments>
</xe:remoteMethod>
</xe:this.methods>
</xe:jsonRpcService>
Show Value of "sessionScope.sessionScopeVarTest" ->
<xp:text escape="true" value="#{sessionScope.sessionScopeVarTest}" style="font-weight:bold">
</xp:text>
<br/>
<br/>
<xp:button id="btnTriggerRPC" value="Trigger RPC Method">
<xp:eventHandler event="onclick" submit="false">
<xp:this.script><![CDATA[rpcService.setUniqueID('13F51C65D8C257FCC1257ED000361786')]]></xp:this.script>
</xp:eventHandler>
</xp:button>
<xp:button id="btnRefresh" value="Refresh Page">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
</xp:eventHandler>
</xp:button>
</xp:view>

Why does this code write out TWO documents?

Have a database where I only want one document for a certain category. So when the user goes to this Xpage I want to test to see if there is already a doc, and if so grab that one, if not, then create and save one.
I wrote some SSJS in the datasource to do this, but the first time I run it it creates two docs. I put a print in the code and it executes this part twice. Why does it do that?
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xe="http://www.ibm.com/xsp/coreex">
<xp:this.beforePageLoad><![CDATA[#{javascript:sessionScope.selectedPage = "page001"}]]></xp:this.beforePageLoad>
<xp:this.resources>
<xp:script src="/xpValidationDocument.jss" clientSide="false" />
<xp:styleSheet href="/custom.css" />
</xp:this.resources>
<xp:this.data>
<xp:dominoDocument var="document1" action="editDocument">
<xp:this.documentId><![CDATA[#{javascript:sessionScope.selectedPage = "page001";
var v:NotesView = database.getView(sessionScope.selectedPage)
var doc:NotesDocuent = v.getFirstDocument()
if (doc == null)
{doc = database.createDocument();
doc.appendItemValue("form","document");
doc.appendItemValue("key",sessionScope.selectedPage);
doc.appendItemValue("crtUsr",session.getCommonUserName());
doc.appendItemValue("crtDte",session.evaluate('#Today'))
doc.save();
print ("here");
return doc.getUniversalID();}
else
{
print ("here2");
return doc.getUniversalID()}}]]></xp:this.documentId>
</xp:dominoDocument>
</xp:this.data>
<xp:panel style="width:900.00px" id="pnlForm">
<xe:widgetContainer id="widgetContainerHeader"
style="width:100%">
<xp:panel id="plContainer">
<xe:formTable id="frLocationMaster"
disableErrorSummary="true" disableRowError="true"
style="lotusForm2" styleClass="scllotusui30dojo">
<xp:this.facets />
<xe:formRow id="formRow5" labelPosition="none"
style="padding-bottom:10.0px">
<xp:table style="width:99%" border="0"
cellpadding="0" role="presentation" cellspacing="0"
id="table2">
<xp:tr>
<xp:td
style="width:80.00px;min-width:120px">
<xp:label id="label2" for="formRow1"
value="Notes" />
</xp:td>
<xp:td style="width:px">
<xp:inputRichText
id="inputRichText1" value="#{document1.Body}">
<xp:this.attrs>
<xp:attr name="toolbar">
<xp:this.value><![CDATA[
[
["Format", "Font", "FontSize"],
["Bold", "Italic", "Underline", "Strike", "-", "TextColor", "BGColor", "-", "JustifyLeft", "JustifyCenter", "JustifyRight", "JustifyBlock", "NumberedList", "-", "BulletedList"],
["Indent", "Outdent"],
["Subscript", "Superscript"],
["RemoveFormat", "-", "MenuPaste", "-", "Undo", "Redo", "Find", "LotusSpellChecker", "-", "Image", "Table", "Link", "Flash", "-", "PageBreak", "HorizontalRule", "SpecialChar", "Blockquote", "Smiley", "ShowBlocks"],
["Maximize", "Source"]
]
]]></xp:this.value>
</xp:attr>
</xp:this.attrs>
<xp:this.dojoAttributes>
<xp:dojoAttribute
name="enterMode" value="2" />
</xp:this.dojoAttributes>
</xp:inputRichText>
</xp:td>
</xp:tr>
</xp:table>
</xe:formRow>
</xe:formTable>
</xp:panel>
</xe:widgetContainer>
</xp:panel>
</xp:view>
After you have created the document det the UNID or the NoteID in a viewScope variable and at the top of you code check if the scope variable is null if not use that one.
the reason for this is that the datasource is recalculated several times while loading the page.
So the code would be something like this
sessionScope.selectedPage = "page001";
if(viewScope.thisUNID==null){
var v:NotesView = database.getView(sessionScope.selectedPage)
var doc:NotesDocuent = v.getFirstDocument()
if (doc == null)
{doc = database.createDocument();
doc.appendItemValue("form","document");
doc.appendItemValue("key",sessionScope.selectedPage);
doc.appendItemValue("crtUsr",session.getCommonUserName());
doc.appendItemValue("crtDte",session.evaluate('#Today'))
doc.save();
print ("here");
viewScope.thisUNID=doc.getUniversalID()
return viewScope.thisUNID;}
else
{
print ("here2");
viewScope.thisUNID=doc.getUniversalID()
return viewScope.thisUNID}
}else{
return viewScope.ThisUNID
}
I see a couple of problems on a quick review.
As Per says, documentId may need to be page load binding, not runtime - the datasource had to be loaded in before render response, and runtime binding may not run early enough.
But the bigger problem is your documentId code is not going to have any effect, because you are not setting ignoreRequestParams="true". Consequently the documentId will be picked up from the URL parameters and, if there's nothing there, it will create a new document each time.

How to Save Values in Documents Edited In-line On Repeat Control

I have a repeat control on an xPage with a text field displayed directly in edit mode. When a user changes the value in the field, I need them to be able to either:
Select an icon directly beside the field to save the value in the document.
Make changes to this field in more than one document and click a button to save all of these changes to the appropriate documents saved simultaneously.
What I have so far is a method of capturing the unids of the documents whose editable field has been updated.
I cannot get either of these saves to work. I have listed below the portion of the code that controls these areas.
Here's the save all and sessionScope information
<xp:panel id="InlineEditContainer" xp:key="facetMiddle" style="width:100%">
<xp:this.data>
<xp:dominoView var="view1" viewName="vwMetricsByAssigned">
<xp:this.postOpenView><![CDATA[#{javascript:var myList = new java.util.ArrayList();
sessionScope.put("myList", myList);}]]></xp:this.postOpenView></xp:dominoView>
</xp:this.data>
<xp:button value="Submit All" id="button1">
<xp:eventHandler event= <"onclick" submit="true" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:// Getting list of unids from docs which have been updated, and saving those docs
var db:NotesDatabase
if(sessionScope.myList == null){
return;
}else{
for (var s in sessionScope.myList){
var doc:NotesDocument = (db ? db.getDocumentByUNID(s) : database.getDocumentByUNID(s));
if (doc && doc.isValid()) {
doc.save();
}
}
}}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:br></xp:br>
<xp:repeat id="repeat1" rows="30" value="#{sessionScope.myList}" var="listData">
<xp:text escape="true" id="computedField6"><xp:this.value><![CDATA[#{javascript:listData + " , "}]]></xp:this.value></xp:text></xp:repeat>
<xp:br></xp:br>
Here's all the repeat data
<xp:repeat id="repeat2" rows="20" var="FColl" indexVar="idx" value="#{javascript:view1}">
<xp:panel id="InlineEditContainer2">
<xp:this.data>
<xp:dominoDocument var="document1" formName="frmMetricData" action="editDocument" documentId="# {javascript:FColl.getNoteID();}" >
</xp:dominoDocument>
</xp:this.data>
<xp:tr>
<xp:td id="td1">
<xp:text escape="true" id="computedField3">
<xp:this.value> <![CDATA[#javascript:FColl.getDocument().getItemValueString("BusinessUnit")}]]>
</xp:this.value>
</xp:text>
</xp:td>
<xp:td id="td2">
<xp:link escape="true" id="link1" value="/MetricData.xsp">
<xp:this.text><![CDATA[#{javascript:FColl.getDocument().getItemValueString("MetricName")}]]> </xp:this.text>
<xp:eventHandler event="onclick" submit="true" refreshMode="norefresh" immediate="true">
<xp:this.action>
<xp:openPage name="/MetricData.xsp" target="editDocument" documentId="#{javascript:return FColl.getNoteID();}" />
</xp:this.action></xp:eventHandler>
</xp:link>
</xp:td>
<xp:td id="td3">
<xp:inputText id="EditBox3" value="#{document1.Actual}" tabindex="1">
<xp:this.defaultValue><![CDATA[# {javascript:FColl.getDocument().getItemValueString("Actual")}]]></xp:this.defaultValue>
<xp:this.converter>
<xp:convertNumber type="number" integerOnly="true" />
</xp:this.converter>
<xp:eventHandler event="onchange" submit="true" refreshMode="partial" refreshId="repeat1">
<xp:this.action><![CDATA[#{javascript:// get the universalID of the document
var keyCode = FColl.getDocument().getUniversalID();
// Create an Array
var myArray = sessionScope.get("myList");
//If it's not already in the Array then add it.
if (!myArray.contains(keyCode)) {
myArray.add(keyCode);
}}]]></xp:this.action>
</xp:eventHandler></xp:inputText>
<xp:span>
<xp:image url="/.ibmxspres/domino/oneuiv2/images/iconConfirmation16.png" id="image1">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:saveDocument var="document1" />
</xp:this.action>
</xp:eventHandler>
</xp:image>
</xp:span>
If anybody can give me any ideas to try, I would be very grateful.
Make it simple! There is a simple action "save". Comes in save and save all flavors. The later goes below the repeat and saves any changed document.

XPages Mobile Control Partial refresh returns to menu page

I have a simple page inside mobile controls. I have an edit box and what I want to happen is to a partial refresh of the current in the onChange event of the edit control. Basically type something in the edit control - hit enter and do the partial refresh.
What's happening is hitting enter if returning the page to the main menu. If I put a value in and hit TAB then it works as I would want.
I'm starting a new app from scratch. But I've done this concept many times with an app in production. I can't find anything special in the code that would "trap" an enter button... So I'm at a loss why I can't get the behavior I want this time around.
Here's a video demo of the problem:
http://traffic.libsyn.com/notesin9/SO-Question2-HB.mp4
Below is the full code.
Thanks for any help!!
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xe="http://www.ibm.com/xsp/coreex"
xmlns:xc="http://www.ibm.com/xsp/custom">
<xp:this.resources>
<xp:styleSheet href="/.ibmxspres/dojoroot/dijit/themes/tundra/tundra.css">
</xp:styleSheet>
<xp:styleSheet href="/mobile.css"></xp:styleSheet>
</xp:this.resources>
<xe:singlePageApp id="singlePageApp1"
selectedPageName="mainMenu">
<xe:djxmHeading id="djxmHeading1" label="My App"></xe:djxmHeading>
<xe:appPage id="mainMenuID" pageName="mainMenu">
<xe:djxmRoundRectList id="djxmRoundRectList1"
title="Main Menu">
<xe:djxmLineItem id="djxmLineItem9" moveTo="#container"
label="Test Page">
</xe:djxmLineItem>
</xe:djxmRoundRectList>
</xe:appPage>
<xe:appPage id="containerID" pageName="container"
resetContent="true">
<xe:djxmHeading id="djxmHeading5" label="My Page"
back="Main Menu">
</xe:djxmHeading>
<xe:djxmRoundRectList id="djxmRoundRectList2">
<xp:panel id="mainPanel">
<xp:table style="width:100.0%">
<xp:tr>
<xp:td style="width:50%"></xp:td>
<xp:td>Details</xp:td>
</xp:tr>
<xp:tr>
<xp:td>
<xp:inputText id="inputText1" styleClass="target alignVMiddle"
value="#{sessionScope.myValue}">
<xp:this.attrs>
<xp:attr name="autocorrect" value="off"></xp:attr>
<xp:attr name="placeholder" value="Tap to Scan...">
</xp:attr>
</xp:this.attrs>
<xp:eventHandler event="onchange" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:viewScope.put("test", "test");}]]></xp:this.action>
</xp:eventHandler>
</xp:inputText>
</xp:td>
<xp:td></xp:td>
</xp:tr>
</xp:table>
<xp:br></xp:br>
Current Value: 
<xp:text escape="true" id="computedField1" value="#{sessionScope.myValue}"></xp:text>
<xp:br></xp:br>
<xp:br></xp:br>
Current Time: 
<xp:text escape="true" id="computedField2" value="#{javascript:#Now();}">
<xp:this.converter>
<xp:convertDateTime type="time"></xp:convertDateTime>
</xp:this.converter>
</xp:text>
</xp:panel>
</xe:djxmRoundRectList>
</xe:appPage>
</xe:singlePageApp>
</xp:view>
Can you do something like this to force a partial refresh on Enter?
<xp:inputText id="inputText1" value="#{sessionScope.myValue}">
<xp:eventHandler event="onkeypress" submit="true" refreshMode="partial" refreshId="something">
<xp:this.script><![CDATA[//partial refresh on Enter
if( thisEvent.keyCode === dojo.keys.ENTER ){
dojo.stopEvent( thisEvent );
} else {
return false;
}
]]></xp:this.script>
</xp:eventHandler>
</xp:inputText>
I think the problem is that enter will try to do a submit and submit will return you to the first page. Try to add a check in onkeyup or down for charcode 13 and if this is found return false.
You might also need to do a stopproprigate or something like that.
Google for enter key submit form
From my mobile ;-)
Or perhaps this post. http://tinyurl.com/bsgy9g6

Resources