Add attachments to a xpage - xpages

I have a XPage with an data source attached to a notes document. On this XPage I have a button that calls method in a managed bean. This method retrieves a notes document from another notes database. This notes document has some attachements in a richtext field. These attachements shall be copied to my XPage.
Is there a way to achieve this?
I know how to retrieve the attachments from the notes document. But how can I attach them to my XPage?
For my task I can't use the File Upload control, because the "File Upload" should happend automaticly within my mananged bean.
I found something call AttachmentHolderValue that may fulfil my task, but unfortunately there is no documentation for this class.

Ok for the donwload display you could use code like this:
<xp:this.data>
<xp:dominoDocument var="yourNewDocument"></xp:dominoDocument>
</xp:this.data>
<xp:panel>
<xp:this.data>
<xp:dominoDocument ignoreRequestParam="true" var="download" action="openDocument"
databaseName="otherDatabase" documentId="calculated">
</xp:dominoDocument>
</xp:this.data>
<xp:fileDownload rows="30" id="fileDownload1"
displayLastModified="false" value="#{download.richTextItem}">
</xp:fileDownload>
</xp:panel>
This will add you Document from the other Database as a dominoDocument dataSource wich you can use to bind a <xp:fileDownload> to.
Then you could add something to select the Attachments what you want to copy to your new Document for that i would recoment a repeatcontrol and use it like:
<xp:repeat id="repeat1" rows="30"
value="#{javascript:download.getAttachmentList('richTextItem');}"
var="attachment">
<xp:panel>
<xp:label value="#{javascript:attachment.getName() }" id="label1"></xp:label>
<xp:br></xp:br></xp:panel></xp:repeat>
Insted of a label you could add a checkbox and in the onSave event you can run some code wich copys the selected elements to the new Document (have to look it up in my app).
You can copy them Using NotesDocument.copyAllItems() or saving the attachments to your server disk and add them with ritem.embedObject to your new's documents richTextItem. But i recomend doing the attachment copy in backend in my expirience working with attachments can be a very tricky part.

Related

How to define empty DataSource depending on param in URL in Xpage?

