How can I refresh the field in CSJS - xpages

How to refresh one field in csjs? the code is here:
<xp:repeat id="repeat1" rows="30" var="currentDetail" indexVar="detailIndex" value="#{LeaveBean.details}">
<xp:inputText id="leavefrom" value="#{currentDetail.subfromtime}">
<xp:eventHandler event="onblur" submit="false" refreshMode="partial" refreshId="repeat1">
<xp:this.script><![CDATA[
XSP.partialRefreshPost('#{id:view:_id1:repeat1:0:leavefrom}');
var detailIndex = document.getElementById("#{id:detailIndexText}").innerHTML;
myRPC.checkfromdate(detailIndex).addCallback(function(returnAlert){alert(returnAlert);});
]]></xp:this.script>
</xp:eventHandler>
</xp:inputText>
</xp:repeat>
what I want to do is call ssjs from csjs as you can see, but the strange thing to me is the click thing didn't work immediately, for example, when I first open the page, and click the input field, and enter "1" in it, it should be popup alert just when i left the field, but nothing happend, then I click this field again, and enter "2", then I left the field, but I just got the alert "1" on the secreen...sorry for my poor expressions...
so my question is I should refresh the field just when I left the field immediately, but why the XSP.partialRefreshPost not working? I tried to refresh repeat1, not working either
update 2015/06/13:
At last, I found view.postScript....so....

One obvious problem is the partialRefreshPost id won't work. You're combining #{id:...} which runs server-side to calculate the corresponding client-side ID. But the ID that you're passing is a client-side ID for the first row of the repeat. Even if that corresponded to a server-side component, you're trying to hard-code every row to map to a field in row 1 of the repeat ("repeat1:0").
Is there a reason for not using a normal partial refresh and using view.postScript in your SSJS to post CSJS back to the browser? You're triggering a partial refresh posting data back anyway. I'm not sure what the final line of your code is doing, but it seems like it's calling another server-side request to add a response. So the code seems to do two calls to the server, to trigger an alert. I don't know the design and what that subsequent rpc call is doing, but if it can be achieved in a single partial refresh, that would seem better.

Related

xpages set value to field before action=newDocument

