Clicking on Navigator Entry hides my nodes - xpages

hen the xPage loads the render code works just fine. However, when the user clicks on Register for e-Statements they both get hidden until I refresh the page manually. I tried doing a full update and other parts of my code fail trying to access some java beans.
The code used for the render is a in my global javascript library.
Any thoughts?
<xe:navigator id="navigator1">
<xe:this.treeNodes>
<xe:basicContainerNode label="Register for e-Statements"
submitValue="RegisterForEstatements" enabled="true">
<xe:this.rendered><![CDATA[#{javascript:myEStatements.renderStatements()}]]>
</xe:this.rendered>
</xe:basicContainerNode>
<xe:basicLeafNode label="View My e-Statements" onClick="linkToEstatements();">
<xe:this.rendered><![CDATA[#{javascript:myEStatements.renderStatements()}]]>
</xe:this.rendered>
</xe:basicLeafNode>
</xe:this.treeNodes>
<xp:eventHandler event="onItemClick" submit="true"
refreshMode="partial" refreshId="navigator1">
<xp:this.action><![CDATA[#{javascript:
if( context.getSubmittedValue() == "RegisterForEstatements" )
{
sessionScope.put( "dialogAcceptEStatementTitle", "Accept e-Statements!" );
var dialogAcceptEstatements = getComponent( "dlgAcceptEStatements" );
dialogAcceptEstatements.show();
return "";
}
sessionScope.put( "dialogOopsTitle", "Oopps!" );
sessionScope.put( "dialogOopsMessage", "\nThis Feature Has Not Been Enabled Yet!" );
var dialogOops = getComponent( "dialogOops" );
dialogOops.show();
return "";
}]]>
</xp:this.action>
</xp:eventHandler>
}]]>
</xe:navigator>
Here is the additional code from the Javascript Library. FYI, the properProfile is a JavaBean that appears to be null when I click the navigator. I have defined the bean scope as request and tried session neither change the error.
var myEStatements =
{
// If the property receives Statements return true to display the e-Statement Links
// in the occ navigator
"renderStatements" : function()
{
var result = false;
try
{
result = aPropertyProfile.getStatementCoupon_1().equalsIgnoreCase( "Statement" );
} catch (e)
{
print(e.message);
}
return result;
},
// Fetch the e-Statement Accept Message
"getEStatementAcceptMessage" : function()
{
var eStatementAcceptMessage = "";
try
{
eStatementAcceptMessage = eStarService.getEStatementAcceptMessage();
} catch(e)
{
print( e.message );
}
return eStatementAcceptMessage;
}
}

Related

Primefaces CommandButton disable and enable

<p:commandButton id .......
onclick=”disableButton(this);”
onkeypress=”disableButton(this);”
oncomplete="enableButton('${bean.enableButton()}');"
private boolean enableButton(){
return false;
}
<script>
function disableButton(data) {
data.disable = true;
}
function enableButton(data) {
data.disable = data;
}
</script>
Observed both calls working in the debugger, but the button remains disabled
When disableButton is called data = button#MessageView j_idt183:….
When enableButton is called data = {url: “ ……….}
from the debugger
<p:commandButton id .......
onclick=”disableButton(this);”
onkeypress=”disableButton(this);”
oncomplete="enableButton();"
<script>
function disableButton(data) {
data.disable = true;
window.buttonPressed.disabled = data
}
// Save and use the initial "data" object
function enableButton() {
window.buttonPressed.disabled = false;
}

Xpages - JS code fails to execute when clicked via a button

