setting database for xp:dominoDocument via properties file - xpages

I would like to set the location of a database for the xp:dominoDocument data Property via SSJS and a properties file:
<xp:this.data>
<xp:dominoDocument var="document1" action="openDocument"
formName="album - $f-album" computeWithForm="both"
concurrencyMode="force"
databaseName="#{javascript:datasource.getString('DB_FILEPATH')}">
<xp:this.documentId><![CDATA[#{javascript:context.getUrlParameter("UNID")}]]></xp:this.documentId>
</xp:dominoDocument>
</xp:this.data>
The datasource property contains e.g.
DB_FILEPATH=Bildr6Phase10Data.nsf
and is available via
<xp:this.resources>
<xp:bundle src="/datasource.properties" var="datasource"></xp:bundle>
</xp:this.resources>
The code above will cast the error:
com.ibm.xsp.exception.EvaluationExceptionEx: Error while executing JavaScript computed expression
Error while executing JavaScript computed expression
Script interpreter error, line=1, col=12: [ReferenceError] 'datasource' not found
However if I try:
<xp:text escape="true" id="computedField1"
value="#{javascript:datasource.getString('DB_FILEPATH')}">
</xp:text>
I get the value from the property.
What am I doing wrong?

Instead of a Computed Field, try logging datasource.getString('DB_FILEPATH') in beforePageLoad and beforeRenderResponse. Also log out a message in databaseName property. I would expect the databaseName property to be required when the component tree is first loaded. However, I would not be surprised if the resource string is loaded later.
An alternative may be to use xsp.properties file. There is code on how to retrieve a property from xsp.properties in XPages OpenLog Logger.

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.

Using design definition for computed properties

I cant find a solution for this problem. I am using design definitions for almost all my controls.
They are working fine the only problem i have is that if i am computing one of the properties i cant use the property anymore in the design definition. It will create a text in red and the xpages will prompt some error messages.
Is there a way to ask if the property is computed and show a standard text instead.
This is the design definition.
<?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:inputText type="text" value="<%=this.field_name %>"></xp:inputText>
</xp:view>
Whenever the value of the property field_name is computed in the custom control it brings up that error.
Anybody any ideas?
When I insert the Field custom control with a static text value for field_name, the design definition will display the field_name properly.
<xc:Field field_type="text" field_name="myfield_1"></xc:Field>
If I insert the Field custom control with a computed text value for field_name, it doesn't:
<xc:Field field_type="text"><xc:this.field_name><![CDATA[# {javascript:"myfield_"+#Text(1)}]]></xc:this.field_name>
</xc:Field>
Make sure field_name is the exact name of the property passed in as CompositeData. For example, I was able to reference the string property 'create' to create the image of field this way:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:inputText value="<%=this.create%>">
</xp:inputText>
</xp:view>
So, I suspect it's a typo, a missing property, or not a string.

Custom Property in Repeat control stopped working

I have a strange bug that is reproducible but i cant find out whats causing it.
If i call this xpage i get the following error message:
Error while executing JavaScript computed expression
'fieldname' not found
<?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.data>
<xp:dominoDocument var="Request"></xp:dominoDocument>
</xp:this.data>
<xp:repeat rows="999" var="fieldname">
<xp:this.value><![CDATA[#{javascript:"myfieldname"}]]></xp:this.value>
<xc:Widgets_Field
field_datasource="#{javascript:currentDocument}"
field_name="#{javascript:fieldname}">
</xc:Widgets_Field>
</xp:repeat>
I have tried to empty the cc but without any success. The only thing thats working is when i am either hardcoding the property field_name or when i set the repeat control to "create controls at page creation"
I am absolutely sure that code was working before but i cant find out whats causing the error message. Can you please give it a try and let me know if you also have the same problem.
Attached please see stack trace
com.ibm.xsp.exception.EvaluationExceptionEx: Error while executing JavaScript computed expression
com.ibm.xsp.binding.javascript.JavaScriptValueBinding.getValue(JavaScriptValueBinding.java:132)
com.ibm.xsp.page.compiled.ExpressionEvaluatorImpl.getBindingValue(ExpressionEvaluatorImpl.java:151)
xsp.Widgets_005fField$Widgets_005fFieldPage.createInputText4(Widgets_005fField.java:776)
xsp.Widgets_005fField$Widgets_005fFieldPage.createComponent(Widgets_005fField.java:142)
com.ibm.xsp.page.compiled.AbstractCompiledPage.buildComponent(AbstractCompiledPage.java:265)
com.ibm.xsp.page.compiled.CompiledComponentBuilder.buildChildren(CompiledComponentBuilder.java:115)
com.ibm.xsp.page.compiled.CompiledComponentBuilder.buildAll(CompiledComponentBuilder.java:84)
Within the custom control, if you use wrong binding that should be known at the page load, it throws such an error. For instance if your custom control contains a "loaded" attribute like:
<xp:text
loaded="${compositeData.field_name}">
That will throw such an error. That's why it works with "create controls at page creation" setting.
Update: If you are going to use dynamic binding within the custom control, see my answer at this question:
Dynamic Data Binding?

Add attachments to a xpage

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.

Dynamic binding within a repeat control

In a purchase order module, we need to ask certain questions depending on the source selection method, competition type and total cost of the PO. These questions are likely to change over time and in between different instances of the database.
So I have a view containing the questions, so that I can add questions dynamically to my XPage without needing to change the code. The answer to each question will be stored in a field. So, the document that contains the question has a field called FieldName that is used to supply the field name that will be used. Unfortunately, I am having no luck binding these dynamic fields to the document.
<xp:this.data>
<xp:dominoView var="competitionQuestionView"
viewName="CompetitionQuestions">
</xp:dominoView>
</xp:this.data>
<xp:repeat id="repeat2" rows="30" var="rowData" style="width:700px"
value="#{competitionQuestionView}">
<xp:label id="label1">
<xp:this.value><![CDATA[#{javascript:rowData.getColumnValue("Question");}]]></xp:this.value>
</xp:label>
<xp:inputText id="inputText1">
<xp:this.rendered><![CDATA[#{javascript:rowData.getColumnValue("FieldType") == "Text Box"; }]]></xp:this.rendered>
<xp:this.value><![CDATA[#{javascript:poDoc[rowData.getColumnValue ("FieldName")];}]]></xp:this.value>
</xp:inputText>
</xp:repeat>
I've tried various ways to do this, including making a dynamicInputText custom control to pass in the field name, but without luck. The closest I got was when I used this:
<xp:this.value>
<![CDATA[#{javascript:tmp = rowData.getColumnValue ("FieldName");'#{poDoc.'+tmp+'}';}]]>
</xp:this.value>
That gave me something like #{poDoc.justification}, which was what I wanted to pass to the 'binding', but it ended up displaying as the text value.
I did try using $ to compute the value on load, but I am guessing that it didn't work because my (and the rowData) view is not available on load. That would eventually present a problem when I wanted to use partial refreshes due to updates on the criteria for which fields I want to display anyway.
Some of the answers to other questions looked promising, but no code was provided, so I couldn't figure it out.
Behind the scenes, all data sources use the methods getValue and setValue to (respectively) read and write data. In the case of a Domino document data source, the expression #{currentDocument.fieldName} gets translated at runtime to either currentDocument.getValue('fieldName') or currentDocument.setValue('fieldName', postedValue), depending on whether the current operation is a read or a write.
If you set the value attribute of an otherwise editable component to a SSJS value binding, then it can't do this auto-translation... so it just treats every operation as a read.
In other words, for read/write to work, it has to be a "prefixless" expression.
There are several ways to handle this, but the easiest is to use a data context to map a SSJS expression to a single variable. Data contexts can be attached to the view root or to a panel, so in your example, you'd want to wrap your repeat contents in a panel:
<xp:repeat id="repeat2" rows="30" var="rowData" style="width:700px"
value="#{competitionQuestionView}">
<xp:panel>
<xp:this.dataContexts>
<xp:dataContext var="fieldName">
<xp:this.value><![CDATA[#{javascript:rowData.getColumnValue ("FieldName");}]]></xp:this.value>
</xp:dataContext>
</xp:this.dataContexts>
<xp:label id="label1">
<xp:this.value><![CDATA[#{javascript:rowData.getColumnValue("Question");}]]> </xp:this.value>
</xp:label>
<xp:inputText id="inputText1" value="#{poDoc[fieldName]}">
<xp:this.rendered><![CDATA[#{javascript:rowData.getColumnValue("FieldType") == "Text Box"; }]]></xp:this.rendered>
</xp:inputText>
</xp:panel>
</xp:repeat>
So for each member of the repeat, the variable fieldName becomes the column value for that row. Then in the value attribute of the input component, the array syntax is used (instead of the usual dot syntax) since we want to use a variable to specify the field name instead of hardcoding the name.
In theory, however, you should be able to skip the data context entirely, and just set the following to be the value expression for the field:
#{poDoc[rowData.FieldName]}
In the context of the default ("prefixless") EL resolver, rowData.FieldName should return precisely the same value that rowData.getColumnValue("FieldName") returns in the context of a SSJS expression.
Finally, I would recommend reading this Expression Language tutorial to become familiar with all of the things that you can do in core EL without resorting to SSJS.

Resources