I have a simple button with the eventHandler:
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:openPage target="newDocument" name="/doc.xsp"></xp:openPage>
</xp:this.action>
</xp:eventHandler>
In lotusScript I would add a value to a field, before composing the form, using:
Call doc_new.ReplaceItemValue("txt_codformularmain","01")
....
....
Set uidoc = w.EditDocument ( True, doc_new )
I tried in the postNewDocument event of the doc.xsp
<xp:this.data>
<xp:dominoDocument var="Contr" formName="(fmFormularCIP)">
<xp:this.postNewDocument><![CDATA[#{javascript:Contr.replaceItemValue("txt_codformularmain", "01")}]]></xp:this.postNewDocument></xp:dominoDocument>
</xp:this.data>
I don't want every time the doc is created that value to be, let say, 01, BUT only when the doc. is composed by a specific button. Some other button will have the chance to add the 02 value for that field, and so on.
How can I achieve this in xpages development? Thanks for your time.
This is a little bit tricky in Web application development, because what you did in classical Notes development cannot be applied here. I had a lot of issues in this.
The classical scenario is that you have a Page X with some value (say txt_codformularmain will be 01). How do you decide this value "01"?
In some cases, this value is something you have in the page X. So you want to pass a specific value to the target page. One option could be using a query parameter (doc.xsp?myValue=01) and consume it on doc.xsp with param.myValue. Or, you might put a sessionScope variable before going to the target page and consume it by sessionScope.myValue.
It depends on what you need. Query parameter is somewhat safer, because the user might use the same button twice and sessionScope variable causes inconsistent behaviour. On the other hand, query parameter can be changed by the user, so you might have a breach in your application.
Some cases, you want to populate some values at the second page. Simple values (e.g. creation date, user names, etc.) can be populated with forms (i.e. compute value on load). Sometimes it would be more complicated (e.g. the department of the user where you have to lookup some views). For such cases, you need to use postNewDocument event at the target page.
After you have passed the value to the doc.xsp page, you will consume in the way you need. If it's not going to be edited on the page, you may again use postNewDocument event and set value by dataSourceName.replaceItemValue('itemName', param.myValue). If the value can be edited, you would use it as a default value on your field component.
One problem I have experienced: Once you set a value in postNewDocument, you may have problems to change it later, until the document data source saved. This is happening on specific cases. If you experience such a problem, you might use some editable field with readonly attribute. Just keep in mind :)

Session Expiration Warning

I have an XPages app that is supposed to save the main doc (and do a couple of other things) when the user clicks a button on the dialog box. The dialog box is presented by a CSJS function which runs according to a setInterval command. The dialog box and all the programming that present it are on a Custom Control. I have no problem displaying the dialog box, but have been unable to come up with a way to save the underlying document. I have other dialog boxes on their respective XPages, and saving the doc with a click (and some SSJS) works fine, but the same process doesn't seem to work if the dialog box is on a CC. I have searched all over the web, including StackOverflow, and haven't been able to find just what I need. Any ideas as to what I am missing?
Here's the code from one of my more recent attempts:
<xp:button value="Continue" id="button1">
<xp:eventHandler event="onclick" submit="false" id="eventHandler1">
<xp:this.script>
<![CDATA[
if (intvlID2) {
clearInterval(intvlID2);
}
var b18 = dojo.query('[id$="button18"]')[0];
if (b18) {
b18.click();
} else {
location.reload(true);
}
XSP.closeDialog('#{id:WarningDialog}');
]]>
</xp:this.script>
</xp:eventHandler>
</xp:button>
As you can see, it clears the interval first, then looks for a button on the underlying form. I've been able to verify that it does, in fact, find the button, but nothing happens with the click() command. The button it finds includes this save command that doesn't appear to execute:
document1.getDocument(true).save();
The button works perfectly when clicked by mouse or tapped by finger, but not when 'clicked' programmatically by another button on a CC.
The currentDocument global variable can be used to access the nearest dominoDocument datasource. Alternatively, the Extension Library dialog box has an additional parameter when closing the dialog box, the id of the refresh area. Maybe you can use that to trigger a save, something like setting a requestScope variable on close, and in the refresh area having code that does a save if the requestScope variable is set and, after save, clearing the requestScope variable?

XPages event code executing twice rather then once

Here’s what I want to do:
On an XPage I want to have an edit box control that calls some server-side code (Java bean or SSJS) when the user presses enter. The main use case for this is that this page will be run from an an iPad and a bluetooth barcode scanner is attached. This scanner emulates a keyboard. The user will tap into the edit box. They will then scan with the scanner and the barcode will be entered along with an “enter” key. The edit box needs to be immediately cleared for the next scan and the value of the scan needs to be processed. The processing will do various backend things to a java bean and then return a message to be displayed on the page. Basically one of these:
1. Item not found, 2. Item is available and assigned, 3. Item is already assigned but you can have it anyway 4. Item Unavailable
I have code for this and overall the core code is working fine. I’ve normally used the onchange event but since I had this problem I moved to the onkeypress event. That was as much an attempt to get it to run in IE. Again the goal is only for the iPad/Safari, but I’d love to get it working on desktop browsers as well. I’m currently testing only with Chome.
In the CSJS piece of the edit box I have this code:
var e = dojo.fixEvent(thisEvent);
if (e.keyCode == dojo.keys.ENTER) {
return true;
} else {
return false;
}
The thinking is that I only want to call the SSJS on Enter.
Here’s the SSJS code that clears the edit box, processes the value and then sets a couple viewScope variables.
// Get the value off the page and put it in to the key variable
var key:String = getComponent("scanBox").getValue();
// clear the scanbox so it's ready for the next scan.
getComponent("scanBox").setValue("");
//Managed Bean to hold the last scan value - since the scanbox is cleared we do want to show the value
Scan.setLastScan(key);
// Managed Bean to process the item.
AddToJob.processItem(key);
viewScope.put("vsShowAssignPanel", true);
viewScope.put("vsShowMessagePanel", false);
The SSJS code is set to partially update the main content of the page. I’m using bootstrap and am trying to refresh everything on the page except a top and bottom nav bar. The editbox itself IS in the partial refresh zone since I’m clearing the value after the scan.
Finally here’s the problem:
The SSJS code of the button is being run TWICE. Not all for some reason but maybe 90% of the time. I’m not clicking twice. The way I test is by using Chrome on my desktop and I paste a value into the field and press enter once on the keyboard.
If I’m trying to scan in and assign an Item with a barcode. It first runs fine. the it updates the objects and saves a field to the backend NotesDocument to mark it assigned. Just want I want. But the second run through hits and it’s deterring that the item is ALREADY assigned and giving me back the wrong message.
After a lot of trial and error I’m fairly certain that something in the JSF lifecycle is causing this to run twice. Why I have no idea. I have no idea how to get it once.
The only good workaround that I’ve found so far is in the “AddToJob.processItem” method. “AddToJob” is a managed bean in the viewScope. In there I store and keep the last barCode. Then I do a check to see of the value is the same. If so then I assume it’s on the second run and stop processing.
I’ve used this basic concept of calling code in the on change event of an edit control for years. But that was inside XPages Mobile Controls and sometimes things do behave a little differently in there. I’m trying to re-write this app to use Bootstrap rather then XPages Mobile controls.
Below is the full XML markup of the edit control if that helps.
<xp:inputText id="scanBox" styleClass="newTarget">
<xp:this.attrs>
<xp:attr name="placeholder" value="Tap to Scan..." />
<xp:attr name="autocorrect" value="off" />
</xp:this.attrs>
<xp:this.dojoAttributes>
<xp:dojoAttribute name="autocorrect" value="off" />
</xp:this.dojoAttributes>
<xp:eventHandler event="onkeypress" submit="true" refreshMode="partial" refreshId="mainPanel">
<xp:this.script><![CDATA[var e = dojo.fixEvent(thisEvent);
if (e.keyCode == dojo.keys.ENTER) {
return true;
} else {
return false;
}]]></xp:this.script>
<xp:this.action><![CDATA[#{javascript:// Get the value off the page and put it in to the key variable
var key:String = getComponent("scanBox").getValue();
// clear the scanbox so it's ready for the next scan.
getComponent("scanBox").setValue("");
//Managed Bean to hold the last scan value - since the scanbox is cleared we do want to show the value
Scan.setLastScan(key);
// Managed Bean to process the item.
AddToJob.processItem(key);
viewScope.put("vsShowAssignPanel", true);
viewScope.put("vsShowMessagePanel", false);}]]></xp:this.action>
</xp:eventHandler></xp:inputText>
ANY information is appreciated. Thank you very much!!!
The Enter key is a special one because pressing enter can also submit the form you are currently in. In this case you actually have two POST requests hitting the server, one for the partial request and then another when the form is submitted.
What you need to do it prevent the enter key from submitting the form using an event.preventDefaults() call. Here is the updated CSJS
var e = dojo.fixEvent(thisEvent);
if (e.keyCode == dojo.keys.ENTER) {
e.preventDefault();
return true;
} else {
return false;
}
Now the form won't get submitted but the partial refresh will fire correctly.
David,
Not really a specific XPages solution but I had to do this in the Notes client - where a barcode was scanned in - it was processed and then the field was cleared and the next one could then be scanned in. The operator was not at the client (its a bluetooth scanner).
My solution and I admit was a bit nasty was to use a NotesTimer - whereby the field contents were checked to see if it was empty or if it had the same value as previously. To make sure I didn't catch a partial scan I did the check twice and if the value did not change then I processed it.
So after all that - couldn't you use a Javascript timer and follow the same logic?
Please forgive me if I'm missing something here, but it seems to me you have set up an unnecessarily complex design.
Why is CSJS or SSJS even needed?
Meaning, have you tried just some simple markup and a bean to do the processing?
Example Markup:
<xp:panel
id="panelbarcode">
<xp:inputText
id="barcode1"
value="#{MyBean.barcode}">
<xp:eventHandler
event="onchange"
submit="true"
refreshMode="partial"
refreshId="panelbarcode" />
</xp:inputText>
</xp:panel>
Example Bean Code:
public class MyBean implements Serializable {
private static final long serialVersionUID = 8541L;
// Zero-Argument Constructor
public MyBean() {}
public String getBarcode() {
// give out a barcode here,
// or return "" for an empty barcode
return "";
}
public void setBarCode(String barcode) {
// process the scanned in barcode
}
}
(edited to get rid of stupid "onClick" event)