I have a strange issue, where I have a simple javascript button, that call's 1 function to write some document history and replace the value of one field. It then does a partial update of a container div ID.
This button works fine when accessed via the UK, however when used by Swiss colleagues, the button is doing nothing.
I have in 1 instance, witnessed it not working for 1 user, only for it to suddenly work later in the day, so I'm stumped as to what the issue may be.
Button Code
<xp:button id="btnProceed" styleClass="btn btn-primary" value="Proceed">
<xp:this.disabled><![CDATA[#{javascript:try{
if (getComponent("chkConfirmed").getValue() == "false") {
return true;
} else {
return false;
}
}catch(e){
openLogBean.addError(e,this);
}
}]]></xp:this.disabled>
<xp:eventHandler event="onclick" submit="true" refreshMode="partial"
refreshId="contentWhiteBackground">
<xp:this.action><![CDATA[#{javascript:var dt = new Date();
var arrHistory:array = AddIndepConfirmationHistoryItem(currentDocument, dt, "Confirmed understanding of the opening guidance", userBean.displayName);
document1.replaceItemValue("showIntroduction", "2");
document1.save();
}]]></xp:this.action>
</xp:eventHandler></xp:button>
Called code
Sub AddIndepConfirmationHistoryItem(confdoc As NotesDocument, dt As Variant, action As String, usrname As String)
Dim hlist As StringList
If Len(confdoc.History(0)) = 0 Then
confdoc.History = IndepConfirmationHistoryItem(dt, action, usrname)
Else
Set hlist = New StringList(confdoc.History, "")
Call hlist.Append(IndepConfirmationHistoryItem(dt, action, usrname))
confdoc.History = hlist.Items
End If
End Sub
EDIT:
function AddIndepConfirmationHistoryItem(doc, dt, action, username){
var ArrDocHistory:array = doc.getItemValueArray("History");
var dateTimeFormat = new java.text.SimpleDateFormat("dd/MM/yyyy kk:mm");
var dateTimeString = dateTimeFormat.format(dt);
if(ArrDocHistory.length < 1){
// This should always return an object as it is created when an objectives document is first
// created but do this check to be safe and create an array if for some reason it doesnt exist
ArrDocHistory = [dateTimeString+"|"+action+"|"+username];
}else{
// append new value to the array
ArrDocHistory.push(dateTimeString+"|"+action+"|"+username);
}
doc.replaceItemValue("History",ArrDocHistory);
doc.replaceItemValue("LastUpdatedByName",username);
doc.replaceItemValue("LastUpdatedDate",dt);
//doc.Save();
}

Getting value via getComponent on compositeData

A check is made on a input field during save, if value exit then it should pass. The input field value exist as a compositeData, but the check keeps failing.
Whats the best way of validating or getting the value of the input field?
I have tried getting this value using the getComponent function.
<xp:inputText id="fieldname" value="#{compositeData.dataSource.fieldname}">
<xp:this.attrs>
<xp:attr name="placeHolder" value="type here"></xp:attr>
</xp:this.attrs>
<xp:eventHandler event="onchange" submit="true" refreshMode="partial" refreshId="inputTextContainer" execId="fieldname">
<xp:this.action><![CDATA[#{javascript:try {
var vVal = getComponent("fieldname").getValue();
viewScope.put("fieldNameScope", vVal);
print("vVal: " + vVal);
}catch(e) {
print("Fieldname error: " + e.toString());
}
}]]></xp:this.action>
</xp:eventHandler>
</xp:inputText>
//var field = getComponent("fieldname").getSubmittedValue(); //returns null.
var field = viewScope.fieldNameScope; //getComponent("fieldname").getValue(); //returns nothing.
if(field == "" || field == null){
vContinue = false;
viewScope.MessageType = "Error";
viewScope.MessageText = "Please field is empty";
return context.redirectToPage( "home.xsp" );
}else{
vContinue = true;
}
I was expecting the check to pass if value exist in the field, but the actual result is null.
I stored the value into a viewscope and then call the viewscope instead of using the getComponent. I will update my question with the onchange eventhandler.

XPages SSJS Action Group