Design pattern in my Xpages application looks like below. When I in list view, I want to call dominoDocument1 for print and expect return null, because dominoDocument do not have key(documentId in url), but return UNID.I want this behavior for global custom control what can delete how in view mode and how in form mode. In form_toolbar component I what do something with dominoDocument and that`s why my dominoDocument define above another components.
<?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="dominoDocument1" formName="sample"
concurrencyMode="force" action="openDocument">
<xp:this.databaseName><![CDATA[#{javascript:var object1 = new SamplesDB();
object1.getDBPath();}]]></xp:this.databaseName>
</xp:dominoDocument>
</xp:this.data>
<xp:this.resources>
<xp:script src="/dbClass.jss" clientSide="false"></xp:script>
</xp:this.resources>
<xc:resources></xc:resources>
<xc:global_left_sidebar></xc:global_left_sidebar>
<xc:layout_content>
<xp:this.facets>
<xc:form_toolbar xp:key="sample_form"></xc:form_toolbar>
<xc:view_toolbar xp:key="sample_view"></xc:view_toolbar>
<xc:form_toolbar xp:key="sample_to_researches_table"></xc:form_toolbar>
</xp:this.facets>
</xc:layout_content>
<div class="container-fluid">
<div class="row">
<xc:layout_content>
<xp:this.facets>
<xc:sample_form xp:key="sample_form"></xc:sample_form>
<xc:sample_view xp:key="sample_view"></xc:sample_view>
<xc:cc_sample_to_researches_table
xp:key="sample_to_researches_table">
</xc:cc_sample_to_researches_table>
</xp:this.facets>
</xc:layout_content>
</div>
</div>
</xp:view>
w>
First, create the XPages application as a stand alone NSF for only one purpose, a web UI, and leave all the legacy Notes and new NSF data as data repositories for the UI.
-XPages UI NSF-
I think its best to create a 'Managed Bean' in faces-config, such as App.java and name it 'app'. Then create a DominoService.java that gets and sets data to the database NSF.
Design Java model objects, plain old Java objects that are in between the NSF and XPages UI. Reuse in other XPages projects.
On start, the server instantiates the Java objects in faces-config.
You also can can add Action Listeners to events that will do some work like get all documents from a view and return a ArrayList and that 'persons' is what is the in the 'value' property of a <xp:repeat /> or <xp:table /> component.
You will will want your XPages UI components to bind to Plain Java objects and lists for data.
The benefit you can always switch out the backend, for example, instead of writing and reading from a Key/Value pair NSF data store you can create a NoSQLHelper.java or SQLHelper.java and implement the same methods from the DominoService.java and the UI does not change.

Can I filter an Xpages search bar

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

Replace embedded views with multiple data sources

I am building an application that will have a parent documents with up to 5 different child documents attached to the parent. Each parent can have one and only 1 of each of the 5 types of child documents.
In traditional notes programming I would probably put an embedded view within the parent documents form. I was starting down that path when I wondered if this wouldn't be better done in Xpages with one Xpage that has multiple datasources.
A complicating factor is that each form/data source will have a different group of people who own it - only they can create or edit it. But I don't think this would be a problem.
Couple of ideas to consider ...
don't use response docs ... tie the related docs together via a document key like unid
put the create/edit function for the five child docs in their own separate panels ... childpanel1, childpanel2, etc.
add the datasources for the child docs in the respective panels ... childdoc1, childdoc2, etc
restrict edit access via the acl property for each panel
with multiple data sources on an XPage remember to set ignoreRequestParams="true" for the childdoc data sources
For example, here's the panel structure for the first child doc:
<xp:panel id="childpanel1">
<xp:this.data>
<xp:dominoDocument var="childdoc1" formName="ChildForm1"
ignoreRequestParams="true">
</xp:dominoDocument>
</xp:this.data>
<xp:this.acl>
<xp:acl>
<xp:this.entries>
<xp:aclEntry type="GROUP" name="doc1group" right="EDITOR">
</xp:aclEntry>
</xp:this.entries>
</xp:acl>
</xp:this.acl>
</xp:panel>
More on ignoreRequestParams:
In a two-page application involving a "view" XPage and a "document" XPage, when the application user clicks a link on the view page to open the document on the document page the ID for the document to open is passed with the REQUEST parameters. You can see this in the resulting URL for the document page which will have the ID for the document to open appended to the URL address, for example:
&documentId=49530CA58D17CCE5852575150069D857&action=openDocument
This works perfectly when the document page has only one Domino document data source. However, in the embedded view application the "document" XPage will also include a data source for the xp:viewPanel. When ignoreRequestParams is NOT true for the Domino view data source (and for any other additional data sources on the page, like childdoc1) then the parameters passed in the request ARE evaluated to determine which view entries to display in the xp:viewPasnel. These request parameters point to a UNID that is not the desired data source for the view so no view entries are displayed.
Note, you may not need to set ignoreRequestParams to true for ALL of the data sources on the XPage ... just be aware of this setting and what it does when things get wonky for one of the view or document data sources on the page.
Not sure if your question is how to limit the form creation or how to have something like an embedded view in xPages. Both are easier to do in xPages.
Basically you just need to make the children responses of the parent. I prefer to not use normal response documents and prefer instead to add a field called uid with the unid of the parent to the children. I then filter my datasource to match the uid of the parent document. You can use view controls for this but repeats look even better.
Its a great place to start using dialogs as you can have the second data source in the dialog and the user never needs to leave the page.
As far as restricting the view creation you can do something like hide the button to create a new child based on a criteria.
This action will add the unid of document1 to document3
<xp:modifyField name="uid"
value="#{javascript:document1.getDocument().getUniversalID()}" var="document3">
</xp:modifyField>
Here is the code I use for a repeat control datasource. The view is categorized by uid field
<xp:dominoView var="view7" viewName="VIEWNAME"
keys="#{javascript:document1.getDocument().getUniversalID()}">
</xp:dominoView>
Then the repeat control just grabs the fields you want.
<xp:table styleClass="table">
<xp:tr>
<xp:td>Column Header</xp:td>
<xp:td>Column Header</xp:td>
<xp:td>Column Header</xp:td>
</xp:tr>
<xp:repeat id="repeat3" rows="30" value="#{view7}"
var="rowData">
<xp:tr>
<xp:td>
<xp:text escape="true"
id="computedField3" value="#{rowData.columnname1}">
</xp:text>
</xp:td>
<xp:td>
<xp:text escape="true"
id="computedField4" value="#{rowData.columnname2}">
</xp:text>
</xp:td>
<xp:td>
<xp:text escape="true"
id="computedField5" value="#{rowData.columnname3}">
</xp:text>
</xp:td>
</xp:tr>
</xp:repeat>
</xp:table>
Ignore some of the styleclasses as I am using bootstrap.

Xpages: How to program a Drag and Drop a File Attachment in an Xpages to My Widgets

I have an Xpage that has instructions for users to get a widget into their Sidebar. I was going to send out the instructions in an email but I thought I should just embed it in an Xpage. Everything works, but I would like to have the file in the Xpage and have the users have the ability to drag and drop it right into My Widgets. I cannot see how to do this.
So far I have saved the file as a file resource. How can I connect that resource to a control in the Xpage?
Could I embed a view in the Xpage?
Or a Link?
<xp:fileDownload rows="30" id="fileDownload1"
displayLastModified="false">
</xp:fileDownload>
<xp:link escape="true" text="Link" id="link1"
target="_blank">
</xp:link>
</xp:td>
Just create a link to the file resource. Here's an example (assuming that your file resource is called widget.xml):
<xp:link escape="true" text="Link to widget" id="link1" value="/widget.xml"></xp:link>
The user should then be able to drag and drop that link to the My Widgets sidebar.

xe:dialog won't open in edit mode with view picklist OpenNTF control

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!

Resources