xpages how to force a partial refresh afterPageLoad

I asked this question a couple months ago, but there has been no response so I thought I would try again. I have a block of SSJS that manipulates a number of values. There are some computed fields that are impacted by these changes and they do not display correctly. I have a refresh button on the XPage and it does a partial refresh after which everything works fine. I need to somehow trigger a partial refresh on the a specific item (a panel in this case) as the last step in the afterPageLoad in the SSJS.
Any ideas?
Thanks
Refreshing Panels from SSJS without a button, link or something like that is a bit tricky.
But i think your problem is more located in the order in wich you are trying to compute your fields what about triggering your Code in a erlier event before those Fields are rendered, to avoid displaying the wrong values in the first place, maby post some example Code.
If you only want to refresh a the panel again after the page has bean loaded try this in the onClientLoad ClientEvent this could also fix it:
<xp:eventHandler event="onClientLoad" submit="false">
<xp:this.script><![CDATA[dojo.ready(function(){
XSP.partialRefreshGet('#{id:yourPanel}',{})
});]]></xp:this.script>
</xp:eventHandler>

Creating a response document via a button

I have two forms, Organisation and Contact. Contact is a response to Org, and each form has an XPage where the form can be filled in, saved etc. When opening edit_contact.xsp directly and creating a document (not as a response to an org), everything works fine.
On edit_org.xsp, I have a button with 2 events. The first copies some values into sessionScope so I can inherit them into the Contact. The second is a "Create Response Document" event which creates a new response with the parent ID being the current org document, and sends the user to edit_contact.xsp. Pressing the button changes XPage correctly and the field inheritance works fine, but pressing "Submit" on the Contact form doesn't save anything, and no document is created.
This exact same setup works 100% as desired in another database, I have no idea why it won't work properly here. Is there an obscure setting somewhere I am missing?
<xp:button value="Create Contact" id="button1" rendered="#{javascript:!document1.isEditable()}">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:actionGroup>
<xp:executeScript>
<xp:this.script>
<![CDATA[#{javascript:var doc = document1.getDocument();
sessionScope.PFirstName = doc.getFirstItem("P_Firstname").getValueString();
sessionScope.PSurname = doc.getFirstItem("P_Surname").getValueString();
sessionScope.PFamily = doc.getFirstItem("P_Family").getValueString();
sessionScope.PDOB = doc.getFirstItem("P_DOB")
sessionScope.PAGE = doc.getFirstItem("P_Age").getValueString();}]]
</xp:this.script>
</xp:executeScript>
<xp:createResponse name="/edit_contact.xsp" parentId="#{javascript:document1.getNoteID()}">
</xp:createResponse>
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
</xp:button>`
Here is a link that shows what I am trying to do (minus the field inheritance):
http://min.us/mKSJED8tT
Currently the forms and views all work, but the document created with the "Response" form appears not to be a response document - it has no $REF field. This setup works perfectly in a different database - what is going on?
It's hard to tell what might be happening without seeing any code. Since it works for you in another database, could it be an ACL issue? Where the user you're logging in as - possibly - anonymous - doesn't have the ability to create documents?
Instead of "push" approach go for "pull" - just open response page with url parameter of parent document. In its postNewDocument event initialize field values from it.
It would be useful to get an update on two key points made by others:
Is ignoreRequestParams set on your response document datasource? If not, regardless of what you're trying to define for the second datasource, it's UNID etc are pulled from the request parameters. So both datasources are effectively the same datasource.
Is it throwing a validation error? If so, nothing will be saved.
There are two possible issues:
First the use of getFirstItem("x") is not a best practice. So:
sessionScope.PDOB = doc.getFirstItem("P_DOB")
would be storing a NotesItem in the sessionScope which will not work. It is recommended to use:
sessionScope.PDOB = doc.getItemValueString("P_DOB");
Second the use of getNoteID() might not be returning what you want (Which is the UNID of the document). Use .getDocument().getUniversalID() instead.
<xp:createResponse
name="/edit_contact.xsp"
parentId="#{javascript:document1.getDocument().getUniversalID()}">
</xp:createResponse>
-edited-
/Newbs

Resources