Xpages: Cannot get OnClick event in Navigator to fire - xpages

I am trying to build a dynamic navigator for a document database. The navigator build correctly by using a repeat node (I got this from a post by Per) and I can put page or basic nodes in the repeat node and everything looks good, but I need to set a scope variable and then refresh the view element, and I cannot get that code to fire.
I have included the code for the navigator below. Any help would be greatly appreciated, I have scoured Stack Overflow and tried adding events manually all to no avail.
<?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:navigator
id="navigator1"
expandable="false">
<xe:this.treeNodes>
<xe:repeatTreeNode
var="navEntry"
indexVar="index"
loaded="true">
<xe:this.children>
<xe:pageTreeNode
rendered="true"
page="/xpViewAllDocs.xsp">
<xe:this.label><![CDATA[#{javascript:var dbName=#DbName();
var arr = #Unique(#Trim(#DbColumn(dbName,"alldocslookup",1)))
arr[index]}]]></xe:this.label>
</xe:pageTreeNode>
</xe:this.children>
<xe:this.value><![CDATA[#{javascript:var dbName=#DbName();
#Elements(#Unique(#Trim(#DbColumn(dbName,"alldocslookup",1))))}]]></xe:this.value>
</xe:repeatTreeNode>
</xe:this.treeNodes>
<xp:eventHandler
event="onItemClick"
submit="true"
refreshMode="complete">
<xe:this.action><![CDATA[#{javascript:viewScope.put("key","Test");
view.postScript("alert('Client Side JavaScript executed!')");}]]></xe:this.action>
</xp:eventHandler></xe:navigator>
</xp:view>
EDIT:
I tried all of the suggestions below but none of them worked.
I can get this to work by simply putting a link in the repeat or a computed field or something like that, but then it doesn't really look the navigation element at all. If I can just change the css some to make it look like the navigation I would be happy. I have taken a stab at it with a list container, but it is not working:
I feel like I am kind of close. What can I go to get this to look more like a navigator?
<?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:list
id="list1"
styleClass="lotusMenuHeader">
<xp:link
role="menuItem"
styleClass="lotusSelected"> All Documents</xp:link>
<xp:link>Tag 1</xp:link>
<xp:link>Tag 2</xp:link>
</xe:list>
<xp:panel>
<ul
header="lotusMenuHeader">
<li
class='lotusSelected'>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
</xp:panel>
</xp:view>

onItemClick doesn't seem to work with pageTreeNode. The event doesn't get rendered at all.
Use basicLeafNode instead. onItemClick does work with it well.
Put the current clicked value into sessionScope variable with context.getSubmittedValue().
Redirect to you target XPage with context.getSubmittedValue().
<xe:navigator
id="navigator1"
expandable="false">
<xe:this.treeNodes>
<xe:repeatTreeNode
var="navEntry">
<xe:this.children>
<xe:basicLeafNode
label="#{navEntry}"
submitValue="#{navEntry}" />
</xe:this.children>
<xe:this.value><![CDATA[#{javascript:var dbName=#DbName();
#Unique(#Trim(#DbColumn(dbName,"alldocslookup",1)))}]]></xe:this.value>
</xe:repeatTreeNode>
</xe:this.treeNodes>
<xp:eventHandler
event="onItemClick"
submit="true"
refreshMode="complete">
<xe:this.action><![CDATA[#{javascript:
sessionScope.key = context.getSubmittedValue();
context.redirectToPage("xpViewAllDocs.xsp")}]]></xe:this.action>
</xp:eventHandler>
</xe:navigator>

Related

Call XPages Dialog in typeAhead

is it possible to call a Dialog component in typeAhead functionality?
What i want to do is If the user enter a word which does not come up with typeAhead function then a dialog should appear on the screen.
Please find my code below (my dialog is in custom control)
Regards
Cumhur Ata
<?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:dialog id="dialogConfirmation">
<div class="modal-body">
<p>You have entered a word which is not in the list</p>
<p class="text-warning">Please add/or cancel<small> </small></p>
</div>
<xe:dialogButtonBar id="dialogButtonBar1">
<xp:button value="Hayır" id="btnConfirmYes">
<xp:eventHandler event="onclick" submit="false">
<xp:this.script><![CDATA[XSP.closeDialog('#{id:dialogConfirmation}')]]></xp:this.script>
</xp:eventHandler></xp:button>
<xp:button value="Evet" id="btnConfirmNo" styleClass="btn-primary">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:openNewFrm(sessionScope.extDbPath,sessionScope.expDbPage)}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xe:dialogButtonBar>
<xe:this.title><![CDATA[#{javascript:var c = "Warning";return c;}]]></xe:this.title></xe:dialog></xp:view>
You can hijack the result of the typeahead and call your dialog if it's empty by using this snippet:
https://openntf.org/XSnippets.nsf/snippet.xsp?id=typeahead-onstartoncomplete-event
I don't have Domino Designer at hand right now so I can't try this out. So this is just guessing:
I don't think that you can use the standard Edit Box control's type ahead feature for something like that; instead you could program this yourself using the control's "onkeyup" event, mimicking the standard type ahead. the idea is that a classic type-ahead operates as a filter to a list of possible entries, just like a "getElementsByKey" method that is fired upon each key stroke. So with every event you check what's in the Edit Box so far, compare it to your list, then display the filtered result to the user in a pop-up (you may want to use a dojo tooltip here).
If the result is null you can bring up your dialog instead.

Xpage: programmatically set custom control from session variable?

I am starting to get the dynamic nature of Xpages and am trying to make my coding more streamlined.
I am using the switchFacet cc in my xpages to control which custom control to load, depending on the value in a sessionScope variable.
To keep things simple I made the name of the cc match the sessionScope variable. So I ended up with the following code.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlnsstrong text:xc="http://www.ibm.com/xsp/custom"
xmlns:xe="http://www.ibm.com/xsp/coreex">
<xc:ccAppLayout>
<xp:this.facets>
<xc:ccAppNav xp:key="LeftColumn" />
<xe:switchFacet id="switchFacet1" xp:key="facet_1"
selectedFacet="#{javascript:return sessionScope.pageSelected}">
<xp:this.facets>
<xc:cpApp2Title1Page1 xp:key="cpApp2Title1Page1" />
<xc:cpApp2Title2Page1 xp:key="cpApp2Title2Page1" />
<xc:cpApp2Title2Page2 xp:key="cpApp2Title2Page2" />
<xc:cpApp2Title3Page1 xp:key="cpApp2Title3Page1" />
</xp:this.facets>
</xe:switchFacet>
</xp:this.facets>
</xc:ccAppLayout>
</xp:view>
Not to bad, but it seems to me things would be even cleaner if I could just directly set the cc to be the sessionScope variable. That way the code for this Xpage wouldn't have to change between different Xpages. I could get by with just one Xpage.
Is there a way to do this, and is it even a good idea?
Bryan
===============================================
What I am looking for is something like this:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlnsstrong text:xc="http://www.ibm.com/xsp/custom"
xmlns:xe="http://www.ibm.com/xsp/coreex">
<xc:ccAppLayout>
<xp:this.facets>
<xc:ccAppNav xp:key="LeftColumn" />
<xc:#{javascript:return sessionScope.pageSelected} xp:key="facet_1"></xc:#{javascript:return sessionScope.pageSelected}>
</xp:this.facets>
</xc:ccAppLayout>
</xp:view>
==============================================================
Knut,
That is a good suggestion, but as you indicated it only loads on page creation.
Is there a different way to do what I want, or is it just easier to leave the code as I originally had it?
<?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">
<xc:ccAppLayout>
<xp:this.facets>
<xc:ccAppNav xp:key="LeftColumn" />
<xp:include id="include1" xp:key="facet_1">
<xp:this.pageName><![CDATA[${javascript:sessionScope.pageSelected + ".xsp"}]]></xp:this.pageName>
</xp:include></xp:this.facets>
</xc:ccAppLayout>
</xp:view>
You can use <xp:include... and "calculate" custom control's name:
<xp:include pageName="${sessionScope.yourCC}" />
The sessionScope variable has to contain the name of your custom control like "cpApp2Title1Page1.xsp". Don't forget ".xsp" at the end.
Be aware that pageName gets calculated only once at first page load.
I know from your previous question that you'd like to keep the possible pages flexible in a sessionScope variable. Assuming you have a sessionScope variable pages which contains all custom control names as an array then you'd use a repeat and put the xp:include in it:
<xp:repeat
id="repeat1"
rows="30"
var="key"
repeatControls="true"
value="${sessionScope.pages}">
<xp:panel
rendered="#{javascript:sessionScope.pageSelected == key}">
<xp:include
pageName="${javascript:key + '.xsp'}" />
</xp:panel>
</xp:repeat>
It will include all pages defined in sessionScope variable pages but render only the one page with the name contained in sessionScope variable pageSelected.
You'd include the code above instead your switchFacet.
Could you create one custom control to rule them all? A CC that takes the name of the desired CC as a custom property, then renders only the one you want. So shove the switchFacet into a new custom control, e.g. ccAll.xsp:
<?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">
<xe:switchFacet id="switchFacet1" selectedFacet="#{javascript:return compositeData.ccName}">
<xp:this.facets>
<xc:cc1 xp:key="cc1" />
<xc:cc2 xp:key="cc2" />
<xc:cc3 xp:key="cc3" />
</xp:this.facets>
</xe:switchFacet>
</xp:view>
Add a custom property of ccName to the custom control using the "property definition" tab in the CC's properties.
Then add that to your XPage and pass in the sessionScope variable.
<xc:ccAll ccName="#{javascript:return sessionScope.pageSelected}"></xc:ccAll>
A while ago I have created a component to switch custom controls on-the-fly. The code is available at github:
https://github.com/hasselbach/domino-ccinjector
The component can inject custom components whenever you want: during a partial refresh or depending on a variable.

JQuery Script works with new document, but not with saved ones

Here is what I have :
Lotus database (8.5.3) with jQuery and jQueryUI included
form1 is a form with just one field.
It is set to
"On open - Automatically enable Edit mode"
"On Open - Display XPage instead : xpage1"
"On Web Access - Display XPage instead : xpage1"
xpage1 is an xpage. It contains :
An inputBox linked to the field in form1
A button that calls a small script, just alert("some text")
A jQuery script is included on the page. It's a draggable Panel. It's all there is to it. Just a panel that you can drag on the page.
view1 is a view displaying documents based on form1
Now my problem :
If launch the Xpage in my browser (Chrome or IE), it behaves normaly : I can see my alert when I click on the button, I can drag my panel on the page, I can fill my field, I can save the document.
When I open it later, however, the Xpage opens and display the field data, but my scripts don't work : impossible to save the document, move the panel, display the alert.
If I launch the Xpage in my Lotus client, it works !
If I remove my jQuery reference and my movable panel, the other scripts work.
Did I forget something ? Is it some kind of known problem?
Here is my Xpage source, for reference :
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<!-- THIS WHERE I MAKE JQUERY AVAILABLE -->
<script src="js/jquery-1.9.1.js"></script>
<script src="js/jquery-ui-1.10.3.custom.js"></script>
<!-- THIS IS MY DATA BINDING -->
<xp:this.data>
<xp:dominoDocument var="ds1" formName="form1"></xp:dominoDocument>
</xp:this.data>
<!-- THIS IS MY FIELD -->
<xp:br></xp:br>
Field1 : <xp:inputText id="field1" value="#{ds1.field1}"></xp:inputText>
<xp:br></xp:br><xp:br></xp:br>
<!-- THIS IS MY PROMPT BUTTON -->
<xp:button value="Alert" id="button2">
<xp:eventHandler event="onclick" submit="false">
<xp:this.script><![CDATA[alert("Waring!")]]></xp:this.script>
</xp:eventHandler>
</xp:button>
<xp:br></xp:br><xp:br></xp:br>
<!-- THIS IS MY MOVABLE PANEL -->
<xp:panel id="myPan01"
style="height:120px;width:120px;background-color:rgb(0,64,128)">
<xp:this.attrs>
<xp:attr name="class" value="dragItem"></xp:attr>
</xp:this.attrs>
<xp:div style="text-align:center">
<xp:span style="font-weight:bold;color:rgb(255,255,255)">
</xp:span>
</xp:div>
<xp:div style="text-align:center">
<xp:span style="font-weight:bold;color:rgb(255,255,255)">
Move Me!
</xp:span>
</xp:div>
</xp:panel>
<script>
XSP.addOnLoad(function(){ $(".dragItem").draggable({ grid: [
40,40 ]}); })
</script>
<xp:br></xp:br>
<!-- THIS IS MY SAVE BUTTON -->
<xp:button value="Save" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" immediate="false" save="true">
</xp:eventHandler>
<!-- THIS IS THE END... -->
</xp:button>
</xp:view>
You're including jquery via a standard HTML <script> tag, this may lead to problems since this will be placed in the HTML body instead of the header.
Use the XPage's resource's property. Add some client side JavaScript library with in the XPage ressources properties, then go to the source of the XPage, locate the xp tag that includes the JavaScript library and change it's URL so that your jquery resource is included.
I'm not 100% sure that this solves your problem, but since your code looks good otherwise it's worth a try.

Setting focus to first field of a tab on a tabbed table

When a user clicks on a tab of a tabbed table, I want to be able to set the focus tot the first field on that tab.
Each tab seems to only have one event mouse onclick. So I tried placing the following code in one of that tab's onclick events.
var f = dojo.byId('#{id:NotInvitedMsg}');
if (f != null)
f.focus();
But when I click on the tab nothing happens. And I mean nothing. The tab can no longer be selected and the script is never executed.
Any way around this?
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:tabbedPanel id="tabbedPanel1">
<xp:tabPanel label="New Tab" id="tabPanel1">
<xp:panel>
<xp:inputText id="inputText1"></xp:inputText>
<xp:eventHandler event="onClientLoad" submit="false">
<xp:this.script><![CDATA[var edit = dojo.byId("#{id:inputText1}");
if (edit) {
edit.focus()
}]]></xp:this.script>
</xp:eventHandler>
</xp:panel>
</xp:tabPanel>
<xp:tabPanel label="New Tab2" id="tabPanel2">
<xp:panel>
<xp:inputText id="inputText2"></xp:inputText>
<xp:eventHandler event="onClientLoad" submit="false">
<xp:this.script><![CDATA[var edit = dojo.byId("#{id:inputText2}");
if (edit) {
edit.focus()
}]]></xp:this.script>
</xp:eventHandler>
</xp:panel>
</xp:tabPanel>
</xp:tabbedPanel>
</xp:view>
This is working code (tested on Chrome and IE9). It uses simple trick I saw few days ago (and I want to apologize to original author, I couldn't manage to find the original post): to create onClientLoad event at XP/CC level, and to move event handler in source view into the panel body. Works like charm...
Try the HTML5 Autofocus attribute:
<xp:inputText id="field1" value="#{document.Field1}">
<xp:this.attrs>
<xp:attr name="autofocus" value="autofocus"></xp:attr>
</xp:this.attrs>
</xp:inputText>
One caveat: The autofocus attribute is supported in all major browsers, except Internet Explorer.
This might not be exactly what you´re looking for, but maybe it can be of some help..
Link -> How can I set focus to Edit Box inside repeat control?

Change an eventHandlers refreshMode depending on client side value?

I have a submit button on top that's normally doing a partial refresh of the form.
When I added a fileUpload control that won't due, as I need to do a full refresh. But I only wish this to happen if the user has added a file to be uploaded. So if the file Upload is empty I want to use a partialRefresh to submit.
I can check if a file is added easily enough and I could have two buttons with different refresh modes and hide them using JS, but that's a clunky solution.
What I would like to do is change the refresh mode on the submit button depending on a submitted value in the current form.
Any ideas?
Thanks!
/J
You can do this by adding a second event handler to your button: One event handler is for a full refresh, the other one for the partial refresh.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:div id="divRefresh">
<xp:label value="#{javascript:java.lang.System.currentTimeMillis()}" id="label1" />
<xp:label value="#{javascript:java.lang.System.currentTimeMillis()}" id="label2" />
</xp:div>
<xp:br></xp:br>
<xp:button value="Refresh" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.script>
<![CDATA[alert("Complete!"); return false;]]>
</xp:this.script>
</xp:eventHandler>
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="label2">
<xp:this.script>
<![CDATA[alert("Partial!");return true;]]>
</xp:this.script>
</xp:eventHandler>
</xp:button>
</xp:view>
The CSJS code in the events has to return false to stop the event.
I do this in http://www.intrapages.com when posting new stream content.
in the onchange event for the upload control I set a requestScope variable. and if that is set I perform a full refresh. works great

Resources