xpages number converter with combobox in ND9 - xpages

I'm having trouble using number conversion with numberConvert in a combo box in xpages on a Domino 9 server. This used to work on the 8.5 server.
When I submit the values I get: Validation Error: Value is not valid
I also tried to populate the values with "new javax.faces.model.SelectItem" but that didn't make any difference.
Does anyone know how to use numbers in combo boxes in ND9?
Here is the source (I removed everything unneccesary for this example):
<xp:comboBox id="combo" value="#{viewScope.testfield}">
<xp:this.converter>
<xp:convertNumber type="number"></xp:convertNumber>
</xp:this.converter>
<xp:selectItem itemLabel="9" id="selectItem1" itemValue="9">
</xp:selectItem>
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:var arr=new Array("0","1","2"); return arr;}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox>
<xp:message id="message1" for="combo"></xp:message>
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action>
<xp:save></xp:save>
</xp:this.action>
</xp:eventHandler>
</xp:button>

Please ensure that field 'testField' is of type 'Number' on the underlying form.
I had the same issue on 8.5.3 server. So, i wrote the below code to overcome the issue..
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:
var arr = ['0','1','2']
var comboOptions = [];
for (i = 0; i < arr.length; i++){
comboOptions.push(new javax.faces.model.SelectItem(parseFloat(arr[i]), arr[i]))
}
return comboOptions}]]>
</xp:this.value>
</xp:selectItems>
You can simplify the above code, if you know how to use managed beans.
Below is the code for bean.
public class ApplicationSettings implements Serializable{
private static final long serialVersionUID = 1L;
private List comboOptions;
public ApplicationSettings(){
loadDefaults();
}
public void loadDefaults(){
for(int x = 0; x <= 3; x = x+1){
SelectItem item = new SelectItem(new Double(x),""+x);
comboOptions.add(item);
}
}
public List getComboOptions() {
return comboOptions;
}
public void setComboOptions(List comboOptions) {
this.comboOptions = comboOptions;
}
}
In faces-configxml, register the managed bean(name: ApplicationSettings, scope:application).
Then in your xpage..
<xp:selectItems value="#{ApplicationSettings.comboOptions}"></xp:selectItems>

EDIT:
If you want to select numbers in a ComboBox you have to define comboBox's possible values as an array of numbers, not strings.
<xp:this.beforePageLoad><![CDATA[#{javascript:viewScope.testfield = 1}]]></xp:this.beforePageLoad>
<xp:comboBox id="combo" value="#{testfield}">
<xp:selectItem itemLabel="0" itemValue="${javascript:0}"></xp:selectItem>
<xp:selectItem itemLabel="1" itemValue="${javascript:1}"></xp:selectItem>
<xp:selectItem itemLabel="2" itemValue="${javascript:2}"></xp:selectItem>
</xp:comboBox>
This example works perfect without using a converter if the value is a scope variable.
If you have a flexible number of entries you can use both ways shown in Adibabu Kancharla's answer.
The number converter is necessary for binding to a document's number field. The following example works for me in ND853 and ND9. I had to add integerOnly="true" though:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.data>
<xp:dominoDocument var="document1" formName="NumberTest"
action="editDocument"
documentId="477FF8697EE50EDBC1257B710073DDE3">
</xp:dominoDocument>
</xp:this.data>
<xp:comboBox id="combo" value="#{document1.Number}">
<xp:selectItem itemLabel="0" itemValue="${javascript:0}"></xp:selectItem>
<xp:selectItem itemLabel="1" itemValue="${javascript:1}"></xp:selectItem>
<xp:selectItem itemLabel="2" itemValue="${javascript:2}"></xp:selectItem>
<xp:this.converter>
<xp:convertNumber type="number" integerOnly="true"></xp:convertNumber>
</xp:this.converter>
</xp:comboBox>
<xp:message id="message1" for="combo"></xp:message>
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action>
<xp:save></xp:save>
</xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:view>

Related

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>

Change the state of a checkbox in the backend

In ssjs I try to change the state of a checkbox.
I tried :
doc.replaceItemValue( 'picWeb', "true" );
which doesn't seem to change anything (checkbox doesn't change to checked)
I also tried :
doc.replaceItemValue( 'picWeb', true );
which throws an error
( [TypeError] Exception occurred calling method NotesDocument.replaceItemValue(string, boolean) null)
If I understand it well : you can't change a checkbox (boolean) with replaceItemValue, but how do I change it then ?
Is it possible with ssjs or java or ...
Define in checkbox which string relates to checked value and which to unchecked value with the properties checkedValue and uncheckedValue:
<xp:checkBox
...
uncheckedValue="false"
checkedValue="true">
</xp:checkBox>
You can set the value then with
document1.replaceItemValue("picWeb", "true")
This is a complete example to demonstrate how to set a checkbox value in SSJS:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.data>
<xp:dominoDocument var="document1" formName="Test" />
</xp:this.data>
<xp:checkBox text="picWeb" id="checkBox1"
value="#{document1.picWeb}"
uncheckedValue="false"
checkedValue="true">
</xp:checkBox>
<xp:button value="True" id="button2">
<xp:eventHandler event="onclick" submit="false"
refreshMode="partial" refreshId="checkBox1">
<xp:this.action><![CDATA[#{javascript:
document1.replaceItemValue("picWeb", "true")
}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:button value="False" id="button3">
<xp:eventHandler event="onclick" submit="false"
refreshMode="partial" refreshId="checkBox1">
<xp:this.action><![CDATA[#{javascript:
document1.replaceItemValue("picWeb", "false")
}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:button value="Submit" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" immediate="false" save="true">
</xp:eventHandler>
</xp:button>
</xp:view>
The value is set in document as string

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.

dynamic combobox does not update it's binding scopevar when it's items get updated

I ran in some troubles with a combobox. Here is a copy/paste example code to demonstrate my problem.
<xp:this.beforeRenderResponse><![CDATA[#{javascript://
viewScope.value1 = "document.getItemValueString('value1')" + viewScope.document;
viewScope.value2 = "document.getItemValueString('value2')" + viewScope.document;}]]>
</xp:this.beforeRenderResponse>
<xp:button
value="change document"
id="button1">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript: viewScope.document = new Date().getMilliseconds()//}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<br></br>
<xp:comboBox id="comboBox1" value="#{viewScope.value3}">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:viewScope.value1;}]]></xp:this.value>
</xp:selectItems>
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:viewScope.value2;}]]></xp:this.value>
</xp:selectItems>
<xp:eventHandler
event="onchange" submit="true" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript://}]]></xp:this.action>
</xp:eventHandler>
</xp:comboBox>
<br></br>
<xp:text escape="true" id="computedField1" value="#{viewScope.value1}"></xp:text>
<br></br>
<xp:text escape="true" id="computedField2" value="#{viewScope.value2}"></xp:text>
<br></br>
<xp:text escape="true" id="computedField3" value="#{viewScope.value3}"> </xp:text>
What did I try to accomplish: I have a combobox with two or more calculated selectItems. They depend on which document is currently selected. To demonstrate a switch of documents I use the button change document in this example. When a new document is selected the beforeRenderResponse event
gets the itemvalues from the document and puts them in a viewscope var. I have to separate the two values so I can't use a Array for them. That's all working so far but: If I select a value e.g. value2(timestamp1) and do a switch document the viewScope.value3 where the combobox is bound to did not update.
It displays the old value2 from the last document until I trigger its onChange event.
How can I force the comboBox to update its viewScope var with its selectItems?
Found a solution wich works at least for my copy/pase example:
<xp:this.beforeRenderResponse><![CDATA[#{javascript://
viewScope.value1 = "document.getItemValueString('value1')" + viewScope.document;
viewScope.value2 = "document.getItemValueString('value2')" + viewScope.document;
var list = new Array();
list.push(value1);
list.push(value2);
if(!#IsMember(viewScope.value3,list)){
viewScope.value3 = list[0];//list.pop();
}}]]>
</xp:this.beforeRenderResponse>
Now the viewScope.value3 gets changed to value1 if the documents is changed.