I have an action group on click of a button. First action, does some validation, second action throws up a confirm (Do you want to save?) And if yes, the third action goes off and does some other stuff.
The issue I have, is if validation fails on the first action, I don't want the other 2 actions to run, so I should get no confirmation etc.
If validation fails, I've tried doing a break, and a return false, but neither seem to work. I'm sure I'm missing something obvious, and suffering from Monday syndrome, but I can't seem to work it out!
Event handler code below, thanks:
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action>
<xp:actionGroup>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:for (var i = 1; i < viewScope.rows+1; i++) {
print("Starting Array.....");
var fieldName:string = "ObjectiveSelfAssessment" +i;
var fieldName2:string = "ObjectiveDetails" +i;
print ("Field Name: " + fieldName);
var fieldValue = document1.getItemValueString(fieldName);
var fieldValue2 = document1.getItemValueString(fieldName2);
print ("Field Value: " + fieldValue);
if (fieldValue =="" || fieldValue==null){
print("Assessment Empty");
if(!fieldValue2 =="" || !fieldValue2 == null){
print("Objective Empty");
//Do validation
var o = {};
o.title = "Validation Failed";
o.body = "You must enter self assessment details for each objective";
o.alertIcon = "fa-thumbs-down fa-lg";
o.autoClose = true;
o.alertType = "danger";
requestScope.put("alertServer",o);
//requestScope.put("validated",false);
return false;
break;
}
}
}
}]]></xp:this.script>
</xp:executeScript>
<xp:confirm>
<xp:this.message><![CDATA[#{javascript:"Are you sure you want to submit your self assessment?"}]]></xp:this.message>
</xp:confirm>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:document1.replaceItemValue("rows",viewScope.rows);
//document1.replaceItemValue("status","Self Assessment Completed");
document1.save();
var o = {};
o.title = "Document Saved";
o.body = "This document has been succesfully submitted";
o.alertIcon = "fa-thumbs-up fa-lg";
o.autoClose = true;
o.alertType = "success";
requestScope.put("alertServer",o);
}]]></xp:this.script>
</xp:executeScript>
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
Update 1: Conditional code on action group:
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:actionGroup>
<xp:this.condition><![CDATA[#{javascript:for (var i = 1; i < viewScope.rows+1; i++) {
print("Starting Array.....");
var fieldName:string = "ObjectiveSelfAssessment" +i;
var fieldName2:string = "ObjectiveDetails" +i;
print ("Field Name: " + fieldName);
var fieldValue = document1.getItemValueString(fieldName);
var fieldValue2 = document1.getItemValueString(fieldName2);
print ("Field Value: " + fieldValue);
if (fieldValue =="" || fieldValue==null){
print("Assessment Empty");
if(!fieldValue2 =="" || !fieldValue2 == null){
print("Objective Empty");
var o = {};
o.title = "Validation Failed";
o.body = "You must enter self assessment details for each objective";
o.alertIcon = "fa-thumbs-down fa-lg";
o.autoClose = true;
o.alertType = "danger";
requestScope.put("alertServer",o);
print("FALSE");
return false;
break;
}else{
print("TRUE");
return true;
}
}
}
}]]></xp:this.condition>
<xp:confirm>
<xp:this.message><![CDATA[#{javascript:"Test11111"}]]></xp:this.message>
</xp:confirm>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:document1.replaceItemValue("rows",viewScope.rows);
//document1.replaceItemValue("status","Self Assessment Completed");
document1.save();
var o = {};
o.title = "Document Saved";
o.body = "This document has been succesfully submitted";
o.alertIcon = "fa-thumbs-up fa-lg";
o.autoClose = true;
o.alertType = "success";
requestScope.put("alertServer",o);}]]></xp:this.script>
</xp:executeScript>
</xp:actionGroup>
</xp:this.action></xp:eventHandler>
Paul, I've accepted your answer reg doing more manual coding as that's the approach I've taken. I'm submitting an answer so I can show my solution using code formatting....
I now do my validation client side - The reason for getting the children etc, is I create/remove fields dynamically which are shown with repeat controls for my text box's, so I do not know the element id's....
var objcolparent = document.getElementById("ObjColOuter").children[0];
var sacolparent = document.getElementById("SAColOuter").children[0];
var rows = sacolparent.getElementsByTagName("TEXTAREA").length;
for (var i = 0; i < rows; i++) {
var saValue = sacolparent.getElementsByTagName("TEXTAREA")[i].value;
if(saValue ==""){
var objValue = objcolparent.getElementsByTagName("TEXTAREA")[i].value;
if(!objValue==""){
// Validation failed, do client side bootalert
var o = {};
o.title = "Validation Failed";
o.body = "You must enter self assessment details for each objective";
o.alertIcon = "fa-thumbs-down fa-lg";
o.alertType = "danger";
bootAlert.show('alertServer',JSON.stringify(o))
return false;
break;
}
}
}
if(confirm("Are you sure you want to submit your self assessment?")){
return true;
}else{
return false;
}
If validation is successful, it then continues to run my server side stuff:
document1.replaceItemValue("rows",viewScope.rows);
document1.replaceItemValue("status","Self Assessment Completed");
document1.save();
var o = {}
o.title = "Document Saved";
o.body = "This document has been succesfully submitted";
o.alertIcon = "fa-thumbs-up fa-lg";
o.autoClose = true;
o.alertType = "success";
requestScope.put("alertServer",o)
Thanks to everyone who contributed!
Action groups are useful for basic, minimum-coding actions. But, as you're seeing, "easier" point-and-click, configuration-driven actions mean flexibility is harder. Manual coding may seem harder, but makes flexibility easier. If you put a confirm action on an XPage, preview it, and look at the source, it will tell you what function you need to use for manual coding. When I looked at the XSP class about seven years ago, I think the function used was XSP.confirm() equivalent to a basic JavaScript confirm() call. Using that may make your code more readable and make flexibility easier.
You can add a condition to your actionGroup. Here's a simple example:
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:actionGroup condition="#{javascript:myCondition()}">
xp:confirm>
<xp:this.message><![CDATA[#{javascript:"Are you sure you want to submit your self assessment?"}]]></xp:this.message>
</xp:confirm>
<xp:executeScript>
...
</xp:executeScript>
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
So in your case you just add your first action as a condition and have it return true or false depending on whether the logic in the action group must run or not.
There is a solution but it involves implementing a series of elements to properly support this scenario. But when it's up I believe it can be very helpful.
Your question is somewhat connected to a blog post of mine.
To help you in your specific case I will try to summarize here all the moving parts. Hope you like reading...
1st element: a server-side helper method
If you do validation outside of the validation phase there's no real way to let the client know something went wrong, or better there might be but it would be disconnected from an eventual flow you want to stay in (your case). What you want to do first, therefore, is to create a way to tell the client. First thing we build a static class with a simple helper method:
public enum Helper {
;
public static void setErrorHeader(HttpServletResponse response, PhaseId phaseId) {
response.setHeader("Application-Error", phaseId.toString());
}
}
We will later invoke this method to "flag" the validation as failed
2nd element: a client-side helper method
We need a JavaScript function that helps us tap into the response header we eventually add (add this function to your XPages through a JS library).
var helper = {
isBadRequest : function(xhr) {
return xhr.getResponseHeader("Application-Error") !== null;
}
}
3rd element: a beefed up event handler
To get things started in the proper way we must leverage the event handler parameters:
<xp:button id="myButton" value="Three-step action">
<xp:eventHandler
id="myEventHandlerId"
event="onclick"
submit="false"
action="#{myBean.makeItFlow}"
script="threeStep('validate', 'threeStepSave(arguments[1].xhr)')"/>
</xp:button>
It's very important for the eventHandler to have the attributes defined as written above:
id: used to grab the event handler later on
submit="false": doesn't submit the form, we will do it manually
action: contains the reference to the server side bean method that will be invoked. I used the name myBean.makeItFlow. I'm making the assumption you know how to use managed beans
script: where the "real" action takes place
At this point in the script attribute we call the XPages client-side javascript method that does the post - XSP.partialRefreshPost() - and we pass the various parameters manually. In this case I chose to avoid putting all the necessary script in-line with the event. At the bottom of the page you can add the following helper functions:
<xp:scriptBlock
value="
function threeStep(param, onCompleteFunc) {
var execId = '#{id:containerId}';
var refreshId = '#{id:containerId}';
var eventHandlerId = '#{id:myEventHandlerId}';
var opts = {
execId: execId,
params: { '$$xspsubmitid': eventHandlerId, action: param },
onError : 'console.log(arguments[0])'
};
if (onCompleteFunc) {
opts.onComplete = onCompleteFunc;
}
XSP.partialRefreshPost(refreshId, opts);
}
function threeStepSave(xhr) {
if (helper.isBadRequest(xhr)) {
return alert('Validation failed');
}
if (!confirm('Do you want to continue?')) return;
threeStep('save');
}" />
The method's first parameter is the id that will be refreshed. Then we have an object whose properties define:
param: a parameter we want to pass in order to tweak the server-side method behaviour
onCompleteFunc: the client side javascript that will be invoked at the end of the server side method evaluation (the js must be a string and will be evaluated)
var execId: the block (and therefore scope) that will be submitted with the POST
var refreshId: the block that will be refreshed
var eventHandlerId: the very important reference to the event handler ID
4th element: the bean action method
Now, by means of a Java bean we define all the action logic behind the button. I decided to go with 1 specific method that will react to the action parameter value passed by the event handler.
public void makeItFlow() {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
String action = (String) externalContext.getRequestParameterMap().get("action");
if ("validate".equals(action)) {
// Your logic
boolean failed = false;
// When validation fails add the error response header
if (failed) {
HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
Helper.setErrorHeader(response, PhaseId.INVOKE_APPLICATION);
}
} else if ("save".equals(action)) {
// Let's save this thing
}
}
I am adding a brief video of how it should behave (in the example I added some additional code to make the various phases obvious)
https://youtu.be/JayzcGex-rQ

XPages ApplicationLayout: get clicked value of selected drop down item in BannerLinks

I have a drop down I want to use to select the province the user wants to work in (yep, I'm in Canada!).
I'm having a hard time figuring out how to get the value that is clicked, as I want to put that value in a session scope variable.
The code for the drop down is built that way for now:
<xe:this.bannerUtilityLinks>
<xe:basicContainerNode
submitValue="provinceSwitch">
<xe:this.children>
<xe:basicLeafNode label="Québec"></xe:basicLeafNode>
<xe:basicLeafNode label="Ontario"
submitValue="Ontario">
</xe:basicLeafNode>
<xe:basicLeafNode label="Maritimes"
submitValue="Maritimes">
</xe:basicLeafNode>
<xe:basicLeafNode label="West"
submitValue="West">
</xe:basicLeafNode>
</xe:this.children>
<xe:this.label><![CDATA[#{javascript:if(!!sessionScope.province) {
sessionScope.province;
} else {
"Province";
}}]]></xe:this.label>
</xe:basicContainerNode>
<xe:basicLeafNode submitValue="langSwitch"
styleClass="lotusFirst">
<xe:this.label>
<![CDATA[#{javascript:if(!!sessionScope.lang) {
if(sessionScope.lang=="FR") {
return "English";
} else {
return "Français";
}
} else {
return "English";
}}]]>
</xe:this.label>
</xe:basicLeafNode>
<xe:this.bannerUtilityLinks>
I already have an eventHandler defined, used to select the language:
<xp:eventHandler event="onItemClick" submit="false"
refreshMode="partial" refreshId="PanelAll">
<xe:this.action><![CDATA[#{javascript:var submittedValue=context.getSubmittedValue();
if(submittedValue=="langSwitch") {
if(!!sessionScope.lang) {
if(sessionScope.lang=="FR") {
sessionScope.lang = "EN";
} else {
sessionScope.lang = "FR";
}
} else {
//since the default is FR, the first time it is clicked means we want to go to English
sessionScope.lang = "EN";
}
return;
}}]]>
</xe:this.action>
</xp:eventHandler>
How can I get the selected item value from the drop down and act upon it? I need to set a session scope variable and do a full (or partial) refresh.
Thanks :)
You have to add code to your onItemClick you already have since that one event does all the onclick events for the app layout.

Resources