0

我最近发现了 Facelet 标记文件作为复合组件的替代品,这要归功于 BalusC 编写的许多 stackoverflow 答案,并且一直在使用它们来解决 PrimeFaces 数据表的问题。我想将 p:dataTable 的一堆杂项属性标准化为一个组件/facelet,但是一些我希望是可选的属性,比如“selectionMode”,不能评估为空字符串,否则组件会被破坏(参见http:/ /forum.primefaces.org/viewtopic.php?f=3&t=29066)。使用 Facelet 标记文件,我根据存在的可选属性有条件地呈现了备用 p:dataTables。

但是现在我对嵌套在 dataTable 中的 AjaxBehaviors 的 EL 表达式有一个新问题。

/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>

使用标签文件的示例页面:

<my:dataTable value="#{mybean.list}" state="#{mybean.state}">
  <p:column headerText="Name"
            sortBy="#{row.name}"
            filterBy="#{row.name}">
    #{row.name}
  </p:column>
</my:dataTable>

看起来我的“状态”表达式处理得很好,直到三个 p:ajax 事件被执行。事件被破坏(即分页/排序无效)并记录以下堆栈跟踪:

  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]

当实现为复合组件时,不存在此问题,即正确使用#{cc.attrs.state} 函数与这些AjaxBehaviors。

我对 Facelet 标记文件的范围和生命周期、它们的属性和 EL 表达式的理解是有限的。我是否遇到了 p:ajax 的错误,或者我的“状态”表达式仅在早期阶段有效?

仅供参考,“mybean”和“state”对象使用 CDI 和 CODI,定义如下:

@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

}

...和...

@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);
    }

}
4

0 回答 0