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.
Related
I have the following structure:
listView.xhtml
<h:dataTable value="#{listBean.myList} ...>
//for every row I create a commandLink
<h:commandLink action="editView" value="edit" />
</h:dataTable>
ListBean.java
#ManagedBean
#ViewScoped
public class ListBean{
public List<Entity> myList; // also getters and setters
}
editView.xhtml
<h:inputText value="#{editBean.selectedEntity.name}" />
EditBean.java
#ManagedBean
#ViewScoped
public class EditBean{
public Entity selectedEntity; // also getters and setters
}
You know the question: How can I transport the selected Entity from listView to editView? This should be very simple I thought, but after a whole day, I didnt get it work.
I tried different stuff, like #ManagedProperty and <f:param name="" value=""> but I didnt help me.
So please, show me how simple and nice this can be :)
Thanks in advance!
UPDATE - Solution#1
Thanks to Daniel,
a possible way that works is, when the entity is hold by an EntityManager, so you can access the entity by its id. So you will pass the id as an request Parameter. Here we go:
listView.xhtml
<h:dataTable value="#{listBean.myList} ...>
//for every row I create a commandLink, so you can click on that entity to edit it
<h:commandLink action="editView" value="edit">
<f:param name="selectedEntityId" value="#{entity.id}" />
</h:commandLink>
</h:dataTable>
EditBean.java
#ManagedBean
#ViewScoped
public class EditBean{
private Entity selectedEntity;
#PostConstruct
public void init() {
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
long selectedEntityId = Long.parseLong(params.get("selectedEntityId"));
selectedEntity = SomeEntityManagerUtil.getEntity(selectedEntityId);
}
}
The general idea could be :
To pass an id of that entity and get an entity by that id later on...
You also could use a converter and inside it translate that id into entity...
like this :
<h:inputText value="#{editBean.selectedEntity.name}" converter="myEntityConverter"/>
Perhaps you should merge your beans if they have the same scope ?
You may also use the context:
jsf-get-managed-bean-by-name
Also look at this question:
passing-data-between-managed-components-in-jsf
I have to put radio and chechbox controls in primefaces's 2.2.1 datatable but not as a selection mode controls. I want to bind that controls as a values for the backing bean.
For example:
A have a list of some configurations and in that list only one configuration can be active at one time (radiobox) but every single configuration can be active or not (selectbox).
Datatable doesn't have to be editable, because I will change values in another window. Only controls should be in the datatable.
Is that possible?
Yes, it is definitely possible I do this all the time in my datatables. However, you need to keep in mind that each row will require identification. You can do this with objects or parameters to your listener:
//Backing Bean
#ViewScoped
public class TestBean
{
private ArrayList<Element> elements;
TestBean(){...}
public ArrayList<Element> getElements(){...} //Initialize things here
public class Element
{
/* getter/setter and initialization assumed */
private boolean selected;
private String radioSelection = "one";
private String[] radioChoices = new String[]{"one", "two", "three"};
public void selectMe(ActionEvent evt)
{
System.out.println("Selected -> " + this);
}
}
}
//HTML
<p:dataTable value="testBean.elements" var="element">
<p:column>
<p:commandButton value="Select" actionListener="#{element.selectMe}"
</p:column>
<p:column>
<h:selectBooleanCheckbox value="#{element.selected}" />
</p:column>
<p:column>
<h:selectOneRadio value="#{element.radioSelection}">
<f:selectItems
value="#{element.radioChoices}"
var="item"
itemLabel="#{item}"
itemValue="#{item}"
/>
</h:selectOneRadio>
</p:column>
</p:dataTable>
You can (and might want to) use a parameter using the ID from the element or whatever your preferred pattern is. The key is remembering that each row has its own id and you're creating a set of elements, not a single element. That's where you're most likely to get bound up. Seeing as how each button is a first class citizen you should be able to whatever you want with it.
Edit:
I added a Radio/Checkbox example. It sounds like you're new to JSF so I'd advise reading up on the SelectItem class and run through how combo-boxes etc... work. The key to remember (as I stress above) is that you're rendering a lot of components so if you share a value it can easily lead to behavior you don't want. Encapsulate everything and you're usually in good shape.) You can also look at bindings as a possible solution. It all depends on where you'd rather write your code.
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.
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.
I need to determine the ID of a form field from within an action handler. The field is a part of a included facelets component and so the form will vary.
included.xhtml
<ui:component>
<h:inputText id="contained_field"/>
<h:commandButton actionListener="#{backingBean.update}" value="Submit"/>
</ui:component>
example_containing.xhtml
<h:form id="containing_form">
<ui:include src="/included.xhtml"/>
</h:form>
How may I determine the ID of the form in the update method at runtime? Or better yet, the ID of the input field directly.
Bind the button to your backing bean, then use getParent() until you find the nearest form.
Programmatically I would use jsight's method. You can know the id of your elements (unless you let JSF create them, I don't know the means for numbering in the ids) by looking at it. h:form is a naming container so as long as you don't have it wrapped in another naming container it will be containingForm:containedfield The ':' is the naming separator by default is JSF and the ids are created like this, roughly anyway, (parentNamingContainerId:)*componentId
Since update method is of type actionListener, you can access your UI component as follows
public void update(javax.faces.event.ActionEvent ac) {
javax.faces.component.UIComponent myCommand = ac.getComponent( );
String id = myCommand.getId(); // get the id of the firing component
..... your code .........
}