xpages add a html file into a facets - xpages

I'm using some <xp:this.facets> elements in my xpages.
I already imported a html file into my resources. I want to display this html file using this facets, but I'm not having any success.
They are numerous layouts using in the Xpage as I want to display a correct arrangement.
For a custom control, I did use something like this:
<xc:layout>
<xp:this.facets>
<xc:view_all xp:key="facet_1"></xc:view_all>
</xp:this.facets>
</xc:layout>
How can I do the same thing for my test.html ?

This has been explained by Sven Hasselbach:
http://hasselba.ch/blog/?p=752
At the very basic level, you can dump contents of a file resource (from your Resources\Files inside the NSF database) into a computed text and place it as a facet.
<xc:layout>
<xp:this.facets>
<xp:text
escape="false"
xp:key="facet_1"
id="computedField1">
<xp:this.value><![CDATA[#{javascript:
var url = "/test.html";
var data = facesContext.getExternalContext().
getResourceAsStream( url );
var txt = "";
while( data.available() ){
txt += #Char(data.read());
}
txt}]]>
</xp:this.value>
</xp:text>
</xp:this.facets>
</xc:layout>
One quick note, during the JSF lifecycle, this code will run a number of times. So I recommend placing this into a SSJS lib and cache the contents once in a viewScope/applicationScope variable, depending on your case. Otherwise it will waste some memory and CPU during the loop.

Related

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.

Is it possible to generate viewColumn using repeat ? It doesnt work for me :-(

Is it possible to generate viewColumn dynamicly using repeat control,? I have a viewPanel and repeater that runs over all columns in this view and try to create viewColumn control for each as below. It doesnt throw any error for me but also no table apear on screen ... I would like to generate it dynamicly as I have many existing views with up to 20 columns so maintaining this manualy would be not so nice. I also need to use viewPanel because a first view column is categorized so I need the viewPanel mechanism for epanding/collapsing these categories.
<xp:viewPanel rows="30" id="viewPanelMain" var="row" value="#{viewDS}">
<xp:repeat id="repeat1" rows="100" value="#{javascript:myView.getColumns()}" disableOutputTag="true" var="column">
<xp:viewColumn>
<xp:this.columnName><![CDATA[#{javascript:column.getItemName()}]]></xp:this.columnName>
<xp:viewColumnHeader value="#{javascript:column.getTitle()}"></xp:viewColumnHeader>
</xp:viewColumn>
</xp:repeat>
</xp:viewPanel>
Mabe there is some better way how to achieve the same result ... Any idea?
Have a look at the Dynamic View Panel control from the Extension Library (included as part of the Domino 9 installation). The following should work using your example:
<xe:dynamicViewPanel value="#{viewDS}" id="dynamicViewPanel1" var="viewEntry">
</xe:dynamicViewPanel>
You can then consider customizing the look and fel using a customizer bean, you can add a pager, you can add an onColumnClick event etc.
My repeat works, inside a viewPanel
...to create numerous view columns.
Need to set "true" -- for repeatControls and removeRepeat

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.

How to get Image uploading for Rich Text control within a repeat control to 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.

Resources