<h:commandButton> doesn't start the action - NO IDEA? - java

I'm trying to use dataModel instead of binding dataTable and have this issue. At the last column there is a commandButton which should be used for delete item from database. But when I press it, the java method isn't started.
Part of xhtml (reduced code):
<h:form>
<rich:extendedDataTable
id="table"
var="fItem"
value="#{myFood.model}"
selectionMode="none">
<rich:column width="150px">
<f:facet name="header">Datum:</f:facet>
<h:outputText value="#{fItem.date}"/>
</rich:column>
<rich:column>
<h:commandButton id="save" action="#{myFood.delete}" value="delete"/>
</rich:column>
<f:facet name="footer">
<h:commandButton id="btnTest" action="#{myFood.test}" value="test"/>
</f:facet>
</rich:extendedDataTable>
</h:form>
Part of MyFood.java:
public void delete()
{
System.out.println("TEST");
try
{
DaoCrud.delete(model.getRowData(), 'P');
}
catch (Exception e) {.....}
}
public void test()
{
System.out.println("TEST");
}
But even "TEST" is not writen to console!
Where could be the problem?
UPDATE: I've updated code examples (facet & test()), it works. Everything works fine until I've tried using dataModel private DataModel<Item> model;...
When I simply move the same commandButton to the facet, it works.

If the bean is request scoped, then you need to ensure that exactly the same model is been created during bean's (post)construction of the form submit request as it was during displaying the initial form.
private List<Item> list;
private DataModel<Item> model;
#PostConstruct
public void init() {
list = itemService.list();
model = new ListDataModel<Item>(list);
}
JSF will namely iterate over the model during the apply request values phase to determine the button pressed so that it can be invoked during the invoke application phase.
If preserving the model in the subsequent request isn't exactly trivial due to some business restrictions (e.g. missing parameters, etc), then you need to put the bean in the view scope by marking it #ViewScoped instead of #RequestScoped. This works only if you're using JSF 2.0.
#ManagedBean
#ViewScoped
public class MyBean {}
Alternatively, since you're using RichFaces, you could also use <a4j:keepAlive> for this. Put this somewhere in the same page as the form:
<a4j:keepAlive beanName="#{myBean}" />
This does effectively the same as #ViewScoped does in JSF 2.0.

It should be under <h:form>

Your delete() method should return an Object. It won't be called if the signature is not correct. "signature must match java.lang.Object action()". See here.
As far as I remember you can just return null if you want to stay at the page.
public String delete()
{
System.out.println("TEST");
try
{
DaoCrud.delete(model.getRowData(), 'P');
}
catch (Exception e) {.....}
return null;
}
You might want to use the actionListener attribute with its corresponding method if you dont want to use the method outcome for navigation. Also consider to use a <a4j:commandButton> if you want to reRender something after the actionListener has been executed.

Related

Primefaces DataTable display only the last item

the Datatable is displaying only the last item added, it seems that every time i press the commandButton the method rewrites the list, what can I do to avoid that?
JSF
<p:commandButton action="#{productoBean.setPedidoActual()}" value="Agregar" update="dt"/>
</p:panelGrid>
<p:dataTable value="#{productoBean.pedidoActual}" var="pedi">
<p:column headerText="Nombre">
<h:outputText value="#{pedi.descripcion}"/>
</p:column>
</p:dataTable>
Bean
public void setPedidoActual() {
Producto pro = productoFacade.find(idProducto);
listPedidoActual.add(pro);
}
public List<Producto> getPedidoActual() {
return listPedidoActual;
}
Your setPedidoActual() method seems like to receive only one item based on the facade service find(idProducto), is that correct? Have you checked what the remote service returns? Probably there is in fact just one record.
Beside that, try to rename your setter/getter from
getPedidoActual() / setPedidoActual()
into
getListPedidoActual() setListPedidoActual()
Now your method names are consistent with your attribute.
EDIT: What happened to the panelGrid tag? Have you purposely omitted or where does it start?

Primefaces cannot update p:tree

