XPages - SSJS calling a bean - xpages

I am attempting to call some java code from an XPage and was attempting to do this via SSJS. Just trying to get even a basic hello world example working. Ideally the return from the java code could be stuffed into a variable.
Goal: (Xpage contents)
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:label value="#{javascript:helloWorld.anyoneThere}" id="label1"></xp:label>
</xp:view>
would print 'Yo!' when the page loads. Instead I get a Runtime Error that helloWorld is not found.
Created a package
package testBean;
public class helloWorld {
public String anyoneThere(){
return "Yo!";
}
}
Then I modified the faces-config file
<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
<managed-bean>
<managed-bean-name>helloWorld</managed-bean-name>
<managed-bean-class>testBean</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
</faces-config>
Not sure what I need to do to initialize / call the java function. Some examples I've seen are hooking into views or are on events but the intended code for what I'm doing would more likely be run in the beforePageLoad section.

Your managed-bean-class has you include the class name as well.
<managed-bean-class>testBean.helloWorld</managed-bean-class>
Also your label has to have parenthesis
<xp:label value="#{javascript:helloWorld.anyoneThere();}" id="label1"></xp:label>

I have written a small tutorial on the basics of creating and using a simple managed bean with XPages.
The tutorial also shows how to add getters and setters to your variables so that you can use EL to reference them. So in your example you will be able to do the following to reference the anyoneThere variable (assuming that you have set up a getter and setter for it):
<xp:label value="#{helloWorld.anyoneThere}" id="label1"></xp:label>

Related

How to define empty DataSource depending on param in URL in Xpage?

