Reputation: 1
I recently discovered Facelet tag files as an alternative to Composite Components, thanks to many stackoverflow answers written by BalusC, and have been using them to solve a problem with PrimeFaces dataTable. I want to standardize a bunch of the sundry attributes of p:dataTable into a component/facelet, however some attributes which I want to be optional, like 'selectionMode', cannot evaluate to empty string otherwise the component is broken (see http://forum.primefaces.org/viewtopic.php?f=3&t=29066). Using Facelet tag files and I have conditionally rendered alternate p:dataTables depending on which optional attributes are present.
However now I have a new problem with EL expressions of AjaxBehaviors nested in the dataTable.
Shortened example of /WEB-INF/tags/dataTable.xhtml:
<ui:composition>
<p:dataTable var="row"
value="#{value}"
filteredValue="#{state.filteredValue}"
first="#{state.first}"
rows="#{state.rows}">
<f:event type="preRenderComponent" listener="#{state.onPreRenderComponent}"/>
<p:ajax event="page" listener="#{state.onPage}"/>
<p:ajax event="sort" listener="#{state.onSort}"/>
<p:ajax event="filter" listener="#{state.onFilter}"/>
<ui:insert/>
</p:dataTable>
</ui:composition>
Example page utilizing the tag file:
<my:dataTable value="#{mybean.list}" state="#{mybean.state}">
<p:column headerText="Name"
sortBy="#{row.name}"
filterBy="#{row.name}">
#{row.name}
</p:column>
</my:dataTable>
It looks like my "state" expressions are processed fine up until the three p:ajax events are executed. The event is broken (i.e. paging/sorting ineffective) and the following stack trace is logged:
12:36:06,660 WARNING [javax.enterprise.resource.webcontainer.jsf.lifecycle] (http--0.0.0.0-8080-3) Target Unreachable, identifier 'state' resolved to null: javax.el.PropertyNotFoundException: Target Unreachable, identifier 'state' resolved to null
at org.apache.el.parser.AstValue.getTarget(AstValue.java:98) [jbossweb-7.0.13.Final.jar:]
org.apache.el.parser.AstValue.invoke(AstValue.java:244) [jbossweb-7.0.13.Final.jar:]
org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:278) [jbossweb-7.0.13.Final.jar:]
org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:39) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31]
org.primefaces.component.behavior.ajax.AjaxBehaviorListenerImpl.processCustomListener(AjaxBehaviorListenerImpl.java:70) [primefaces-3.5.jar:]
org.primefaces.component.behavior.ajax.AjaxBehaviorListenerImpl.processArgListener(AjaxBehaviorListenerImpl.java:59) [primefaces-3.5.jar:]
org.primefaces.component.behavior.ajax.AjaxBehaviorListenerImpl.processAjaxBehavior(AjaxBehaviorListenerImpl.java:47) [primefaces-3.5.jar:]
org.primefaces.event.data.SortEvent.processListener(SortEvent.java:45) [primefaces-3.5.jar:]
javax.faces.component.behavior.BehaviorBase.broadcast(BehaviorBase.java:106) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
When implemented as a Composite Component this problem doesn't exist, i.e. using #{cc.attrs.state} functions correctly with these AjaxBehaviors.
My understanding of the scope and lifecycle of Facelet tag files, their attributes and EL expressions is limited. Have I hit a bug with p:ajax or is my 'state' expression only valid during an earlier phase?
FYI, the "mybean" and "state" objects use CDI and CODI and are defined as follows:
@Named("mybean")
@ViewAccessScoped
@SuppressWarnings("serial")
public class MyBean implements Serializable {
private List<SomeEntiy> list;
@Inject
private DataTableState state;
public List<SomeEntity> getList() {
return list;
}
public DataTableState getState() {
return state;
}
// Details about loading the list hidden
}
...and...
@Dependent
@SuppressWarnings("serial")
public class DataTableState implements Serializable {
private final static Logger log = Logger.getLogger(DataTableState.class.getName());
private List<?> filteredValue;
private int first;
private int rows = 20;
private Map<String,String> filters = new HashMap<String,String>();
private ValueExpression sortBy;
private String sortOrder;
public List<?> getFilteredValue() {
return filteredValue;
}
public void setFilteredValue(List<?> filteredValue) {
this.filteredValue = filteredValue;
if (filteredValue == null && !filters.isEmpty()) {
if (log.isLoggable(Level.FINEST))
log.finest("setFilteredValue: Resetting filters");
filters.clear();
}
}
public int getFirst() {
return first;
}
public void setFirst(int first) {
this.first = first;
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
if (log.isLoggable(Level.FINEST))
log.finest("setRows: " + rows);
this.rows = rows;
}
public Map<String,String> getFilters() {
return filters;
}
public void onPreRenderComponent(ComponentSystemEvent event) {
DataTable source = (DataTable) event.getSource();
if (sortBy != null)
source.setValueExpression("sortBy", sortBy);
if (sortOrder != null)
source.setSortOrder(sortOrder);
}
public void onPage(PageEvent event) {
DataTable source = (DataTable) event.getSource();
first = source.getFirst();
}
public void onSort(SortEvent event) {
UIColumn column = event.getSortColumn();
sortBy = column.getValueExpression("sortBy");
if (event.isAscending())
sortOrder = "ascending";
else
sortOrder = "descending";
}
public void onFilter(FilterEvent event) {
Map<String,String> filters = event.getFilters();
this.filters.clear();
this.filters.putAll(filters);
}
}
Upvotes: 0
Views: 1145