I'm working with primefaces 4.0 and JSF 2.2 and I'm currently trying to update a form with a p:tree on it. The commandButton works correctly but it does not update the form or call the init() method until I manually refresh the page. I don't know what I'm doing wrong since the same code does work for a DataTable element.
Here's the code:
<h:form id="preferenciasForm">
<div id="panelTree">
<p:panel id="defTree" style="margin-bottom: 20px">
<p:tree value="#{dtPreferencesBuilder.root}" var="node"
selectionMode="checkbox"
selection="#{dtPreferencesBuilder.selectedNodes}"
style="width:100%; height:100%;" animate="true">
<p:treeNode>
<h:outputText value="#{node.label}" />
</p:treeNode>
</p:tree>
<p:commandButton value="Add preferences"
icon="ui-icon-pencil"
actionListener="#{dtPreferencesBuilder.insertPrefNodes()}"
update=":preferenciasForm" ajax="true" />
</p:panel>
</div>
</h:form>
And here's is the java class.
#ManagedBean(name="dtPreferencesBuilder")
#ViewScoped //I've tried with or without the ViewScoped, neither work
public class PreferencesBuilderBean {
private TreeNode root;
private TreeNode prefRoot;
private TreeNode[] selectedNodes;
#PostConstruct
public void init() {
System.out.println("Building Tree");
selectedNodes=null;
root=null;
prefRoot=null;
root=getStandardTree();
prefRoot=getPreferedTree();
}
The init() is not called as the print is only show on manual reload so the tree is not updated nor the selectedNodes refreshed. Any ideas why it doesn't work?
As I cannot describe bean scopes better than excellent answers already given for similar questions I'll just refer you to the answers by BalusC and Kishor P here.
The init-method (or any method with the #PostConstruct-annotation) will be called by the framework only when the bean is created, after injections and therefore after the constructor has run as rion18 said. It would not be normal to use the method for anything else than initializing work. So create other methods, and call those from actions and actionListeners.
If you want the bean to be the same when you call it with ajax (as you do) it needs to be at least ViewScoped. If you really do want to call the init() every time it should be RequestScoped, but then the bean will be new when you call it with ajax and not remember a thing.

open new page (navigate to new site) when selecting a dataTable row

There a several related question on this topic on SO and elsewhere, but I couldn't find a definitive answer on this specific question.
I have a p:dataTable and I want the possibility to click on a row and open a detail page (a new page, not a dialogue or window).
I have solved it this way (which I have from the primefaces website, for some reason it is no longer there: http://web.archive.org/web/20101001223235/http://www.primefaces.org/showcase/ui/datatableRowSelectionInstant.jsf):
<p:dataTable var="order" value="#{orderBean.orders}" selection="#{orderBean.selectedOrder}" selectionMode="single" rowKey="#{order.number}">
<p:ajax event="rowSelect" listener="#{orderBean.orderSelect}"/>
<p:column ... />
</p:dataTable>
The navigation is then executed in the bean:
public void orderSelect(SelectEvent event) {
ConfigurableNavigationHandler nh = (ConfigurableNavigationHandler)FacesContext.getCurrentInstance().getApplication().getNavigationHandler();
nh.performNavigation("orderDetail?faces-redirect=true");
}
My Question: is there a way of doing this just inside JSF without the help of a backing bean?
I am also asking because they removed the code exmaple from the primefaces site, which might be an indication that this is not the right way of doing something like that.
Wrap the cell(s) of interest in a simple <h:link>.
<p:column>
<h:link outcome="orderDetail">
...
</h:link>
</p:column>
Use if necessary CSS display:block on the link to let it span the entire cell. You can if necessary pass request parameters using a nested <f:param>.
since it is an ajax request, typically the request/response is used to re-render some components in the web page. What you could do is
<p:ajax event="someventofintrest" onsuccess="javascript:myjsmethod();"></p:ajax>
and
<p:remotecommand name="myjsmethod" action="#{mybean.mybeanmethod}" />
and in the backing bean
public String mybeanmethod(){
return "mynewpage"; // Navigate away to mynewpage.xhtml
}
HTH.
As I didn't find a really perfect solution, this is how I do it now.
I have now a "navigator" class like this
#Component
public class Navigator {
public void nav(String page) {
UIHelper.navigateTo(page);
}
}
And I call this class from my ajax event:
<p:ajax event="rowSelect" listener="#{navigator.nav('orderDetail')}"/>
As I said, not really perfect, but I like the fact that I don't have to write code in my backing bean. (Of course I have to write code for the Navigator, but that I can re-use.)

Passing Parameter From One Method To Another

I have a rather silly question, I need to pass a parameter from one method to another method.
I have the following method
public String test(Employees emp)
{
return emp.getempno();
}
I need to pass emp.getempno() to my another method loadDetails();
My problem is I cannot add an argument in loadDetails() method because I am calling this method in couple of other places.
How can I achieve this? I tried putting emp.getempno() in collecion object but problem is test(Employees emp) methood is not being invoked in my second method.
Excuse me for my ignorance, any help is highly appreciable.
Thanks
Update 1
This is how I assign value to test method and getTestValues method is being called from another class when I pass parameter from one page to another.
public void getTestValues(List<Employees> paramList) {
for (Employees dataItem: paramList) {
test(dataItem);
}
}
Update 2
This is my loadDetails() method where I am fetching db values and to display as datatable in jsf page.
private void loadDetails() {
try {
dataDetails = anotherclass.deptDetails(passempno);
} catch (Exception e) {
e.printStackTrace();
logger.error("error from loadDetails" + e.getMessage());
}
}
Basically what I am trying to do is when I click a row in a datatable I would like to pass that row's primary key to second page's bean class so that I could populate datatable in second page.
JSF 1.1 and would like to pass as POST GET with commandlink outputlink in datatable.
Use the following (assuming JSF 1.1):
EmployeeBacking
public class EmployeeBacking {
private List<Employee> list;
public EmployeeBacking() {
list = employeeService.list();
}
// ...
}
employees.jsp
<h:dataTable value="#{employeeBacking.list}" var="employee">
<h:column>
<h:outputText value="#{employee.name}" />
</h:column>
<h:column>
<h:outputLink value="departments.jsp">
<h:outputText value="Show departments" />
<f:param name="employeeId" value="#{employee.id}" />
</h:outputLink>
</h:column>
</h:dataTable>
DepartmentBacking
public class DepartmentBacking {
private Long employeeId;
private List<Department> list;
private void load() {
list = departmentService.list(employeeId);
}
public List<Department> getList() {
if (list == null) load();
return list;
}
// ...
}
(please note the lazy loading in getter, in JSF 1.2 you could better use #PostConstruct method for this)
departments.jsp
<h:dataTable value="#{departmentBacking.list}" var="department">
<h:column>
<h:outputText value="#{department.name}" />
</h:column>
</h:dataTable>
faces-config.xml
<managed-bean>
<managed-bean-name>employeeBacking</managed-bean-name>
<managed-bean-class>com.example.EmployeeBacking</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>departmentBacking</managed-bean-name>
<managed-bean-class>com.example.DepartmentBacking</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>employeeId</property-name>
<value>#{param.employeeId}</value>
</managed-property>
</managed-bean>
What happens here, the outputlink will navigate to departments.jsp with the current employee ID as request parameter and the <managed-property> in faces-config.xml will set it in the department backing and finally the getter on the list will lazily load the right departments based on the employee ID.
OK, I'm still trying to wrap my head around this, but I think it's becoming a bit clearer. In order to make loadDetails() function properly, you need to know an employee number (shown above in passempno). I have two responses:
Best case, it appears that passempno is really a parameter of the loadDetails() method. I.e., the value of passempno is part of the method's behavior. As such, the strongly preferred option is to simply add the employee number as an argument. You state that you don't want to do this because other places are using it -- how are the other clients of the method using it without having an employee number specified?
If this is part of some non-trivial state of the parent class, then possibly you need to sock away the employee number in a field of the object. This is less than desirable because it's hiding (or at least making implicit) important state that loadDetails() needs to function.
If there is a stateful interaction with the backing database, and the employee number here is a piece of that state, I'd recommend factoring out the state of the database interaction into a subsidiary class that holds the employee number and any other state (as suggested in 2 above).
Let me know if this helps; if not... let me know what I missed.
I work on an ERP software for a living. Your LoadDetails method shouldn't take an Employee as a parameter.
I'm assuming loadDetails is on a Load class, and that you have an Employee who scheduled the load, or filled the load. If that's the case, the Load class should have a reference to that Employee from creation time.

Recurring JSF problem

I have a recurring JSF problem everytime I output datatables or composite components using ui:repeat. Suppose you are displaying a list of users, and in one column you have 3 icons, one to view the full profile, another to delete the user, and another to edit his data. Since i can't do something like #{fooBean.delete(user)} how should I handle this?
Here's they layout I'm talking about:
http://img821.imageshack.us/img821/9039/tablev.png
I can use commandLink to invoke logic but how do I get the user or article or product etc.
Is there any non-hackish way?
If you're using a dataTable, you can bind the dataTable component to the backing bean and figure out which row was clicked.
<h:dataTable binding="#{backingBean.userTable}" value="#{backingBean.users}" var="user"> ... </h:dataTable>
and
<h:commandLink actionListener="#{backingBean.deleteLinkClicked}">Delete</h:commandLink>
Then the backing bean:
public class BackingBean implements Serializable {
private HtmlDataTable userTable;
// implement getter/setter for userTable
public void deleteLinkClicked(ActionEvent event) {
User user = (User)userTable.getRowData();
// implement code to delete user
}
}
When using ui:repeat, I don't know the best practice, but I've used f:param to pass a parameter in the link. Below is the ui:repeat equivalent of the above.
<ui:repeat value="#{backingBean.users}" var="user">
<h:commandLink value="Delete" action="#{backingBean.deleteUser}">
<f:param name="userId" value="#{user.id}">
</h:commandLink>
</ui:repeat>
In the backing bean:
public class BackingBean implements Serializable {
#ManagedProperty(value="#{param.userId}")
private Long userId;
// implement getter/setter for userId
public String deleteUser() {
// at this point, the userId field should have been set via the param
}
}
I think that you could use an actionListener instead of an action (as I did in the dataTable example), but I haven't tried it.

Categories