I'm using JSF 2.0 and I want to invoke a function defined in a Java controller when I click on an ace:textEntry.
I tried in this way:
<ace:textEntry readonly="true" value="#{myController.getValue()}"
onclick="#{myController.myFunc()}"/>
but when my page is open, the click event is called instantly.
So, I tried with:
<ace:textEntry readonly="true" value="#{myController.getValue()}">
<ace:ajax event="click" listener="#{myController.myFunc()}"/>
</ace:textEntry>
but my page is not rendered.
Is there another way to implement this behaviour ?
PS: I can use similar JSF components instead of ace:textEntry too.
First, you do not access getters directly in JSF for value backing - you access the property. Secondly, you should call the listener with the correct signature. To correct your example I would first rewrite the call like this,
<ace:textEntry readonly="true" value="#{myController.value}">
<ace:ajax event="click" listener="#{myController.myFunc}"/>
</ace:textEntry>
Then define MyController, like this;
#Named
#ViewScoped
public class MyController {
private value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public void myFunc(javax.faces.event.AjaxBehaviorEvent event) {
/* Do somethinig here... */
}
}
I am developing a JSF application
I have 2 selectOnemenu controls and submit button.
I need to disable the button if the values of 2 fields are equal
<h:selectOneMenu id="from" value="#{currencyBean.history.fromCurrency}" >
<f:selectItems value="#{currencyBean.currency}" var="c" itemValue="#{c}" itemLabel="#{c.name}"/>
</h:selectOneMenu>
<p:outputLabel for="to" value="to:" />
<h:selectOneMenu id="to" value="#{currencyBean.history.toCurrency}" >
<f:selectItems value="#{currencyBean.currency}" var="c" itemValue="#{c}" itemLabel="#{c.name}"/>
</h:selectOneMenu>
<p:commandButton id="calculateButton" value="Convert" update=":convert :historyPanel" onstart="PF('statusDialog').show()" onsuccess="PF('statusDialog').hide()" validateClient="true" ajax="true" action="#{currencyBean.Calculate()}" />
I tried to use onchange with ajax but everytime I change one dropdown the value of the second drowpdown became null in the backbean so I cannot read it.
Here is my backbean
#Named(value = "currencyBean")
#RequestScoped
public class CurrencyBean implements Serializable {
/**
* Creates a new instance of CurrencyBean
*/
private History history;
private Currency currency;
private Date currentDate;
#Inject
private Loginbean loginBean;
private List<History> historyList;
public List<History> getHistoryList() {
int userId = loginBean.getUserId();
if (userId != -1) {
return new HistoryHelper().GetHistoryListByUser(userId);
}
return null;
}
public CurrencyBean() {
history = new History();
}
public History getHistory() {
return history;
}
public void setHistory(History history) {
this.history = history;
}
public Currency[] getCurrency() {
return Currency.values();
}
public Date getCurrentDate() {
return new Date();
}
public void Calculate() {
int userId = loginBean.getUserId();
if (userId != -1) {
new CurrencyClient().Convert(userId, this.history);
}
}
}
any clue ?
My assumption is that all of your problems come from your managed bean scope. You have #Request scope so every request your managed bean will be removed from container, thus when you define onchange="submit()" (this is only my assumption because you haven't define how you implement onchange attribute) and you select value from one selectBox component values for this component is updated but the first one is still null. When you select second selectBox value updated from first selectBox doesn't exists anymore as managed bean has been removed after first request. You should try with wider scope for instance #ViewScope. If it doesn't help then further informations like implementation onchange attribute will be needed
I have a lazily loaded <p:dataGrid>. The corresponding XHTML code is as under.
<p:panel id="dataPanel" header="Data">
<p:dataGrid value="#{testManagedBean}" var="row" columns="3" rows="9" pageLinks="10" paginator="true" lazy="true">
<p:column>
<h:outputText id="lblCharge" value="#{row.weight}" converter="#{bigDecimalGeneralOutputConverter}"/><br/>
<p:inputText id="txtCharge" value="#{row.charge}" converter="#{bigDecimalGeneralConverter}"/>
</p:column>
<p:ajax event="page"/>
</p:dataGrid>
<p:commandButton id="btnSubmit" update="dataPanel" actionListener="#{testManagedBean.insert}" value="Save" icon="ui-icon-check"/>
<p:commandButton value="Reset" update="dataPanel" process="#this">
<p:resetInput target="dataPanel" />
</p:commandButton>
</p:panel>
The associated JSF managed bean looks like as show below.
#ManagedBean
#ViewScoped
public final class TestManagedBean extends LazyDataModel<ZoneChargeUtils> implements Serializable
{
#EJB
private final ZoneChargeBeanLocal zoneChargeService=null;
private static final long serialVersionUID = 1L;
#Override
public List<ZoneChargeUtils> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters)
{
setRowCount(zoneChargeService.rowCount(7L).intValue());
return zoneChargeService.getZoneChargeList(7L, first, pageSize);
}
public void insert() {
System.out.println("insert() called.");
}
}
The data grid displays a group of <p:inputText>s that looks something like the following.
A user can modify values held by <p:inputText> as can be seen in the snap shot. The modified values are to be stored into the database, when the given <p:commandButton> (save) immediately below the data grid is pressed.
The associated action listener insert() is invoked, when this <p:commandButton> is pressed but how to get these modified values in that action listener so that they can be sent to the database in question?
This can be done avoiding lazy loading as shown in this answer. This is the exact same scenario but with lazy loading.
How to get the list, List<ZoneChargeUtils> with new / modified values in <p:inputText>, when the given <p:commandButton> is clicked?
The utility class ZoneChargeUtils though completely unnecessary.
public final class ZoneChargeUtils implements Serializable
{
private Long weightId;
private BigDecimal weight;
private BigDecimal charge;
private static final long serialVersionUID = 1L;
//Getters and setters + constructor(s).
}
This is not a persistent entity / POJO. It is used to execute queries with constructor expressions in JPA
The solution to this problem involves keeping two buffers in your #ViewScoped managed bean, one for the whole set of the changed values and other one for the current view values. Moreover, you'll need to call a listener method everytime you switch the page to send your current values to the managed bean:
<p:panel id="dataPanel" header="Data">
<p:dataGrid value="#{testManagedBean}" var="row" columns="3"
rows="9" pageLinks="10" paginator="true" lazy="true">
<p:column>
<h:outputText id="lblCharge" value="#{row.weight}"
converter="#{bigDecimalGeneralOutputConverter}"/><br/>
<p:inputText id="txtCharge" value="#{row.charge}"
converter="#{bigDecimalGeneralConverter}"/>
</p:column>
<p:ajax event="page" listener="#{testManagedBean.pageChanged}"/>
</p:dataGrid>
<p:commandButton id="btnSubmit" update="dataPanel"
action="#{testManagedBean.insert}" value="Save" icon="ui-icon-check"/>
<p:commandButton value="Reset" update="dataPanel" process="#this">
<p:resetInput target="dataPanel" />
</p:commandButton>
</p:panel>
I made couple of changes here. One is adding a listener method to the ajax event for the page changing. The other one is replacing actionListener by action in your p:commandButton. action is the most convenient way to go when performing business actions like yours.
#ManagedBean
#ViewScoped
public final class TestManagedBean extends LazyDataModel<ZoneChargeUtils> implements Serializable
{
#EJB
private final ZoneChargeBeanLocal zoneChargeService=null;
private static final long serialVersionUID = 1L;
private Map<Integer, ZoneChargeUtils> bufferedZones = new HashMap<Integer, ZoneChargeUtils>();
private List<ZoneChargeUtils> currentZones = new ArrayList<ZoneChargeUtils>();
#Override
public List<ZoneChargeUtils> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters)
{
currentZones.clear();
setRowCount(zoneChargeService.rowCount(7L).intValue());
List loadedZones = zoneChargeService.getZoneChargeList(7L, first, pageSize);
for (ZoneChargeUtils zone : loadedZones){
if (bufferedZones.containsKey(zone.getId())){
//The zone has been loaded before in the view. Load the buffered value
//Otherwise, you'll lose it'll be overwritten with DB value when lazy loading
currentZones.add(bufferedZones.get(zone.getId()));
}else{
currentZones.add(zone);
}
}
return currentZones;
}
public void pageChanged(){
//The user has changed the page. Update bufferedZones with the possible new values
for (ZoneChargeUtils zone : currentZones){
bufferedZones.put(zone.getId(), zone);
}
}
//Looks for modified values in the CURRENT page before updating them.
//If value isn't there, return the one passed in the param
private ZoneChargeUtils lookUpInCurrent(ZoneChargeUtils zone){
for (ZoneChargeUtils z : currentZones){
if (zone.getId() == z.getId()){
return z;
}
}
return zone;
}
//Persist the values. Look in the general buffer, keeping in mind it has been updated in the last page change.
//Because of that, we have to look also in the current buffer for changes made in the current page.
public void insert() {
for (ZoneChargeUtils zone : bufferedZones.values()){
zoneChargeService.updateZone(lookUpInCurrent(zone));
}
}
}
For the managed bean, you're interested in keeping two values: the changes happened in the current page and the changes for the whole set of loaded pages. I use a List for the first one and a Map for the second, supposing you already have an Id defined for your ZoneChargeUtils. Steps are following:
When user loads the first page (or any page) the loadData method is called for the current value set. In order of returning the persisted values directly, you check them against the whole buffer. If the value has been loaded before, use the buffered value. Otherwise, present the persisted one.
When user changes the page, update the whole buffer with the current one. That way you are able to keep the modified values.
When user saves the changes, go to the whole buffer (the Map) and iterate over its values. Make an update for each one of the loaded entities.
The associated action listener insert() is invoked, when this
is pressed but how to get these modified values in
that action listener so that they can be sent to the database in
question?
Store the reference of changed 'entities' in a HashMap<Integer, ZoneChargeUtils >. Then execute those changes in insert(), by iterating through that HashMap. You need an ajax value change listener for the <p:inputText> to listen to the changes, and in order to modify/update the state storing HashMap.
It's slightly different that the solution proposed by Xtreme Biker, but the idea is same : Store the state-change in Map.
hy all,
First: i m not ok for do #ManagedBean and #ViewScoped in Class TestManagedBean where this Class extend LazyDataModel
the solution is:
public final class lazyZoneChargeUtils extends LazyDataModel<ZoneChargeUtils> implements Serializable{
#Override
public List<ZoneChargeUtils> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters)
{
currentZones.clear();
setRowCount(zoneChargeService.rowCount(7L).intValue());
List loadedZones = zoneChargeService.getZoneChargeList(7L, first, pageSize);
for (ZoneChargeUtils zone : loadedZones){
if (bufferedZones.containsKey(zone.getId())){
//The zone has been loaded before in the view. Load the buffered value
currentZones.add(bufferedZones.get(zone.getId()));
}else{
currentZones.add(zone);
}
}
return currentZones;
}
}
and :
#ManagedBean
#ViewScoped
public class TestManagedBean {
//all variable
private LazyDataModel<ZoneChargeUtils> listZoneChargeUtils;
#PostConstruct
public void init() {
//init listZoneChargeUtils
this.listZoneChargeUtils = new lazyZoneChargeUtils();
}
public void onEdit(RowEditEvent event) {
ZoneChargeUtils var = (ZoneChargeUtils) event.getObject();
//do your code and save object in DataBase
}
public void onCancel(RowEditEvent event) {
ZoneChargeUtils var = (ZoneChargeUtils) event.getObject();
FacesMessage msg = new FacesMessage("Message : ", var.getName());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
/**
* #return the listZoneChargeUtils
*
* #author asghaier
*
* Created on 12/mag/2014
*/
public LazyDataModel<ZoneChargeUtils> getListZoneChargeUtils() {
return listZoneChargeUtils;
}
/**
* #param listZoneChargeUtils the listZoneChargeUtils to set
*
* #author asghaier
*
* Created on 12/mag/2014
*/
public void setListZoneChargeUtils(LazyDataModel<ZoneChargeUtils> listZoneChargeUtils) {
this.listZoneChargeUtils = listZoneChargeUtils;
}
//all getter and setter
}
and now in your page do this:
<p:panel id="dataPanel" header="Data">
<p:dataGrid value="#{testManagedBean.listZoneChargeUtils}" var="row" columns="3" rows="9" pageLinks="10" paginator="true" lazy="true" editable="true">
<p:ajax event="rowEdit" listener="#{testManagedBean.onEdit}" />
<p:ajax event="rowEditCancel" listener="#{testManagedBean.onCancel}" />
<p:column>
<h:outputText id="lblCharge" value="#{row.weight}" converter="#{bigDecimalGeneralOutputConverter}"/><br/>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{row.charge}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{row.charge}" style="width:100%" converter="#{bigDecimalGeneralConverter}"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column >
<p:rowEditor />
</p:column>
</p:dataGrid>
this is in general haw you must do, ( i dont have see good all code).
resume:
1- do class extends LazyDataModel<...> and dont put any #ManagedBean or #ViewScoped
2- do class #ManagedBeanand and #ViewScoped and in the class creat variable in type
LazyDataModel<...> listData, implement getter and setter for this variabile, and init the variable listData in methode init() where is #PostConstruct
3- add editable="true" to your dataTable
4- in the class creat in step 2 add method onCancel & onEdit , in the methode onEdit do your code Java and save the object in database.
5- all is ok :)
In this case, the following approach using the getWrappedData() method of LazyDataModel<T> works as expected.
#ManagedBean
#ViewScoped
public final class TestManagedBean extends LazyDataModel<ZoneChargeUtils> implements Serializable
{
#EJB
private final ZoneChargeBeanLocal zoneChargeService=null;
private static final long serialVersionUID = 1L;
#Override
public List<ZoneChargeUtils> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters)
{
setRowCount(zoneChargeService.rowCount(7L).intValue());
return zoneChargeService.getZoneChargeList(7L, first, pageSize);
}
public void insert() {
//Returns the lazily loaded list with the modified values completely appropriate to the page size.
//Do whatever you want to do with the lazily loaded list now.
List<ZoneChargeUtils> zoneChargeUtils = (List<ZoneChargeUtils>) getWrappedData();
for(ZoneChargeUtils utils:zoneChargeUtils) {
System.out.println(utils.getWeightId()+" : "+utils.getWeight()+" : "+utils.getCharge());
}
}
}
The getWrappedData() method returns the list with modified values in <p:inputText> according to the page size defined, hence, eliminating the need of extraneous code to get the associated lazily loaded list back in the listener method.
I want to pass parameter node to the function doAction which will be invoked by the remote command, how can I pass it? Suppose node has attributes name and type and I want to use them in doAction, how can I pass the variables?
Thanks!
public static class node {
String name;
String type;
//setters getters etc...
}
<p:remoteCommand name="doWhatYouWant" action="#{managedBean.doAction}" />
<p:treeTable value="#{managedBean.tree}" var="node">
<p:column>
<p:commandLink value="Invoke action" onclick="doWhatYouWant([params...])" />
</p:column>
</p:tree>
public void doAction() {
// do something with var="node"
}
I solved this problem with
<p:remoteCommand name="doWhatYouWant" action="#{managedBean.doAction}" />
...
<p:commandLink value="Invoke action"
onclick="doWhatYouWant(
[{name:'n', value:'#{node.name}'},
{name:'t', value:'#{node.type}'}])" />
In the supporting bean:
public void doAction() {
FacesContext context = FacesContext.getCurrentInstance();
Map<String, String> map = context.getExternalContext().getRequestParameterMap();
String name = map.get("n"); // name attribute of node
String type = map.get("t"); // type attribute of node
...
}
I came up with a strange problem. I tried to isolate the problem so following is my simplified code.
public class MyBean {
private List<Data> dataList;
Data selectedData;
public MyBean() {
dataList = new ArrayList<Data>();
dataList.add(new Data("John", 16));
dataList.add(new Data("William", 25));
}
public List<Data> getDataList() {
return dataList;
}
public void edit(Data data) {
selectedData = data;
}
public void newData() {
selectedData = new Data(null, null);
}
public Data getSelectedData() {
return selectedData;
}
public class Data {
String name;
Integer age;
Data(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
}
xhtml:
<rich:modalPanel id="pop">
<h:form>
Name: <h:inputText value="#{myBean.selectedData.name}" required="true" id="txtName"/><br/>
Age : <h:inputText value="#{myBean.selectedData.age}" required="true" id="txtAge"/>
<a4j:commandButton value="Save"/>
<a4j:commandButton value="Close" onclick="Richfaces.hideModalPanel('pop');return false;"/>
<br/>
<rich:message for="txtName"/><br/>
<rich:message for="txtAge"/>
</h:form>
</rich:modalPanel>
<h:form>
<rich:dataTable value="#{myBean.dataList}" var="data">
<rich:column>#{data.name}</rich:column>
<rich:column>
<a4j:commandLink value="Edit" action="#{myBean.edit(data)}" reRender="pop" oncomplete="Richfaces.showModalPanel('pop')"/>
</rich:column>
</rich:dataTable>
<a4j:commandButton value="New" action="#{myBean.newData()}" reRender="pop" oncomplete="Richfaces.showModalPanel('pop')"/>
</h:form>
This is the path to error:
Load the page
Click the "Edit" link in first row(popup displays)
In popup, clear the "Age" field and click "Save".(Required message shown)
Click cancel(without filling "Age" field)
Click second link.
Now it shows irrelevant data(previous data). - This is the problem
Even when I click "New" button it shows incorrect data.
This happens only if a validation is failed in the popup.
Is there a solution for this?
This problem is in JSF 2 also recognized and explained in detail in the following answer: How can I populate a text field using PrimeFaces AJAX after validation errors occur? If you were using JSF 2, you could have used OmniFaces' ResetInputAjaxActionListener or PrimeFaces' <p:resetInput> or resetValues="true" for this.
To the point, you need to clear the state of the EditableValueHolder component when it's about to be ajax-rendered, but which isn't included in the ajax-execute. To clear the state, in JSF 2 you would have used the convenience method resetValue() for this, but this isn't available in JSF 1.2 and you need to invoke the 4 individual methods setValue(null), setSubmittedValue(null), setLocalValueSet(false), setValid(true) to clear the state.
To figure out which components are to be ajax-rendered, but aren't been ajax-executed, in JSF 2 you would have used PartialViewContext methods for this, but this is not available in JSF 1.2 which hasn't standardized ajax yet. You'd need to fiddle with RichFaces specific ajax API in order to figure that. I can't tell that from top of head, so here's a kickoff example assuming that you already know the components which needs to be cleared. Imagine that the form in your popup has id="popForm" and the name input field has id="nameInput", here's how you could clear it inside the newData() method:
UIInput nameInput = (UIInput) context.getViewRoot().findComponent("popForm:nameInput");
nameInput.setValue(null);
nameInput.setSubmittedValue(null);
nameInput.setLocalValueSet(false);
nameInput.setValid(true);
do one thing on cancel action set all popup values null. now in your next click all values set to be default.
or on click set all previous values null. and set all respective values after that.
I had the same problem. if you are using Primefaces, the solution is as simple as putting resetValues="true" on your p:commandLink or p:commandButton that loads the selected item.
After validation failed if you want to remain same as input data which you have pass as submission parameter, then set value attribute as your form bean name as mention below i.e.
<input type="text" id="fname" path="fname" value="${myFormBean.fname}"/>