Primefaces - 用于dataTable中实时过滤的自定义组件

时间:2013-07-25 12:59:45

标签: jquery jsf-2 primefaces

PrimeFaces为p:dataTable做了很好的过滤器。从UX站点来看很棒,因为过滤器字段在列标题中,所以毫无疑问你要过滤什么,并且它正在工作 - 数据在你输入时会发生变化(好吧,只有你做了一个短暂的停顿,但是它在我的意见正是用户的期望)。

现在我想在标题中放置一些自定义内容作为过滤器。所以,我的想法是在标题facet中放置一个组件:

<p:column ...>
  <f:facet name="header">
     <some:myComponent onkeydown="filterAction()"/>
  </f:facet>
</p:column>

问题是filterAction不能更新整个dataTable组件(因为用户输入的组件将被重新创建),但它必须更新表体。

我认为我可以使用 PrimeFaces选择器(基于jQuery选择器)来实现,但根据主题How to update data rows only using a selector for dataTable?,这是不可能的。并且datatable.js包含专门的Ajax调用来实现它(在PrimeFaces 3.5中的行:839,发布):

    options.onsuccess = function(responseXML) {
        var xmlDoc = $(responseXML.documentElement),
        updates = xmlDoc.find("update");
        ....
        $this.tbody.html(content);

我的问题是,是否可以使用这样的单独过滤器组件,它只刷新表体,就像标准过滤器一样,而不深入PF内部并编写专门的AJAX处理程序?

当然,可以在dataTable之外进行过滤,但是会减少UX(现在使用我的应用程序的人就像当前的设计一样)。

2 个答案:

答案 0 :(得分:2)

可以使用facet将任何组件放入列标题中。但是,不能仅请求dataTable正文刷新。所以解决方案是,发送正常请求,但接管响应并在自定义代码部分处理它。

如果您创建类似的远程命令:

<p:remoteCommand id="refreshDataTable" name="refreshDataTable"
               actionListener="#{carTable.doFilter}" 
               update="dataTable" />

该命令的ID被发送到服务器。知道了,我们可以准备自定义的AJAX请求:

 var options = {
        source: 'main:tabView:refreshDataTable',
        update: carsTable.id,
        formId: carsTable.cfg.formId
}
options.onsuccess = customHandler
PrimeFaces.ajax.AjaxRequest(options);

其中customHandler代码如下所示:

var xml = $(resp.documentElement)
updates = xml.find('update')
for(var i=0; i < updates.length; i++) {
var update = updates.eq(i),
id = update.attr('id'),
content = update.text();
if(id == carsTable.id){
   var tbody = $(content).find('tbody')
   carsTable.tbody.html(tbody.html());
}
else {
   PrimeFaces.ajax.AjaxUtils.updateElement.call(this, id, content);
}
PrimeFaces.ajax.AjaxUtils.handleResponse.call(this, xml);
var paginator = carsTable.getPaginator();
if(paginator) {
    paginator.setTotalRecords(this.args.totalRecords);
}
if(carsTables.cfg.scrollable) {
    carsTable.alignScrollBody();
}
return true;

我们需要在Java代码中设置变量totalRecords:

    RequestContext context = RequestContext.getCurrentInstance();  
    context.addCallbackParam("totalRecords", filteredCars.size());  

答案 1 :(得分:0)

对于Primefaces 5,有一个新的属性filterFunction可以在Java代码中定义自定义过滤器:http://blog.primefaces.org/?p=3084

但是,过滤器输入仍然是输入文本中的字符串。

如果您需要一个自定义组件来输入过滤器值,或者您仍然坚持使用Primefaces 4(就像我最近的项目一样),我将描述对我有用的内容。

我使用这些关键步骤扩展了过滤行为

  • 将普通的JSF输入组件放入列的标题面,而不是使用filterBy属性
  • 将javascript回调附加到用户输入上触发的此组件,该组件调用PF(&#39; dataTableWidgetVar&#39;)。filter()
  • 将filteredValue属性添加到dataTable,它在现有过滤器之上的Java setter中应用自定义过滤器

关键是要利用filteredValue属性 - 当调用Primefaces filter()函数或者当primefaces过滤器更改时,filteredValue被设置为列出过滤值(如果没有应用过滤器,则为null)。然后Primefaces从getter读取filteredValues以更新dataTable中的项目列表。如果我们将过滤器置于这些调用之间(在getter或setter中,setter效率更高,因为只有在过滤器更改时才调用),我们使用过滤器修改原始过滤列表并通过getter返回。

一些代码:

使用inputText作为过滤器组件定义数据表:

<p:dataTable filteredValue="#{view.filteredResults} >
    ...
    <p:columnGroup type="header">
    ...
        <p:row>
    ...
           <p:column>
               <f:facet name="header">
                    <p:inputText value="#{view.filterValue}" />
                </f:facet>
           </p:column>

    ...
</p:dataTable>

在视图命名视图中的filteredRerults的Java Setter和Getter:

public void setFilteredResults(List<?> filteredResults) {
    this.filteredResults = applyPremiumFilters(filteredResults, filterValue);
}

public List<?> getFilteredResults() {
    return this.filteredResults;
}

其余是Javascript代码,用于在过滤器组件中的值更改时对dataTable应用过滤器。