1

I have a primefaces datatable where the commandButton's action addItem within the columns header facet always fires the CDI @ViewScoped beans @PostConstruct method, while the commandButton's action editItem from the column does not?!

Curiously enough this happens only, if the action methods return a non-null string?! Means, if both methods return null, the @PostConstruct method is not called, but I use a non-null string, because clicking the buttons should show a new @ViewScoped page.

The main problem in my real application is, that I do some initialization stuff within @PostConstruct, which should really happen only once during page construction!

datatable.xhtml

<?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:p="http://primefaces.org/ui"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:f="http://xmlns.jcp.org/jsf/core">

<f:view>
    <p:messages autoUpdate="true" showDetail="true"/>
    <h:outputLabel value="Datatable Test"/>
    <h:form>
        <p:dataTable var="item" value="#{datatableBean.items}">
            <p:column>
                <f:facet name="header">
                    <p:commandButton value="Add Item" action="#{datatableBean.editItem(null)}"/>
                </f:facet>
                <p:commandButton value="Edit Item" action="#{datatableBean.editItem(item)}"/>
            </p:column>
            <p:column headerText="Id">
                <p:outputLabel value="#{item.id}"/>
            </p:column>
            <p:column headerText="Name">
                <p:outputLabel value="#{item.name}"/>
            </p:column>
        </p:dataTable>
    </h:form>
</f:view>
</html>

addItem.xhtml

<?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:p="http://primefaces.org/ui"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:f="http://xmlns.jcp.org/jsf/core">

<f:view>
    <h:outputLabel value="Add Item"/>
</f:view>
</html>

editItem.xhtml

<?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:p="http://primefaces.org/ui"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:f="http://xmlns.jcp.org/jsf/core">

<f:view>
    <h:outputLabel value="Edit Item"/>
</f:view>
</html>

DatatableBean.java

package my.web.datatable;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@ViewScoped
@Named
public class DatatableBean implements Serializable {

    private List<Item> items = new ArrayList<>();

    @PostConstruct
    private void init() {
        System.out.println(DatatableBean.class.getName() + " -> init()");

        for (int i = 1; i <= 5; i++) {
            items.add(new Item(i, "Item " + i));
        }

        System.out.println(DatatableBean.class.getName() + " <- init()");
    }

    public List<Item> getItems() {
        return items;
    }

    public String editItem(Item item) {
        System.out.println(DatatableBean.class.getName() + " -> editItem(): " + item);
        if (item == null) {
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "add item", null));
            System.out.println(DatatableBean.class.getName() + " <- editItem()");
            return "addItem.xhtml";
        } else {
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "edit item", item.toString()));
            System.out.println(DatatableBean.class.getName() + " <- editItem()");
            return "editItem.xhtml";    
        }
    }
}

Item.java

package my.web.datatable;

public class Item {
    private final int id;
    private final String name;

    public Item(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return String.format("[id=%d,name=%s]", id, name);
    }
}

Is this a bug regarding command button within datatable column header facet? Or is there a better way, to do what I want?

I am using primefaces 6.0 on wildfly-10.0.0.Final with Mojarra 2.2.12!

Update: removed logger; call same method for addItem / editItem; added redirect / forward pages

raho
  • 129
  • 4
  • 18
  • if you mean "destroyed when a postback with a non-null outcome is been performed" then I don't understand what's the difference between the action within the facet and the other one? – raho Oct 22 '16 at 11:46
  • Sorry, I agree there is something weird going on. I'd suggest you to make a minimal example that can be copied right away. Without the logger, with a page to redirect to, with h:head, h:body etc. I'm observing the same if I call the exact same method from the 2 buttons, so throw 1 method out – Jaqen H'ghar Oct 22 '16 at 15:40
  • I've never seen a commandButton being used in a header like that. Might be that it triggers more events and is (unofficially) just not supported (meaning it is not necessarily a bug), just never tested/used etc. But now I think of it, the one in the header is the expected behaviour. The other one should fire a post construct to IIRC – Kukeltje Oct 25 '16 at 08:50
  • I found a comment in http://stackoverflow.com/questions/15265433/how-and-when-is-a-viewscoped-bean-destroyed-in-jsf telling "the view scoped managed bean will be garbaged and recreated". I want to understand, why the viewscoped bean is recreated before the view changes? – raho Oct 26 '16 at 05:27

0 Answers0