Refresh of cascading panels - xpages

Is have a problem with a refresh of the content on a cascading panel, that contains objects connected to the object of the primary panel? Primary panel has data source of "Invoice" (a managed bean) and the cascaded panel has the content of "Invoice.getAllInvoiceItems()" a List of objects (InvoiceItem).
Primary Panel (I'm loading the bean in beforePageLoad event, not in the primary panel):
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:on="http://www.openntf.org/domino/xsp"
xmlns:xc="http://www.ibm.com/xsp/custom"
xmlns:xe="http://www.ibm.com/xsp/coreex">
<xp:this.beforePageLoad><![CDATA[#{javascript:Invoice.pageInit();}]]>
</xp:this.beforePageLoad>
<xp:panel id="mainpanel" rendered="#{javascript:Invoice.getValid();}"
readonly="#{javascript:Invoice.readOnly;}">
Cascaded Panel:
<xp:panel id="RepeatInvoiceItems">
<xp:this.data>
<xe:objectData var="invoiceItem"
createObject="#{javascript:Invoice.getAllInvoiceItems()}">
</xe:objectData>
</xp:this.data>
I configured Invoice as managed bean in the Faces-config, but InvoiceItem not, because I don't think that's necessary...
<managed-bean>
<managed-bean-name>Invoice</managed-bean-name>
<managed-bean-scope>view</managed-bean-scope>
<managed-bean-class>com.kitc.controller.ControllerInvoice</managed-bean-class>
</managed-bean>
My problem is, when I create a new InvoiceItem the panel containing the InvoiceItems does not refresh, but the Panel containing the Invoice does (Proof method Invoice.getTotalPrice() returns the calculated value of all (including the new) InvoiceItems).

Why using an objectData, you can bind Invoice.getAllInvoiceItems() directly to a repeatControl
And bind a new invoiceItem to a property of your bean

Related

Xpages, faces-config, managed beans, and scoped variables

I have some properties in my database that will rarely if ever change, but are used pervasively throughout. It seems that this might be something I could do with a managed bean?
<managed-bean>
<managed-bean-name>bu</managed-bean-name>
<managed-bean-class> </managed-bean-class>
<managed-bean-scope>application</managed-bean-scope> </managed-bean>
I want to end up with a list of values in applicationScope.bu.
Do I just write a simple java implementation? Is there an easier or better way?
Your faces-config, to properly implement a managed bean, should include a block like you've put in, but you are missing the <managed-bean-class> value. This is what class will be created in memory (in your case, applicationScope). If your bean class has methods to return the values you're looking for, you're good. I'm a fan of beans (managed or POJO) and use this approach for a few applications.
[Edit]
As Steve points out in his answer, your need for accessibility, and quantity, of your configuration may drive how you store those values. How you interface with them may be different, and I lean heavily towards managed bean use.
For small amounts of values that need to be store for a given application, I like to set those in XSP Properties, then I can reference those via XSPContext.getProperty('xsp.property.name');.
For more complex things, I tend to create a config document, which I use as analogous to a profile document, which I then load from / store to the values.
[/Edit]
If you're looking for a good place to start with managed beans, or a quick reference for sanity checking, I'd recommend checking out Per Henrik Lausten's blog post on the subject.
The short version is, to have a managed bean, you must have:
a Java class
built with private properties (values)
which are exposed by public getter/setter methods
implements Serializable (java.io.Serializable)
contains an argument-less constructor (must take no parameters to be built the first time; not to mean that it can't go find values elsewhere)
an entry in faces-config (much like you've outlined)
binding via
EL with #{beanName.propertyName} (EL uses camel cased property names, converting, so the getter method of getPropertyName() is notated in EL as first shown
SSJS with #{javascript:return beanName.getPropertyName()} (full method invocation
You can then use your managed bean's name (in your case "bu") in either Expression Language or SSJS blocks. In the EL binding, note that the properties use camel casing to be accessed; so a property of myProperty is exposed by getMyProperty but looks like #{bu.myProperty}. You can also use it in SSJS, by the full method name, such as #{javascript:return bu.getMyProperty();}
Example
Here's one I have in my demo app is for a data object. It's in viewScope so it lives with the life cycle of a given XPage.
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
<managed-bean>
<managed-bean-name>gotHouse</managed-bean-name>
<managed-bean-scope>view</managed-bean-scope>
<managed-bean-class>com.westeros.model.HouseModel</managed-bean-class>
</managed-bean>
<!--AUTOGEN-START-BUILDER: Automatically generated by IBM Domino Designer. Do not modify.-->
<!--AUTOGEN-END-BUILDER: End of automatically generated section-->
</faces-config>
HouseModel.java
*I've modified this here for brevity as an example.
package com.westeros.model;
//...
public class HouseModel implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
//...
public HouseModel(){}
public void load(String unid){
// do some load things from the doc's UNID
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
//...
}
house.xsp (House XPage) *excerpted for brevity of example
<?xml version="1.0" encoding="UTF-8"?>
<xp:view
xmlns:xp="http://www.ibm.com/xsp/core">
<!-- truncating -->
<div
class="form-group">
<xp:label
for="name"
value="Name" />
<xp:inputText
id="name"
value="#{gotHouse.name}" />
</div>
<!-- truncating -->
</xp:view>
You can use managed properties of managed beans.
For example this little bean...
package ch.hasselba.xpages;
import java.io.Serializable;
#SuppressWarnings("serial")
public class MyBean implements Serializable {
private String dbName;
public void setDbName(String dbName) {
this.dbName = dbName;
}
public String getDbName() {
return dbName;
}
}
... can be initialized in the faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
<managed-bean>
<managed-bean-name>myBean</managed-bean-name>
<managed-bean-class>ch.hasselba.xpages.MyBean</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<managed-property>
<property-name>dbName</property-name>
<value>MyName</value>
<property-class>java.lang.String</property-class>
</managed-property>
</managed-bean>
</faces-config>
As soon you acccess the bean, the value is "there". F.e. a label on your XPage...
<xp:label
value="#{myBean.dbName}"
id="label1">
</xp:label>
... will be then displaying MyName.
Managed properties can contain other beans, and access runtime properties (f.e. request parameters) which makes them extremly powerful.
If I understand your question correctly, I don't think the properties of a managed bean would be where you would want to store application properties.
I would just stick them in application scope on the landing page of your application.

Xpages - Call bean method on click of a button

I have a form displayed in read mode using custom control which is bound to a view scoped bean. I need to have a picker on this CC so that users can select other documents. These display as links (generated using repeat control).
I planned to trigger a method in my view scoped bean to save this value when selection changes.
Now I am stuck with:
onChange event of multi-valued field (used with picker) does not trigger SSJS code
I tried creating a button which I clicked using CSJS on onChange of above field - this does not work either.
In short, SSJS code is not being triggered.
This is troubling me as I have a created a file download control wherein I have added a remove button calling a method in bean and it works just fine.
I am using Debugtoolbar by Mark Leusink and I am not able to display a simple message or set any scope variable. this is happening for onChange and onClick events!!
I have provided my CC code below. If you want you can put it in any Xpage bound to a view scoped bean.
<?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">
<xp:panel id="panel1">
<xp:inputTextarea id="inputTextarea1" style="display:none" value="#{viewScope[compositeData.pickerDetails.beanName][compositeData.pickerDetails.saveToField]}"
multipleSeparator=","
>
<xp:eventHandler event="onchange" submit="true" refreshMode="partial" refreshId="repeatLinks">
<xp:this.action><![CDATA[#{javascript://viewScope[compositeData.pickerDetails.beanName][compositeData.pickerDetails.saveToField]= getComponent("inputTextarea1").getValue();
//viewScope.get(compositeData.pickerDetails.beanName).setValue(compositeData.pickerDetails.saveToField,getComponent("inputTextarea1").getValue());
//viewScope[compositeData.pickerDetails.beanName].linkDocs(compositeData.pickerDetails.saveToField,getComponent("inputTextarea1").getValue());}]]></xp:this.action>
<xp:this.script><![CDATA[//console.log("Btn found : "+document.getElementById(getID("btnLinks")));
document.getElementById(getID("btnLinks")).click();]]></xp:this.script>
</xp:eventHandler>
</xp:inputTextarea>
<xe:valuePicker id="valuePicker1" listHeight="auto" listWidth="auto" dialogTitle="#{javascript:compositeData.pickerDetails.title}" for="inputTextarea1">
<xe:this.dataProvider>
<xe:simpleValuePicker labelSeparator="|">
<xe:this.valueList><![CDATA[#{javascript:var cd = compositeData.pickerDetails;
getPickerList(cd.viewName,cd.filter,cd.filterField);}]]></xe:this.valueList>
</xe:simpleValuePicker>
</xe:this.dataProvider>
</xe:valuePicker>
<xp:repeat id="repeatLinks" rows="30" var="docLink">
<xp:this.value><![CDATA[#{viewScope[compositeData.pickerDetails.beanName][compositeData.pickerDetails.saveToField]}]]></xp:this.value>
<xp:text escape="false" id="computedField1">
<!-- Link is generated here -->
</xp:text>
<xp:br></xp:br>
</xp:repeat>
<xp:button value="Click Me" id="btnLinks" refreshId="repeatLinks" refreshMode="partial">
<xp:this.onclick><![CDATA[#{javascript:viewScope[compositeData.pickerDetails.beanName].linkDocs(compositeData.pickerDetails.saveToField,getComponent("inputTextarea1").getValue());}]]></xp:this.onclick>
</xp:button>
</xp:panel>
</xp:view>
You mention this is a custom control. The most likely cause then is validation failure elsewhere on the page. Your button calls SSJS without execMode="partial" and an execId. This means the complete XPage is validated during the partial refresh. Your refreshId doesn't include an errors block, so there's nothing to alert the user (and you!) if there is a validation error.
Setting execMode="partial" and execId="panel1" on your button should resolve the problem.
If that's the case, for the future I would recommend adding a PhaseListener into your applications so you can easily output what phases are being triggered and/or always ensuring the refreshArea includes an errors control.
If you remove the style "display:none;" does the code then trigger?
There might be a validation failure that's taking place. What happens if you select "process data without validation" for these events?

JSF CommandButton action before submit

I've created JSF 1.1 page.
In the page I have 2 textboxes and commandbutton.
The textboxes are connected to object in the backing bean, and thw object's values are showed there, and the user can edit it as he wants, and when he clicks on the button I want to go to the bean and save the new values in the object.
The bean must be request, not session!
<h:inputText value="myBean.PersonName"><\h:inputText>
<h:commandButton action="myBean.saveEditName"><\h:inputText>
backingBean:
public String saveEditName(){
//Go to database and save the new object
}
The problem is, when I click on the button, the bean is refreshed, the objects returns to its previous values, and then the action is invoked.
Why is that? How can I perform an action before the submit refreshes the bean? (Without using servlet in javascript).
Thanks!
Use Explicit Bean Declarations as Given Below:
<managed-bean>
<managed-bean-name>someName</managed-bean-name>
<managed-bean-class>
somePackage.SomeClass
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

Passing t:savestate bean to another bean

I've two JSF 1.1 pages that I'm currently working with. One of them is viewDevices.jsp and the other is vewDevicesPrint.jsp. They are both running under the view scope (using tomahawk savestate, that is). In viewDevices, it has a img that user can click on to go to the viewDevicesPrint.jsp. Like so:
<img src="redesign/images/printicon2.png" alt="print records" border="0" width="16" height="16" onClick="javascript:window.open('/viewDevicesPrint.jsf','_blank','height=500,width=900,menubar=yes, toolbar=yes,scrollbars=yes')"/>
When this img is clicked, I would like to pass the current instance of viewDevicesBean to the viewDevicesPrintBean. Is there a way to do this?
I've the following in faces-config.xml. In debug, viewDevicesPrintBean is getting a new instance of viewDevicesBean, instead of the current instance of it.
<managed-bean>
<managed-bean-name>viewDevicesPrintBean</managed-bean-name>
<managed-bean-class>com.arch.myaccount.jsf.ViewDevicesPrintBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>param_viewDevicesBean</property-name>
<value>#{viewDevicesBean}</value>
</managed-property>
</managed-bean>
<managed-bean>
<managed-bean-name>viewDevicesBean</managed-bean-name>
<managed-bean-class>com.arch.myaccount.jsf.ViewDevicesBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>param_flow</property-name>
<value>#{param.Flow}</value>
</managed-property>
</managed-bean>
A view scoped bean is tied to the current view. When you change the current view by navigating to a different view, then that different view would get a brand new instance of the view scoped bean. Note that it works also that way in JSF2.
Your best bet is to pass the desired data as request parameters in window.open() URL (escape them!), so that the print bean can get them as request parameters (via either managed property or ExternalContext). An alternative, especially if you've rather a lot of data, is to store the bean instance in the session scope under an unique and autogenerated key (e.g. java.util.UUID) and pass that key as request parameter so that the bean associated with the print page can obtain the data from the session scope by that key.

JSF datatable refresh on page load

I have a data table in JSF which gets populated when user selects a drop-down menu. The list that table shows comes from a backing bean. This backing bean is in the session scope. So when user clicks on other links of the webpage and comes back to this page, it still shows the data from the data list with the previous selections.
Question is - how to make sure, that data gets reset when user leaves the page so that when user comes back in, they can see a fresh page with no data in it.
I can not put the backing bean in request scope as that will make it impossible to have a cart type application.
Keep the datamodel in the session scoped bean, add a request scoped bean which copies the reference from the session scoped bean and let the form submit to that request scoped bean and let the view use the request scoped bean instead. You can access the session scoped bean from inside a request scoped bean by under each managed property injection. E.g.
<managed-bean>
<managed-bean-name>cart</managed-bean-name>
<managed-bean-class>com.example.Cart</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>showCart</managed-bean-name>
<managed-bean-class>com.example.ShowCart</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>cart</property-name>
<value>#{cart}</value>
</managed-property>
</managed-bean>
wherein the ShowCart can look like:
public class ShowCart {
private Cart cart;
private Cart show;
// +getters+setters
public String submit() {
show = cart;
// ...
}
}
and the view uses #{showCart.show} instead.

Resources