XPages xe:listView won't hide the columns

I created a sample to demonstrate. I have a view called "testView" with three columns referencing "field1", "field2", "field3".
When I run this XPage all three columns in the display when it should not show the third column. Clicking the button does not hide the second column either.
Can anyone tell me what I have wrong?
<?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.beforePageLoad><![CDATA[#{javascript:if ( sessionScope.showCol2 == null )
sessionScope.showCol2 = true;}]]></xp:this.beforePageLoad>
<xe:restService id="restService1">
<xe:this.service>
<xe:viewJsonService viewName="testView"
defaultColumns="true">
</xe:viewJsonService>
</xe:this.service>
</xe:restService>
<xp:panel style="margin-left:20.0px;margin-top:20.0px">
<xe:listView id="listView1" storeComponentId="restService1">
<xe:listViewColumn id="listViewColumn1" columnName="field1"
columnTitle="Field1">
</xe:listViewColumn>
<xe:listViewColumn id="listViewColumn2" columnName="field2"
columnTitle="Field2">
<xe:this.rendered><![CDATA[#{javascript:return sessionScope.showCol2;
}]]></xe:this.rendered></xe:listViewColumn>
<xe:listViewColumn id="listViewColumn3" columnName="field3"
columnTitle="Field3" rendered="false">
</xe:listViewColumn>
</xe:listView></xp:panel>
<xp:panel style="margin-top:20.0px;margin-left:20.0px">
<xp:button id="button1" value="Toggle Column 2">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="listView1">
<xp:this.action><![CDATA[#{javascript:if ( sessionScope.showCol2 == false ) {
sessionScope.showCol2 = true;
}
else {
sessionScope.showCol2 = false;
}}]]></xp:this.action>
</xp:eventHandler></xp:button>
</xp:panel></xp:view>
Looks like a bug in ExtLib. But you can hide the column in your code with hidden* property:
<xp:button id="button1" value="Toggle Column 2">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="listView1">
<xp:this.action>
<![CDATA[#{javascript:
var cmp = getComponent('listViewColumn2');
if( cmp.isHidden() ){
cmp.setHidden(false);
}else{
cmp.setHidden(true);
}
}]]>
</xp:this.action>
</xp:eventHandler>
</xp:button>
*: the property is hidden too

Resources