Dynamic Table from Lotus Notes to XPages within a form - xpages

I am taking an existing Lotus Notes database and converting to Xpages. There is one of those tables containing 3 multi-value fields, with New Line as the seperator and the "Add New", "Modify" and "Delete" buttons controlling how the data is entered and removed. The customer would like the XPage to look as similar to the Notes GUI as possible, and I was thinking I would use the dijit dialog box to do the add new line and figure out the delete and modify. But from what I can tell, the dialog box can only be used on client-side and the data input into the dialog box can't be brought down onto the Xpage. Is this true? I was thinking I would use an editable field within a repeat, but I also couldn't that working properly.
Basically, it the solution has to show the multi-value fields for past documents and also be able to allow users to edit those older document...plus work similar/exactly the way as in the past when creating new docs.
Thanks in advance for any help I can get on this as it seems a ton easier than I am probably making it out to be.
I just wanted to update after the solution below, which appears to be an excellent way to solve this problem. However, as an admitted XPages novice, I am really struggling with the application of this concept. This is what I have, and it obviously isn't working.
Logically, this sounds like a great solution. However, I am no xpages expert and I simply can't get this working properly even to get started. Anything at all that would make this easier for me to even get started would be a big help. I'm not one to usually look for "the answer"...I'm just having difficulty getting a handle on this Multi-value field table issue. Thanks again in advance...here's what I wrote that is coming up with a 500 error. "A" is the multi-value field name.
<xp:table>
<xp:tr>
<xp:td>
<xp:repeat id="repeat1" rows="30" var="rowdata">
<xp:this.value><![CDATA[#{javascript:document1.getItemValue("A")}]]></xp:this.value>
<xp:tr id="valueRow">
<xp:td>
<xp:text
value="#{javascript: return rowdata[i]}" />
</xp:td>
<xp:eventHandler event="onclick" submit="false"
refreshMode="partial" execMode="partial" execId="valueRow"
immediate="true">
<xp:this.action>
<![CDATA[#{javascript:document1.getItemValue("A")}]]>
</xp:this.action>
</xp:eventHandler>
</xp:tr>
</xp:repeat>
</xp:td>
</xp:tr>
</xp:table>

I would say do the following
Create a repeat control which will extract the data from the multi value fields and print them read only. The repeat control will generate a tr structure with a event handler bound to it on the onclick event. something like this:
2 In the onclick event change the style of the tr clientside (using dojo) so people know they selected that row and set the id / identifier of that row in a scoped var
3 Above the repeat control add controls like add, remove, update. The add and update will open a dialog box and will read the data from the selected row ( or none if its a add action). The delete control will remove the data from the multiline value fields, save the document and refres the repeat control.
This should work.

Related

Xpages typeahead in dialog does not work unless onChange triggered first

UPDATED at bottom...
I have a custom control that contains an input field with typeAhead enabled:
<xp:inputText id="UTAN1" value="#{document1.UTAN}"
maxlength="5" styleClass="dbListFieldData" style="width:60px;font-size:13px;">
<xp:typeAhead mode="full" minChars="2">
<xp:this.valueList><![CDATA[#{javascript:var key = getComponent("UTAN1").getValue();
var path = new Array("","utans.nsf")
#Unique(#DbLookup(path,"(UTAN Lookup)",key,1,"[PARTIALMATCH]"));}]]></xp:this.valueList>
</xp:typeAhead>
<xp:eventHandler event="onchange" submit="true"
refreshMode="partial" refreshId="utanPanel1">
<xp:this.action>
<!-- DO SOME STUFF -->
</xp:this.action>
</xp:eventHandler>
</xp:inputText>
If I use the control inline on an xpage, typeAhead works fine.
However, if I insert the control in a dialog and call it to open:
<xp:link escape="true" id="link3" styleClass="dbListFieldData" >
<xp:eventHandler event="onclick" submit="false" id="eventHandler3">
<xp:this.script><![CDATA[XSP.openDialog('#{id:miniDialogUTAN1}');]]></xp:this.script>
</xp:eventHandler>
<xp:image id="image2" url="/edit2.png" style="height:16px;width:16px;" alt="Edit UTAN"></xp:image>
</xp:link>
The typeAhead seems to be partly crippled.
If the field is already empty, suggestions comes up fine.
If the field has an existing value, backspacing only shows the existing value as a suggestion.
Overwriting the value entirely gives no suggestions at all.
The only thing that will get the typeAhead working is to change the value and hit Enter. Basically, trigger an onChange. After that, ALL the typeAhead fields start working.
Any ideas on how to correct this behavior? FYI, I'm an xpages noob, so please go easy on me.
UPDATE 6/29/2021:
I'm still desperately in need of help with this. I've been playing around with Firebug and found something interesting.
In type-aheads on a normal Xpage form (where type-ahead works), entering each character calls a POST every time. However, when the type-ahead is in a dialog, typing in characters calls GETs. If I hit Enter or tab out of the field (triggering onChange), I get a single POST, and then clicking back into the field and typing, it starts using GETs again and it pulls valid suggestions as long as I don't backspace and type something different. Then the suggestions go away. This would be expected since GETs are cached and POSTs are not.
So what's going on with type-aheads in dialogs that makes them use GET, and how to I force it to use POST on every key press?
To people of the future...
After weeks of fretting over this and finally giving up I stumbled upon the solution by accident.
My dialog opens in read mode. I have both an Edit button and a Cancel button at top and bottom that were originally hard coded in both spots of the dialog custom control. Later I went to clean some stuff up and decided to create a single custom control for both sets of buttons. Once I did that, suddenly the type-aheads worked!
It turns out that when I copied and pasted the XML from the (supposedly) duplicate button panels to the new custom control, I had copied from the bottom button panel (which I rarely used while testing).
When I compared the XML for the top and bottom Edit Buttons, I found that the top one had the following attributes in the onClick:
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
while the bottom one had:
<xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="dialogOuterPanel1">
So, the full refresh broke my type-aheads and a partial refresh fixed them.

How can I prevent the autoupdate of a data source dominoview?

I have a repeat control with a dominoview as datasource, which shows main documents.
To each entry in the repeat the user can make comments, which are saved with reference to the doc/entry. When the user saved a comment, I use the universalID of the doc as reference. I get this unID from a column value of the underlying dominoview.
We are struggling with changes in the underlying view (new docs are created, deleted from other users). The xpage is - of course - still showing the situation of the page load, but when you do sth in the repeat (add comments), the rowindex is referencing to the backend view, not to the shown data in the xpage.
Maybe an example helps to make it clear:
User A opens the xpage, reads it (...?), then decides to make a comment to entry/doc No 3. Meanwhile User B has created another main doc (so that in the backend view, the position of the entry for user A has moved to row 4. Now when user A saves his comment, it is referenced to the former row 2 document.
Is there a way to prevent this lookup?
thx for any help, Uwe
Don't use the index.
Use underlying repeat row's document instead.
Define a variable in repeat e.g. var="row" and get the document with row.getDocument().
This way you can be sure that the correct document gets changed.
<xp:repeat
id="repeat1"
rows="30"
value="#{view1}"
var="row">
...
<xp:button
value="change document"
id="button1">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:
var doc = row.getDocument();
doc.replaceItemValue("comment", "my comment");
doc.save();
}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:repeat>

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

Partial update dynamic view on CustomControl | XPages

I have an application with one XPage. It has these custom controls(cc):
ccHeader
ccMenu
ccContent
ccFooter
Custom control ccContent has a combobox, with list of Views in sessionScope and dynamic view panel from extension library for XPages. This combobox has an event OnChange defined to partial update dynamic view.
What do I need?: Combobox with view list will be deleted and after that I need to assign this partial update function to five links, which are located on ccMenu custom control. So, i click on link in ccMenu, it returns some view name, assigns it to dynamic view and makes partial update.
How to get id of this dynamic view in ccMenu to call partial update?
Assuming what you mean is that you want to have a clean way to let the buttons know which area to partial-refresh when changed:
You could add a property to the ccMenu control along the lines of "viewRefreshId" and pass in the ID of the area to refresh, so you'd end up with a button like this:
<xp:button id="viewChanger1" value="View 1">
<xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="${compositeData.viewRefreshId}">
<xp:this.action><![CDATA[#{javascript: viewScope.selectedView = 'View 1' }]]></xp:this.action>
</xp:eventHandler>
</xp:button>
Now, there's a question of whether you should try to pass in an ID from something contained within another CC from the main XPage, and I try to avoid that - it would PROBABLY work, but it's a bit messy. I tend to architect similar things so that the part to be refreshed is directly on the XPage (which is to say, I don't use "content" custom controls), so I end up with something like this:
<xc:viewSelector viewRefreshId="dynamicViewContainer"/>
<xp:div id="dynamicViewContainer">
<xe:dynamicView>
<xe:this.data>
<xp:dominoView var="view1" viewName="#{viewScope.selectedView}"/>
</xe:this.data>
</xe:dynamicView>
</xp:div>
The extra container div comes from experience that I had a while ago where refreshing the dynamic view directly caused rendering problems, but I don't know if that's still the case (or if I had run into some other problem).

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

Resources