0
votes

I'm new in JSF and PrimeFaces and I can't understand why my setter for selected value doesn't set:

I've got main XHTML in which after click on <p:commandButton> I want to change selected row. But after changing selection of the row on data setter setSelectedBook() get null value on entrance.

I already set selection and rowKey for <p:dataTable>.

It looks like :

main XTML:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:p="http://primefaces.org/ui"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      >

    <body>
        <ui:composition template="./../../WEB-INF/pagesTemplate.xhtml">
            <form>
                <ui:define name="content">

                    <p:dataTable id="eventsDT" var="book" value="#{bookHolder.books}"
                                 selectionMode= "single" selection="#{bookController.selectedBook}"
                                 rowKey="#{book.id}">

                        <p:ajax event="rowSelect"/>
                        <p:ajax event="rowDblselect" listener="#{bookController.onDoubleRowSelect}"  />

                        <p:column headerText="ID">
                            <h:outputText value="#{book.id}" />
                        </p:column>

                        <p:column headerText="Title">
                            <h:outputText value="#{book.longName}" />
                        </p:column>

                    </p:dataTable>
                </ui:define>

                <ui:define name="right">
                    <h:panelGrid columns="1" cellpadding="5">
                        <p:commandButton id="btnEdit" value="Edit"
                                         action="#{navigationController.moveToBookEditPageSimple}"
                                         style="width: 100px;height: 28px; margin-left: 10%"/>
                    </h:panelGrid>
                </ui:define>

            </form>
        </ui:composition>
    </body>
</html>

BookController that can't get value:

@Named("bookController")
@SessionScoped
@Local(BookView.class)
public class BookController implements Serializable {

    public BookController() {
        navigator = new NavigationController();
    }

    NavigationController navigator;

    @Inject
    BookHolder bookHolder;

    private Book selectedBook;

    public Book getSelectedBook() {
        return selectedBook;
    }

    public void setSelectedBook(Book selectedBookValue) {
        this.selectedBook = selectedBookValue;
    }

    public void onDoubleRowSelect(SelectEvent event) throws IOException {
        String str = navigator.showPage("BookEdit");
        FacesContext.getCurrentInstance().getExternalContext().redirect(str + ".xhtml");
    }      
}

BookHolderBean that contains data:

@Named("bookHolder")
@ApplicationScoped
public class BookHolder {

    public BookHolder() {
    }

    @PostConstruct
    void setValues() {
        this.books = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            this.books.add(new Book(new ParkType(i, i,
                    "Book #: " + i + " (long name)",
                    "Book #: " + i + " (short name)",
                    "Book #: " + i + " (note)")));

        }
    }

    private List<Book> books;

    public List<Book> getBooks() {
        return books;
    }

    public void setBooks(List<Book> parkTypes) {
        this.books = parkTypes;
    }
}

Class Book:

public class Book extends MainEntitie<Book> implements Serializable, SelectableDataModel<Book> {
    @Inject
    BookHolder bookHolder;

    private final String longName;
    private final String shortName;

    public Book(BookBase sd) {
        super(sd.getId(), false, false, sd.getNote());
        this.longName = sd.getLongName();
        this.shortName = sd.getShortName();
    }

    public String getLongName() {
        return longName;
    }

    public String getShortName() {
        return shortName;
    }

    @Override
    public int getId() {
        return super.getId();
    }

    @Override
    public Object getRowKey(Book t) {
        return t.getId();
    }

    @Override
    public Book getRowData(String string) {
        for (Book app : bookHolder.getBooks()) {
            if (app.getId() == Integer.parseInt(string)) {
                return app;
            }
        }
        return null;
    }
}
1
Quite confusing things. Why don't you just use LazyDataModel<T>? It is a kind of specialization of SelectableDataModel<T>. Why don't you just extend your managed bean class (BookHolder) using LazyDataModel<T> and make use of its one of the overloaded versions of public List<T> load(...)?Tiny
Because I only try to understand how does jsf works after programming on .net and didn't know about LazyDataModel. Thank you for your advise, I'll read information about this and try!Alice

1 Answers

0
votes

Since you use ui:define, I assume there is a ui:include in your template file (pagesTemplate.xhtml). If so, that is great, but your included page has some unnecessary stuff, e.g. html and body tag (by the way: use h:body). No need for that.

See second part of this posting to learn how to include an xhtml file into another one.

You will notice that the content of ui:define is kind of "cut&pasted" into the your template file. So, what about your form tag? It's being ignored (at least, I guess it won't be a parent of your datatable). Make the h:form (again, use JSF's h:form instead of HTML form) a child of ui:define, like:

<ui:composition template="/WEB-INF/template.xhtml"
xmlns=.....>
   <ui:define name="content">
      <h:form>
         <p:dataTable ...>
            ...
         </p:dataTable>
      </h:form>
   </ui:define>
</ui:composition>