I read this post
is very similar to what I would like to ask. However, I tried to solve my problem using the solution from that post but not successful. I realize I cannot ask question in that post. So I would post here with my code. (please note, if it is not appropriate to create a new post, please remove it)
In the application, the user is able to search, when the user clicks a button, it will redirect the user the result page.
In the result page, there is a computed field and a view. The computed field is used to show message if there is no result in the view after search. If the result matches to user's criteria, the view will display the result.
The view works fine when the result matches to user's selection, but if no result matches to user's selection, it only displays the view column header. Therefore I would like to use a computed field to show a message to notify the user that the search function is performed and no result return. Otherwise, the user will not know their search has no result return.
Here is the code of the result page.
<?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:text escape="true" id="computedField1" style="margin-left:200.0px"> </xp:text>
<xp:br></xp:br>
<xp:viewPanel id="viewPanel4" viewStyle="width:600.0px;background- color:rgb(255,255,255);margin-left:200.0px" rows="15">
<xp:this.data>
<xp:dominoView var="view4"
viewName="OfficerDepLoc">
<xp:this.search><![CDATA[#{javascript:var qstring= "";
if ((sessionScope.officerSearch != null && sessionScope.officerSearch != "")|| (sessionScope.depSearch != null && sessionScope.depSearch != "")|| (sessionScope.locSearch != null && sessionScope.locSearch !=""))
{
qstring = " ( FIELD officer contains " + sessionScope.officerSearch + " & FIELD department contains" + sessionScope.depSearch + "& FIELD location contains" + sessionScope.locSearch + ")";
}
var db:NotesDatabase = session.getDatabase("", "myapplication.nsf", false)
var dc:NotesDocumentCollection = db.getAllDocuments();
if (dc.getCount() == 0)
{
qstring = getComponent("computedField1").setValue("After search, there is no record found");
}
return qstring;
}]]></xp:this.search>
</xp:dominoView>
</xp:this.data>
<xp:viewColumn columnName="Officer" id="viewColumn11">
<xp:viewColumnHeader value="officer " id="viewColumnHeader11" sortable="true">
</xp:viewColumnHeader>
</xp:viewColumn>
<xp:viewColumn columnName="Department" id="viewColumn12">
<xp:viewColumnHeader value="department" id="viewColumnHeader12" sortable="true">
</xp:viewColumnHeader>
</xp:viewColumn>
<xp:viewColumn columnName="Location" id="viewColumn13">
<xp:viewColumnHeader value="location" id="viewColumnHeader13" sortable="true">
</xp:viewColumnHeader>
</xp:viewColumn>
<xp:this.facets>
<xp:pager partialRefresh="true" layout="Previous Group Next" xp:key="footerPager" id="pager5">
</xp:pager>
</xp:this.facets></xp:viewPanel>
</xp:view>
When I test the page I notice the view does not trigger the computed field to show the message if the search has no result.
I also tried to put this code to the computed field to intend to show the message but it display nothing.
var db:NotesDatabase = session.getDatabase("", "myapplication.nsf", false)
var dc:NotesDocumentCollection = db.getAllDocuments();
if (dc.getCount() == 0)
{
qstring = getComponent("computedField1").setValue("After search, there is no record found");
}
So I would wonder to know how to display the message if the search has no result ? Thanks a lot.
May be something like this?
<xp:panel id="refreshPanel">
<xp:viewPanel id="viewPanel4" rendered="getComponent("viewPanel4").getRowCount()>0">
viewpanel columns
</xp:viewPanel>
<xp:panel id="noentriesPanel" rendered="getComponent("viewPanel4").getRowCount()==0">
text no entries
</xp:panel>
</xp:panel>
Related
I have a xpage that contains 4 edit boxes and a button, they are used to export the data in excel. I use session scope in those four edit boxes because I have store the value in order to generate the excel.
The design look looks like the following:
//1st edit box: get the user name, set it to default so the user does not need to type his/her name
<xp:inputText id="inputText1" value="#{sessionScope.User}">
<xp:this.defaultValue><![CDATA[#{javascript: #Name("[CN]",#UserName())}]]></xp:this.defaultValue>
</xp:inputText>
//2nd edit box: after get the user name in edit box 1, retrieve the user's department in this edit box
<xp:inputText id="inputText2"value="#{sessionScope.Department}">
<xp:this.defaultValue><![CDATA[#{javascript:#DbLookup(#DbName(),"UserView", (getComponent("inputText1").getValue()),2 )}]]></xp:this.defaultValue>
</xp:inputText>
//3rd edit box: get the start search date in YYYYMM format, user only can type numbers
<xp:inputText id="inputText3" value="#{sessionScope.startYYYYMM}">
<xp:eventHandler event="onkeypress" submit="false">
<xp:this.script><![CDATA[if (event.keyCode >= 48 && event.keyCode <= 57)
{
event.returnValue = true;
}
else
{
event.returnValue = false;
}]]></xp:this.script>
<xp:this.parameters>
<xp:parameter name="message1" value="value">
/xp:parameter>
</xp:this.parameters>
</xp:eventHandler>
</xp:inputText>
//4th editbox: get the endsearch date in YYYYMM format, user only can type numbers
<xp:inputText id="inputText4" value="#{sessionScope.startYYYYMM}">
<xp:eventHandler event="onkeypress" submit="false">
<xp:this.script><![CDATA[if (event.keyCode >= 48 && event.keyCode <= 57)
{
event.returnValue = true;
}
else
{
event.returnValue = false;
}]]></xp:this.script>
<xp:this.parameters>
<xp:parameter name="message1" value="value">
/xp:parameter>
</xp:this.parameters>
</xp:eventHandler>
</xp:inputText>
//a button to call another page to export the excel
<xp:button value="Export" id="button11">
<xp:eventHandler event="onclick" submit="true" immediate="false" save="false" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:context.redirectToPage("ExportExcel.xsp");}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
I run the code, it works fine. However here is what I would like to ask. In the first and the second edit box, if I set those edit boxes to Read-only. It seems lose the session scope variable and I run the code, the excel just contains the default header.
I find this post ReadOnly field in Xpage not submitted is very similar to my case, so I set the edit box to editable and try to apply this code from the post:
//for 1st editbox
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[function makeFieldReadOnly() {
document.getElementById("#{id:inputText1}").readOnly = true;
}
window.onload = makeFieldReadOnly;]]></xp:this.value>
</xp:scriptBlock>
//for 2nd edit box
<xp:scriptBlock id="scriptBlock2">
<xp:this.value><![CDATA[function makeFieldReadOnly() {
document.getElementById("#{id:inputText2}").readOnly = true;
}
window.onload = makeFieldReadOnly;]]></xp:this.value>
</xp:scriptBlock>
The edit box still editable and the excel is not work properly (only display the default header).
So how can I make the edit box read-only and still have the session scope variable?
Grateful for your advice please. Thank you.
Reference:
ReadOnly field in Xpage not submitted
export data from panel
You can calculate the values for your two sessionScope variables in e.g. the beforeRenderResponse:
<xp:this.beforeRenderResponse><![CDATA[#{javascript:
sessionScope.User = #Name("[CN]",#UserName());
sessionScope.Department = #DbLookup(#DbName(),"UserView", (#Name("[CN]",#UserName()),2 )
}]]></xp:this.beforeRenderResponse>
You can then show the values of the sessionScope variables in computed text fields instead of input fields:
<xp:text escape="true" id="computedField1" value="#{sessionScope.User}" />
<xp:text escape="true" id="computedField2" value="#{sessionScope.Department}" />
I had this issue with 9.01 FP6
The best solution was to place the inputs in a xp:panel and then use the readonly attribute on the panel to make the field within it read only.
This worked well and was easy to implement
I'm using Mark Hughes picklist on my xpage which is using a datasource. The view from which I pick the values is listing documents having another datasource.
I put the selected value into an <xp:inputText>. I do want to create a link which should redirect me to the listed document from the view ( from it I took the value ). In other words, I do want to find out the UNID of the document from the view, which I did selected it.
I tried the following code for the ssjsSelectFunction:
var unid = viewScope.unid;
if(typeof unid != "undefined" && unid != null)
{
var doc = database.getDocumentByUNID(unid);
var val1 = doc.getItemValueString("txt_numeAcord_1");
var val2 = doc.getUniversalID();
getComponent("inputText24").setValue(val1);
getComponent("inputText25").setValue(val2);
}
But after selecting the desired doc. from the picklist, only inputText25 is updated with the value ( UNID ), the inputText24 is empty. Only if I open again the picklist and select the doc., the inputText24 field value is added. I guess I'm missing something.
How can I achieve this?
My xpage code:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xc="http://www.ibm.com/xsp/custom"
xmlns:xe="http://www.ibm.com/xsp/coreex" >
<xp:this.data>
<xp:dominoDocument var="Contr" formName="(fmFormularCIP)"></xp:dominoDocument>
<xp:dominoView var="view1" viewName="vwAcord"></xp:dominoView>
</xp:this.data>
<xp:panel id="AcordCadru">
<xp:br></xp:br>
<xp:checkBox text="Acord cadru" id="checkBox6"checkedValue="Da" uncheckedValue="Nu" value="#{Contr.chkAcord}">
<xp:eventHandler event="onchange" submit="true"
refreshMode="partial" refreshId="AcordCadru">
</xp:eventHandler>
</xp:checkBox>
<xp:inputText id="inputText24" value="#{Contr.acord}">
</xp:inputText>
<xc:viewpicklist rowsPerPage="10"
buttonImage="./folder_explore.png" tableClass="tablecellgreen"
headerClass="headerclass" rowClass="odd, even" searchBar="false"
searchButtonText="Search" searchButtonClass="button2"
searchBarClass="headerclass" pagerStyleFirst="navbutton1"
pagerStylePrevious="navbutton2" pagerStyleCurrent="navbutton4"
pagerStyleNext="navbutton2" pagerStyleLast="navbutton3"
typeAheadBar="false" select="UNID" onReturn="Set Scope Value"
bottomBarClass="bottomround headerclass" cancelButtonText="Cancel"
cancelButtonClass="button2 floatthisright" type="Single Value"
finishButtonText="Finish" finishButtonClass="button2 floatthisright"
multiSelectButtonAddImg="./add.png"
multiSelectButtonRemoveImg="./delete.png"
picklistButtonClass="button" openDialogWith="Button"
picklistLinkImg="./add.png" multiSelectLinkAddImg="./add.png"
multiSelectLinkRemoveImg="./delete.png" selectWith="Button"
multiValueSeparator="," clearSearchImg="./cross.png"
SelectCellWidth="30px" dialogID="dialog1"
dialogTitle="Alegeti nr. acord cadru" fieldName="inputText24"
refreshID="AcordCadru" datasrc="view1" selectColumn="0"
varName="viewScope.unid">
<xc:this.viewColumn>
<xp:value>0</xp:value>
<xp:value>1</xp:value>
<xp:value>2</xp:value>
<xp:value>3</xp:value>
<xp:value>4</xp:value>
</xc:this.viewColumn>
<xc:this.ssjsSelectFunction><![CDATA[#{javascript:
var unid = viewScope.unid;
if(typeof unid != "undefined" && unid != null)
{
var doc = database.getDocumentByUNID(unid);
var val1 = doc.getItemValueString("txt_numeAcord_1");
var val2 = doc.getUniversalID();
Contr.setValue("acord",val1);
Contr.setValue("sv",val2);
}}]]></xc:this.ssjsSelectFunction>
</xc:viewpicklist>
<xp:br></xp:br>
<xp:inputText id="inputText25" value="#{Contr.sv}">
</xp:inputText>
</xp:panel>
</xp:view>
inputText24 doesn't get the selected value because the execution of ssjsSelectFunction's code is too late. It gets executed during the refresh of panel "AcordCadru" caused by parameter refreshID. All fields positioned in front of xc:viewpicklist get refreshed before ssjsSelectFunction's code execution. That's why inputText24 doesn't get the new selected value but inputText25 which comes after xc:viewpicklist does.
If you put inputText24 behind xc:viewpicklist then it will get the new selected value.
But, probably you want to have field inputText24 first and the picklist button xc:viewpicklist after. For this
delete the ssjsSelectFunction code
add a computed field in front of inputText24 with pretty the same code
<xp:text
escape="true"
id="computedField1">
<xp:this.value><![CDATA[#{javascript:
var unid = viewScope.unid;
if (unid && unid !== Contr.sv) {
var doc = database.getDocumentByUNID(unid);
var val1 = doc.getItemValueString("txt_numeAcord_1");
Contr.setValue("acord",val1);
Contr.setValue("sv",unid);
}
return "";
}]]></xp:this.value>
</xp:text>
It will set the new selected values to document and made them visible in inputText24 and inputText25 right away.
I'm using a repeat control displaying names. The content is displayed proberly, but I needed a pager because there can be more than 30 entries.
As soon as I add a pager for this repeat control and press a button doing a partial refresh on the site I get a "division by zero" error.
Here's my repeat control:
<xp:repeat id="repeat1" rows="30" var="namesList" repeatControls="true" indexVar="rowIndex">
<xp:table>
<xp:tr>
<xp:td>
<xp:link escape="true" id="Employee">
<xp:this.text><![CDATA[#{javascript:namesList.getItemValueString("Employee")}]]></xp:this.text></xp:link>
</xp:td>
</xp:tr>
</xp:table>
<xp:this.value><![CDATA[#{javascript:try {
var wfDoc:NotesDocument = docApplication.getDocument(true);
var dcNoAnswer:NotesDocumentCollection = database.createDocumentCollection();
var count:Integer = 0;
//Gets all response documents, but only adds those to the document collection, without a valid
//response to the cycle
if (wfDoc.getResponses() != null) {
var dc:NotesDocumentCollection = wfDoc.getResponses();
var doc:NotesDocument = dc.getFirstDocument();
while (doc != null) {
if (doc.getItemValueString("Response") == "") {
dcNoAnswer.addDocument(doc);
}
doc = dc.getNextDocument();
}
dc.recycle();
}
docApplication.replaceItemValue("MissingResponsesCount", dcNoAnswer.getCount());
wfDoc.recycle();
return dcNoAnswer;
} catch(e) {
dBar.error("Show no response repeat control data: " + e);
}}]]></xp:this.value>
</xp:repeat>
And here's my pager:
<xp:pager layout="Previous Group Next" id="pager3" for="repeat1"></xp:pager>
As I said, doing a partial refresh on the site oder panel, I'll get this error:
I've been looking for an error for some time, but I can't see anything wrong here. Did anybody else have such a problem and maybe has a solution?
You have repeatControls="true" set. That means "create the controls once and never again", so you can't use a pager to navigate, as mentioned here. Remove repeatControls="true" and it will work.
If you look at the stack trace, it will fail on getStart().
Try adding alwaysCalculateLast="false" to your pager. The repeat control could have 0 values (because of dcNoAnswer) and maybe you have set xsp.repeat.allowZeroRowsPerPage=true in your xsp properties settings.
When user1 sees view with xe:pagerAddRows which show last document in view, another user2 adds new document. user1 clicks xe:pagerAddRows and can't see new document.
How to show new documents for user1 in view using click xe:pagerAddRows without full update page?
How to show new documents for user1 created by user2 automatically without click and full update page?
<xe:dataView
id="dataView1"
openDocAsReadonly="true"
var="viewEntry"
expandedDetail="true"
style="margin-top:20.0px"
repeatControls="true"
rows="1">
<xp:this.facets>
<xp:panel
xp:key="detail">
<xp:text
escape="true"
style="font-family:Arial;margin-right:10.0px"
id="computedField1">
<xp:this.converter>
<xp:convertDateTime
type="date">
</xp:convertDateTime>
</xp:this.converter>
<xp:this.value><![CDATA[#{javascript:
var document : NotesDocument = viewEntry.getDocument();
return #Name('[CN]',document.getItemValue('Author'))
}]]></xp:this.value>
</xp:text>
</xp:panel>
<xe:pagerAddRows
xp:key="pagerBottomLeft"
partialExecute="true"
partialRefresh="true"
refreshPage="false"
id="pagerAddRows1"
for="dataViewUtterance"
state="true"
rowCount="1"
refreshId="ShowMoreUtterance"
disabledFormat="link">
</xe:pagerAddRows>
</xp:this.facets>
<xe:this.data>
<xp:dominoView
viewName="(Documents)"
var="viewData"
ignoreRequestParams="false"
categoryFilter="#{javascript:
currentDocument.getDocument().getItemValueString('Flow')}"
dataCache="id"
scope="view">
</xp:dominoView>
</xe:this.data>
</xe:dataView>
1.
You can refresh your dataView adding an onclick event to xe:pagerAddRows.
<xe:pagerAddRows
xp:key="pagerBottomLeft"
for="dataView1"
state="true"
rowCount="2">
<xp:eventHandler
event="onclick"
refreshMode="partial"
refreshId="dataView1">
</xp:eventHandler>
</xe:pagerAddRows>
This causes a refresh of your view and will show documents created by other users since last refresh.
2.
You can refresh your view with the help of a timer function on client side. setInterval() will execute a function every x seconds. The following example is executing a partial refresh of dataView1 every 5 seconds. Just add the code to your XPage.
<xp:scriptBlock
id="scriptBlockRefresh">
<xp:this.value>
<![CDATA[
setInterval(function() {
XSP.partialRefreshGet("#{id:dataView1}", {})
}, 5 * 1000)
]]>
</xp:this.value>
</xp:scriptBlock>
3.
It seems to me you'd like to show all view entries in real time and expand view automatically. If that's the case you could change the sort order so that newest documents would appear on top. This way and with the automatic refresh, you would always see the newest entries right on your first page.
I would like to refresh a Repeat Control triggered by client side Javascript. To make it interesting, my datasource is a JDBC query which is why I didn't just do a partial refresh.
I've seen pages about using an XHR request to do this, but I don't see how to refresh the JDBC data to capture the new info.
I can refresh the repeat control with the old data, not the new.
I saw Repeat control refresh error
which talks about possibly requiring a timeout because the runtime isn't aware of the new data.
I've run the XHR after manually changing something in the DB and waiting a minute, still had the stale info.
Can I update the variable (jdbcPendingSummary) in the RPC call, if not can I call back to the server to trigger the refresh inside the CSJS function?
<xp:this.data>
<xe:jdbcQuery connectionName="testDB"
sqlQuery="EXEC ptoGetPendingRequests #{sessionScope.userID}"
var="jdbcPendingSummary" />
</xp:this.data>
<xe:jsonRpcService id="ptoRPC" serviceName="ptoRPC">
<xe:this.methods>
<xe:remoteMethod name="createNewRequest">
<xe:this.script><![CDATA[
javaBeanObject.ptoCreateRequest(#{sessionScope.userID}, startDate, endDate, comment, d1,....,d15);
// Can I update the datasource var here?
]]></xe:this.script>
<xe:this.arguments>
<xe:remoteMethodArg name="startDate" type="string"></xe:remoteMethodArg>
..........
<xe:remoteMethodArg name="d15" type="number"></xe:remoteMethodArg>
</xe:this.arguments>
</xe:remoteMethod>
</xe:this.methods>
</xe:jsonRpcService>
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[
function createNewRequest(startDateID, endDateID, commentID, hiddenDivID, requestID) {
ptoRPC.createNewRequest(dojo.byId(startDateID).value, dojo.byId(endDateID).value, ........).addCallback( function(response) {
// ????? Refreshes the Repeat Control, but has the stale data.
setTimeout(
function() {
XSP.partialRefreshGet(requestID, {onComplete: function(responseData) { } })
// Or how about updating the datasource var here?
}, 8000);
});
}
]]></xp:this.value>
</xp:scriptBlock>
While this may not be a perfect solution, adding scope="request" to the JDBC code below caused the variable to be refreshed when the AJAX call completed.
<xp:this.data>
<xe:jdbcQuery connectionName="testDB"
sqlQuery="EXEC ptoGetPendingRequests #{sessionScope.userID}"
var="jdbcPendingSummary" scope="request" />
</xp:this.data>
You could achieve that using refresh() method of specific data source. So if you have a panel with some JDBC Query datasource configured - then inside inner view panel you could reference and refresh data via such syntax:
getComponent('some_panel_id_containing_your_datasource').getData().get(0).refresh();
While you could have multiple datasources configured for a panel - referencing to them is starting from 0 index.
Code snippet to demonstrate that technique could be like this (could make more sense if query would use some computed parameter to present different data on refresh):
<xp:panel id="outerContainer">
<xp:this.data>
<xe:jdbcQuery var="jdbcQuery1"
connectionName="derby1">
<xe:this.sqlQuery><![CDATA[#{javascript:"select * from users";
}]]></xe:this.sqlQuery>
</xe:jdbcQuery>
</xp:this.data>
<xp:viewPanel rows="10" id="viewPanel1"
value="#{jdbcQuery1}" indexVar="idx">
<xp:viewColumn id="viewColumn1" columnName="id"
displayAs="link">
<xp:this.facets>
<xp:viewColumnHeader xp:key="header"
id="viewColumnHeader1" value="ID">
</xp:viewColumnHeader>
</xp:this.facets>
<xp:eventHandler event="onclick"
submit="true" refreshMode="partial" refreshId="outerContainer">
<xp:this.action><![CDATA[#{javascript:
getComponent('outerContainer').getData().get(0).refresh();
}]]>
</xp:this.action>
</xp:eventHandler>
</xp:viewColumn>
</xp:viewPanel>
</xp:panel>