1

A simple application that uses Primefaces datatables with radio button selection doesn't behave properly. When I choose an element with radio button, the event argument is null in delete() method, therefore the selected row can't be removed from the datatable.

view.xhtml // Here is where I get problems

<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://xmlns.jcp.org/jsf/html"
  xmlns:p="http://primefaces.org/ui"
  xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
    <title>Event List</title>
</h:head>
<h:body>
    <h:form>
        <p:dataTable id="eventlist" var="event" value="#{eventBean.eventlist}" selection="#{eventBean.selectedEvent}" rowKey="#{event.id}" scrollable="true" scrollHeight="200" style="width:500px;">
            <f:facet name="header">
                Event List
            </f:facet>
            <p:column selectionMode="single" style="width:16px;text-align:center"/>
            <p:column headerText="ID">
                <h:outputText value="#{event.id}">
                </h:outputText>
            </p:column>
            <p:column headerText="Date">
                <h:outputText value="#{event.date}">
                    <f:convertDateTime pattern="yyyy-MM-dd" />
                </h:outputText>
            </p:column>
            <f:facet name="footer">

                <p:commandButton process="eventlist" action="#{eventBean.delete(eventBean.event)}" value="#{eventBean.event}" ajax="true" >

                </p:commandButton>
            </f:facet>
        </p:dataTable>
    </h:form>
</h:body>

EventBean.java // This is my managed bean

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.annotation.ManagedBean;
import javax.ejb.EJB;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;

@ManagedBean
@Named(value = "eventBean")
@RequestScoped
public class EventBean {

@EJB
private EventManager em;

private Event event;

private Event selectedEvent = new Event(); 

private Date currentDate;

private List<Event> eventlist = new ArrayList<Event>();


public Date getCurrentDate() {
    if (currentDate == null) {
        currentDate = new Date();
    }
    return currentDate;
}

public EventBean() {
}

public Event getEvent() {
    if (event == null) {
        event = new Event();
    }
    return event;
}

public void setEvent(Event event) {
    this.event = event;
}

public List<Event> getEventlist() {
    return eventlist;
}

public void setEventlist(List<Event> eventlist) {
    this.eventlist = eventlist;
}

public Event getSelectedEvent() {

    return selectedEvent;
}

public void setSelectedEvent(Event selectedEvent) {
    this.selectedEvent = selectedEvent;
}

public String create() {
    em.save(event);
    eventlist = em.findEvents();
    return "view";
}

public String delete(Event event){  //the event object is null
    em.deleteEvent(event);
    return "index";
}
}

Briefly, what I would like to achieve is: select properly the row from the datatable and then delete it both from the datatable and database.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
jiasheng
  • 181
  • 8

1 Answers1

1

The selection is set as #{eventBean.selectedEvent}, but you're passing #{eventBean.event} forth and back to the delete method. This problem is two-fold. Firstly, it's the wrong property. Secondly, you don't need to pass it forth and back. It's already in the bean.

So, this should do:

<p:commandButton ... action="#{eventBean.delete}" />

with

public String delete() {
    em.deleteEvent(selectedEvent);
    return "index";
}

Another strange thing is that you're nowhere initializing the eventlist during bean's initialization. This means that when you submit the form, during that new request wherein the request scoped bean is newly constructed and initialized, the eventlist would be null and thus there would be nothing available to select and set in the model.

You should have the following method in EventBean:

@PostConstruct
public void init() {
    eventlist = em.findEvents();
}

This way you should now also be able to see the list already when just directly opening the view.xhtml in browser without first submitting an arbitrary form in another page. In other words, it's now finally idempotent.


Unrelated to the concrete problem, you're mixing JSF and CDI bean management annotations. Get rid of the @ManagedBean annotation altogether. You're also performing lazy loading in getter methods. Get rid of them all and do the job in @PostConstruct and leave the autogenerated getter (and setter) methods untouched. This way you can also easily provide more short code snippets in questions where by you omit all getters/setters, because they are obvious enough.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I tried to modify the code as you suggested but I got this log: Alert: A system exception occurred during an invocation on EJB EventManager, method: public void boundary.EventManager.deleteEvent(entity.Event) Alert: javax.ejb.EJBException [...] at com.sun.proxy.$Proxy244.deleteEvent(Unknown Source) at boundary.__EJB31_Generated__EventManager__Intf____Bean__.deleteEvent(Unknown Source) at control.EventController.delete(EventController.java:86) [...] Caused by: java.lang.IllegalArgumentException: Object: null is not a known entity type. [...] – jiasheng Jan 08 '15 at 16:24
  • It's not visible in your code how you're preparing and preserving the `eventlist`. It's basically an empty list which I assumed to be result of oversimplification of the code. Try posting a http://stackoverflow.com/help/mcve – BalusC Jan 08 '15 at 16:33
  • In the original text of the question there were all the created files of the project except for the entity Event.java. However, the variable List eventlist is only for showing the data in the datatable purpose and not for the the delection of the event, to which I assigned the variable Event selectedEvent. I think my main problem now is that selection="#{eventBean.selectedEvent}" doesn't get the selected event. – jiasheng Jan 08 '15 at 16:53
  • You should be doing `eventlist = em.findEvents();` in `@PostConstruct` of the bean and preferably make the bean `@ViewScoped`. – BalusC Jan 08 '15 at 17:49
  • I think @PostConstruct is not my problem because I actually can see the whole list of the stored data. But anyway I tried your method but if I use ViewScoped I get EJBException when I create and show the list of events (and this was the part that used to work). – jiasheng Jan 08 '15 at 18:17
  • As of now, your list view cannot exist without create view. This isn't right. You should be able to open the list view standalone. See also a.o. http://stackoverflow.com/questions/8459903/creating-a-master-detail-user-interface-for-entities-which-bean-scope-to-choose/8464636#8464636 – BalusC Jan 08 '15 at 18:19
  • It works! :) At the end I've added the `@PostConstruct` as you suggested and mantained the `@RequestScoped` annotation. However I changed the method by passing the value of the id of the event instead of the event itself. Thanks! – jiasheng Jan 09 '15 at 11:58