Why does this simple navigator code not add anything to the sessionScope var in the onItemClick event?
<xe:navigator id="navigator1">
<xe:this.treeNodes>
<xe:dominoViewListTreeNode filter="All.*" submitValue="#{javascript:return viewEntry.getName()}" var="viewEntry" href="page.xsp">
<xe:this.databaseName><![CDATA[#{javascript:database.getServer() + "!!" + "path//db.nsf"}]]></xe:this.databaseName>
</xe:dominoViewListTreeNode>
</xe:this.treeNodes>
<xp:eventHandler event="onItemClick" submit="true" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:sessionScope.clickedView = context.getSubmittedValue()}]]></xp:this.action>
</xp:eventHandler>
</xe:navigator>
The code is heavily inspired by XPages101 lesson 71: http://xpages101.net/xpages101/XPages101.nsf/0/4DB7580AC6931682802579A7004E74E7
As a workaround I am transferring the viewEntry.getName() as a parameter instead by using the following href:
<xe:this.href><![CDATA[#{javascript:"page.xsp?view="+viewEntry.getName();}]]></xe:this.href>
Per,
The href attribute in the xe:dominoViewListTreeNode causes the server side event not to be executed at all. When clicking a node it just performs a HTTP GET to the selected page (page.xsp). If you remove it and redirect the user in the serverside code your sample should work:
<xe:navigator id="navigator1">
<xe:this.treeNodes>
<xe:dominoViewListTreeNode filter="All.*" submitValue="#{javascript:return viewEntry.getName()}" var="viewEntry">
<xe:this.databaseName><![CDATA[#{javascript:database.getServer() + "!!" + "path//db.nsf"}]]></xe:this.databaseName>
</xe:dominoViewListTreeNode>
</xe:this.treeNodes>
<xp:eventHandler event="onItemClick" submit="true" refreshMode="complete">
<xp:this.action>
<![CDATA[#{javascript:sessionScope.clickedView = context.getSubmittedValue();
context.redirectToPage("page");}]]>
</xp:this.action>
</xp:eventHandler>
</xe:navigator>
Another tip: using Expression Language you could shorten the formula for the submitValue attribute to:
submitValue="#{viewEntry.name}"
Related
I have some code, that if a user selects a "NO" answer on a certain field (Q1), it removes the answers of sub question related to Q1, and also hides them in the UI.
This works fine, and I do a partial refresh on the div containing all the questions. However, when I then click on the same question selecting answer "Yes" which then shows all the sub questions, so the user can answer them again, they still have the old values attributed.
When I remove the fields, the backend document reflects this correctly, but then when I click the question which then shows the fields again in the UI, they appear in the backend document again, with their original value. If I do a context.reloadPage() at the end of my code, everything works as expected, but this breaks other functionality and I only want a partial refresh. Any ideas? Thanks
try{
if (compositeData.onClickCode) {
compositeData.onClickCode.invoke( facesContext, null );
}
document1.save();
var fieldName:string = compositeData.fieldName;
//Blank all IFM fields if user selects no IFM *CHANGE FIELDS ARRAY TO GET FROM KEYWORD*
if (fieldName == "Q1") {
print("Yes Q1");
if(document1.getItemValueString(fieldName)=="No") {
print("NO IFMS");
var questionsIFM = ["Q1a", "Q1b", "Q1c", "Q3IFM", "Q3bIFM", "Q3cIFM", "Q3dIFM", "Q4", "Q4a" ,"Q5IFM", "Q6IFM", "Q6aIFM", "Q7IFM",
"Q7aIFM", "Q7bIFM", "Q8", "Q8a", "Q9IFM", "Q9aIFM", "Q9bIFM", "Q10IFM", "Q11IFM"];
var len = questionsIFM.length;
for (i = 0; i < len; i++) {
print("Field Name: " + questionsIFM[i]);
document1.removeItem(questionsIFM[i]);
}
document1.save();
//context.reloadPage();
}
}
var guidanceOptions:string = "";
if (compositeData.guidanceOptions) {
if(#IsMember(document1.getItemValueString(fieldName), compositeData.guidanceOptions)){
guidanceOptions = document1.getItemValueString(fieldName);
}
}
viewScope.guidance = compositeData.fieldName+guidanceOptions;
}catch(e){
openLogBean.addError(e,this.getParent());
}
Instead of changing the backend document you could update the datasource with doc.setValue('fieldName','')
Alternativly, you could change the scope of the datasource to "request", this forces the datasource to reload the backend document for every request.
EDIT:
Here is an example for updating the datasource directly (Button 'Clear') which always works and updating the component (Button 'Update').
If the button 'Reload' is clicked, changes to in the fields are "stored" in the component. The button 'Update' does a partial refresh (which hides the input field), so the value is lost.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view
xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.data>
<xp:dominoDocument
var="document1"></xp:dominoDocument>
</xp:this.data>
<xp:div
id="refreshMe">
<xp:inputText
id="inputText1"
value="#{document1.foo}"></xp:inputText>
<xp:inputText
id="inputText2"
value="#{document1.bar}"
rendered="#{javascript:facesContext.isAjaxPartialRefresh() == false}">
</xp:inputText>
</xp:div>
<xp:button
value="Update"
id="buttonUpdate">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="partial"
refreshId="refreshMe">
</xp:eventHandler>
</xp:button>
<xp:button
value="Clear"
id="buttonClear">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="partial"
refreshId="refreshMe">
<xp:this.action><![CDATA[#{javascript:document1.setValue('foo', '');document1.setValue('bar', '')}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:button
value="Reload"
id="buttonReload">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete">
</xp:eventHandler>
</xp:button>
</xp:view>
I might be late to this party, but I found a way to force a reload from the back-end document. All you have to do is change the id for the dataSource a little, by adding or removing a "0" prefix to the documentId. Something like this:
return (viewScope.idPrefix? "0":"") + param.documentId
and when you want to force a reload during a partial refresh, just set
viewScope.idPrefix= !viewScope.idPrefix;
Don't forget to set ignoreRequestParams to true.
I want to be able to prompt the user for a comment and then be able to send this variable comment in an email. However, I'm unable to pass that variable from CSJS to SSJS. My document is in read mode.
Here is a sample button code where I can't seem to pass my comment.
Does anyone know how to do this?
Thanks in advance :)
<xp:panel readonly="false">
<xp:inputHidden id="inputHidden1" value="#{viewScope.tester}">
</xp:inputHidden>
</xp:panel>
<xp:button value="Reject" id="button7" style="margin-right:5.0px"
save="false">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:actionGroup>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:var doc:NotesDocument = currentDocument.getDocument();
doc.replaceItemValue("status", "0");
doc.save();
database.updateFTIndex(false);
var comment = viewScope.tester; /* HOW DO I GET COMMENT FROM CSJS TO HERE */
var ndoc = database.createDocument();
ndoc.appendItemValue("from", "tome#somewhere.com");
ndoc.appendItemValue("SendTo", "someone#somewhere.com);
ndoc.appendItemValue("subject", "My Subject");
var rti:NotesRichTextItem = ndoc.createRichTextItem("Body");
rti.appendText("Reason:" + comment + "\n\n");
ndoc.send()
}]]></xp:this.script>
</xp:executeScript>
<xp:openPage name="/mainpage.xsp"></xp:openPage>
</xp:actionGroup>
</xp:this.action>
<xp:this.script>
<xp:executeClientScript>
<xp:this.script><![CDATA[
var comment = XSP.prompt("Please enter a comment:");
XSP.getElementById("#{id:inputHidden1}").value = comment;
/*
XSP.partialRefreshGet("#{id:computedField1}",
{
params:{"para1":"1", "para2":"2"}
});
*/
]]></xp:this.script>
</xp:executeClientScript>
</xp:this.script>
</xp:eventHandler>
</xp:button>
XSP.prompt will use the default browser prompt window. You will have limited functionality from it and, in my opinion, not a great user experience. I would recommend having your reject button open an XPages Extension Library dialog with an Edit Box to enter the comment. Bind the Edit Box to a requestScope variable - you won't need the value after the dialog closes, so you would need it at a higher scope level. In the "OK" button of the dialog run your SSJS and use the SSJS hide() method of the Dialog component to close the dialog, adding a parameter for a component on the page if you need to partially refresh it.
Don't bind that field to your document (in read mode). Bind it to viewScope or requestScope variable.
Also, look here for inspiration.
To accomplish this in the past, I have used CSS to hide the input fields and buttons. The client-side script is defined separately from the button actions.
<xp:text escape="false"><xp:this.value><![CDATA[
<script>
function promptBox(){
// ... do whatever to get the data input into
// XSP.getElementById("#{id:inputText1}").value
// OR if using JQuery $('.tester).val()
// then click hidden Save button
$('.reject').click()
// OR
XSP.getElementById("#{id:button1}").click()
}
</script>
]]></xp:this.value></xp:text>
<!-- hide the input field with CSS -->
<xp:inputText
id="inputText1"
value="#{viewScope.tester}"
defaultValue="#{viewScope.tester}"
styleClass="tester hidden">
</xp:inputText>
<!-- hide the button with CSS -->
<xp:button
value="Reject"
styleClass="reject hidden"
id="button1">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:actionGroup>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:var doc:NotesDocument = currentDocument.getDocument();
doc.replaceItemValue("status", "0");
doc.save();
database.updateFTIndex(false);
var comment = viewScope.tester; /* scoped variable already set */
var ndoc = database.createDocument();
ndoc.appendItemValue("from", "tome#somewhere.com");
ndoc.appendItemValue("SendTo", "someone#somewhere.com);
ndoc.appendItemValue("subject", "My Subject");
var rti:NotesRichTextItem = ndoc.createRichTextItem("Body");
rti.appendText("Reason:" + comment + "\n\n");
ndoc.send()
}]]></xp:this.script>
</xp:executeScript>
<xp:openPage name="/mainpage.xsp"></xp:openPage>
</xp:actionGroup>
</xp:button>
<!-- use link for button - style it with CSS -->
Reject
I do not like having both client-side and server-side scripts bound to the same button, the execution order of the code is not easily managed. There are other ways to combine these client side fields and server side scripts, but this is a simple demonstration.
I visit this website to learn to use postscript in xpages. I follow the example to run the code and it runs property.
Then I begin to try other way. I use a computed field that use #DbLookup and a button that will use view.postScript to open xpage in a new window. When #DbLookup returns the value, that value will be the parameter in view.postScipt.
When I run the code, it returns error said Java method 'postScript(Array)' on java class 'com.ibm.xsp.component.UIViewRootEx2' not found
I get confuse about the error since it mentions it is java error and I don't have java code in the xpage.
I think the reason I get the error is the computed field returns more than one value.
However if I hard code values, it run fine
var myparam = "Test,Test2,Test3";
Or
var myparam = "Test"+"Test2"+"Test3";
Please find the code for your review please.(It includes the code that cause error, my attempts and the error message)
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:br></xp:br>
<xp:text escape="true" id="computedField1">
<xp:this.value><![CDATA[#{javascript:
//use #DbLookup to find value, that value will be the parameter in postScript
var value = #DbLookup(#DbName(), "myView", keyword, 3);
return value;
}]]></xp:this.value>
</xp:text>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:
var myparam = getComponent("computedField1").getValue();//does not work
//var myparam = "Test,Test2,Test3"; //works
//var myparam = "Test"+"Test2"+"Test3"; //works
//var myparam = "Test"; //(original) works
var myurl = #LeftBack(context.getUrl(),"/") + "/testpostscript.xsp?id="+myparam;
//error occurs in this code
//Java method 'postScript(Array)' on java class 'com.ibm.xsp.component.UIViewRootEx2' not found
view.postScript("window.open('" + myurl + "')");}]]></xp:this.action>
</xp:eventHandler></xp:button>
<xp:br></xp:br>
<xp:br></xp:br>
</xp:view>
I read this post and it seems different to my question.
When I search "postScript(Array) xpages" on the Internet, I don't find much information about it.
So my question is how to let view.postScript runs when the parameter contains multiple values?
Grateful for your advice please. Thank you.
You are right that the result of your #DbLookup returns more than one value (an array). That's why you see the underlying Java error that postScript(Array) is an unknown method. The postScript method expects a String as input.
I will suggest that you use #Implode() to join the result from the #DbLookup:
<xp:button value="Label" id="button1">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<![CDATA[#{javascript:
var myparam = #Implode(getComponent("computedField1").getValue(); ",")
var myurl = #LeftBack(context.getUrl(),"/") + "/testpostscript.xsp?id="+myparam;
view.postScript("window.open('" + myurl + "')");}]]>
</xp:this.action>
</xp:eventHandler>
</xp:button>
I would like to be able to add a user as a member into an excisting group (Newsletter).
With the code I have so far a new group is created with all the users and also the new member.
So , instead of inserting the user the code makes a new group (Newsletter) with the users.
<xp:this.data>
<xp:dominoDocument var="usergroup"
databaseName="contacts/webusers.nsf" formName="(46Group)"
action="editDocument" computeWithForm="onsave">
</xp:dominoDocument>
</xp:this.data>
<xp:br></xp:br>
<xp:inputText id="fullname" value="#{viewScope.fullname}"></xp:inputText>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:button value="Add new user" id="button1">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:actionGroup>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:var who = #DbLookup("contacts/webusers.nsf","($VIMGroups)","Newsletter",3);
var newone = getComponent("fullname").getValue();
who = who + ", "+newone;
usergroup.replaceItemValue("Members",who);
usergroup.replaceItemValue("ListName","Newsletter");
usergroup.save();}]]></xp:this.script>
</xp:executeScript>
<xp:openPage name="/login.xsp"></xp:openPage>
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
</xp:button>
EDIT
New code :
var ndb = session.getDatabase("","contacts/webusers.nsf")
var d = ndb.getView("($VIMGroups)").getDocumentByKey("Newsletter")
var newArr = new Array(d.getItemValue("Members"));
newArr =newArr + ", another user";
d.replaceItemValue("Members",newArr);
d.save(true,false);
As per suggestion of Thomas I changed my code.
The user is added to the members, but it is added x times. and x is the number of excisting members. I also tried to add the member with push, but this doesn't work. How can I add a member in the array in a proper way ?
The "usergroup" data source is not connected to the group document so the data source creates a new document when you load the page
You need to connect your data source to the group document, once you have that set you do not need to do the dblookup, you can just add the new user to the document data source field and save it.
You should be able to connect your data source doing something like this, (not tested)
var ndb = session.getDatabase("","contacts/webusers.nsf")
var d = ndb.getView("($VIMGroups)").getDocumentByKey("Newsletter")
return d.getUniversalID()
Here is some working code you can use in your button, I had to remove the data source as I was not allowed to save it due to security,
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:inputText id="inputText1"></xp:inputText>
<xp:button value="Add new user" id="button1">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:var ndb = sessionAsSignerWithFullAccess.getDatabase("server","names.nsf")
var d = ndb.getView("($VIMGroups)").getDocumentByKey("Newsletter")
var members = d.getItemValue("Members")
members.add(getComponent("inputText1").getValue())
d.replaceItemValue("Members",members)
d.save()}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:view>
I am writing a system for our forklift drivers in XPages. Basically our machines in production are going to get a iPod with a single big button on it. When they press the button I add a document to the Notes database (see code below). The forklife drivers have an iPad with a view that displays all the calls - they then select one call and drive to that machine. Once the machine operator has pressed the call button they can see some computed text saying that a forklift is command and another Cancel button.
I have it working (well, sort of) - but cannot seem to get the page in the "Single Page Application" to refresh.
This is the code that I have on a button - how do I now get the page to refresh - or how do I move to another page (in the "Single Page Application" using JavaScript) - sorry, I am just stumped!
Thanx for any help
Ursus
// setup date and time
var dt:NotesDateTime = session.createDateTime("Today 12");
dt.setNow();
// create a new document
var newDoc = database.createDocument();
// now set your fields
newDoc.replaceItemValue ("form", "fmRuf");
newDoc.replaceItemValue ("maschineName", sessionScope.displayName);
newDoc.replaceItemValue ("maschineNotesName", sessionScope.notesName);
newDoc.replaceItemValue ("maschineUm", dt);
newDoc.appendItemValue ("status", "20");
newDoc.computeWithForm(true, false);
// save the document
newDoc.save();
If you select the refresh mode to complete, the whole site should refreshed.
<xp:button value="label" id="button4">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript://SOME CODE}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
Or try this code
<xp:button value="Beschriftung" id="button4">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete" immediate="false" save="true">
<xp:this.action>
<xp:actionGroup>
<xp:actionGroup condition="#{javascript://someCode}"></xp:actionGroup>
<xp:openPage name="/YourXpages.xsp"></xp:openPage>
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
</xp:button>