Design pattern in my Xpages application looks like below. When I in list view, I want to call dominoDocument1 for print and expect return null, because dominoDocument do not have key(documentId in url), but return UNID.I want this behavior for global custom control what can delete how in view mode and how in form mode. In form_toolbar component I what do something with dominoDocument and that`s why my dominoDocument define above another components.
<?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">
<xp:this.data>
<xp:dominoDocument var="dominoDocument1" formName="sample"
concurrencyMode="force" action="openDocument">
<xp:this.databaseName><![CDATA[#{javascript:var object1 = new SamplesDB();
object1.getDBPath();}]]></xp:this.databaseName>
</xp:dominoDocument>
</xp:this.data>
<xp:this.resources>
<xp:script src="/dbClass.jss" clientSide="false"></xp:script>
</xp:this.resources>
<xc:resources></xc:resources>
<xc:global_left_sidebar></xc:global_left_sidebar>
<xc:layout_content>
<xp:this.facets>
<xc:form_toolbar xp:key="sample_form"></xc:form_toolbar>
<xc:view_toolbar xp:key="sample_view"></xc:view_toolbar>
<xc:form_toolbar xp:key="sample_to_researches_table"></xc:form_toolbar>
</xp:this.facets>
</xc:layout_content>
<div class="container-fluid">
<div class="row">
<xc:layout_content>
<xp:this.facets>
<xc:sample_form xp:key="sample_form"></xc:sample_form>
<xc:sample_view xp:key="sample_view"></xc:sample_view>
<xc:cc_sample_to_researches_table
xp:key="sample_to_researches_table">
</xc:cc_sample_to_researches_table>
</xp:this.facets>
</xc:layout_content>
</div>
</div>
</xp:view>
w>
First, create the XPages application as a stand alone NSF for only one purpose, a web UI, and leave all the legacy Notes and new NSF data as data repositories for the UI.
-XPages UI NSF-
I think its best to create a 'Managed Bean' in faces-config, such as App.java and name it 'app'. Then create a DominoService.java that gets and sets data to the database NSF.
Design Java model objects, plain old Java objects that are in between the NSF and XPages UI. Reuse in other XPages projects.
On start, the server instantiates the Java objects in faces-config.
You also can can add Action Listeners to events that will do some work like get all documents from a view and return a ArrayList and that 'persons' is what is the in the 'value' property of a <xp:repeat /> or <xp:table /> component.
You will will want your XPages UI components to bind to Plain Java objects and lists for data.
The benefit you can always switch out the backend, for example, instead of writing and reading from a Key/Value pair NSF data store you can create a NoSQLHelper.java or SQLHelper.java and implement the same methods from the DominoService.java and the UI does not change.

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.

Using design definition for computed properties

I cant find a solution for this problem. I am using design definitions for almost all my controls.
They are working fine the only problem i have is that if i am computing one of the properties i cant use the property anymore in the design definition. It will create a text in red and the xpages will prompt some error messages.
Is there a way to ask if the property is computed and show a standard text instead.
This is the design definition.
<?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">
<xp:inputText type="text" value="<%=this.field_name %>"></xp:inputText>
</xp:view>
Whenever the value of the property field_name is computed in the custom control it brings up that error.
Anybody any ideas?
When I insert the Field custom control with a static text value for field_name, the design definition will display the field_name properly.
<xc:Field field_type="text" field_name="myfield_1"></xc:Field>
If I insert the Field custom control with a computed text value for field_name, it doesn't:
<xc:Field field_type="text"><xc:this.field_name><![CDATA[# {javascript:"myfield_"+#Text(1)}]]></xc:this.field_name>
</xc:Field>
Make sure field_name is the exact name of the property passed in as CompositeData. For example, I was able to reference the string property 'create' to create the image of field this way:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:inputText value="<%=this.create%>">
</xp:inputText>
</xp:view>
So, I suspect it's a typo, a missing property, or not a string.

Custom Property in Repeat control stopped working

I have a strange bug that is reproducible but i cant find out whats causing it.
If i call this xpage i get the following error message:
Error while executing JavaScript computed expression
'fieldname' not found
<?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"
xmlns:xc="http://www.ibm.com/xsp/custom">
<xp:this.data>
<xp:dominoDocument var="Request"></xp:dominoDocument>
</xp:this.data>
<xp:repeat rows="999" var="fieldname">
<xp:this.value><![CDATA[#{javascript:"myfieldname"}]]></xp:this.value>
<xc:Widgets_Field
field_datasource="#{javascript:currentDocument}"
field_name="#{javascript:fieldname}">
</xc:Widgets_Field>
</xp:repeat>
I have tried to empty the cc but without any success. The only thing thats working is when i am either hardcoding the property field_name or when i set the repeat control to "create controls at page creation"
I am absolutely sure that code was working before but i cant find out whats causing the error message. Can you please give it a try and let me know if you also have the same problem.
Attached please see stack trace
com.ibm.xsp.exception.EvaluationExceptionEx: Error while executing JavaScript computed expression
com.ibm.xsp.binding.javascript.JavaScriptValueBinding.getValue(JavaScriptValueBinding.java:132)
com.ibm.xsp.page.compiled.ExpressionEvaluatorImpl.getBindingValue(ExpressionEvaluatorImpl.java:151)
xsp.Widgets_005fField$Widgets_005fFieldPage.createInputText4(Widgets_005fField.java:776)
xsp.Widgets_005fField$Widgets_005fFieldPage.createComponent(Widgets_005fField.java:142)
com.ibm.xsp.page.compiled.AbstractCompiledPage.buildComponent(AbstractCompiledPage.java:265)
com.ibm.xsp.page.compiled.CompiledComponentBuilder.buildChildren(CompiledComponentBuilder.java:115)
com.ibm.xsp.page.compiled.CompiledComponentBuilder.buildAll(CompiledComponentBuilder.java:84)
Within the custom control, if you use wrong binding that should be known at the page load, it throws such an error. For instance if your custom control contains a "loaded" attribute like:
<xp:text
loaded="${compositeData.field_name}">
That will throw such an error. That's why it works with "create controls at page creation" setting.
Update: If you are going to use dynamic binding within the custom control, see my answer at this question:
Dynamic Data Binding?

Error in method binding

I want to pass SSJS code from a custom control via a method binding.
Here is the code behind the action button for this example:
<?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">
<xc:ccSSJS>
<xc:this.ssjsCode>
<![CDATA[#{javascript:
var app = facesContext.getApplication();
app.createMethodBinding("#{javascript:var control = getComponent('viewPanel1');print(typeof control);}", null);
}]]>
</xc:this.ssjsCode>
</xc:ccSSJS>
</xp:view>
But i get the Script interpreter error, why i can't call getComponent method?
It is a little bit complicated to explain why...
A workaround is to use the getComponentFor method of FacesUtil class:
com.ibm.xsp.util.FacesUtil.getComponentFor(view,'viewPanel1')

Resources