64. XPages自定义控件(三)高级搜索之二

来源:互联网 发布:淘宝运营外包公司 编辑:程序博客网 时间:2024/06/06 01:45

现在来看看63. XPages自定义控件(三)高级搜索之一中提到的RecordView自定义控件的代码。从控件的设计视图自上而下可以看到用于条件查询的控件、一个向用户反馈操作消息的Message自定义控件、常见的视图操作的几个按钮和一个XPages自带的视图控件。

 
RecordView控件的设计界面
RecordView控件从功能上分成的这四个部分,我们来一一检视:

用于条件查询的控件

RecordView控件上的多条件查询包括员工姓名和打卡的起始日期。员工姓名的输入又采用了另一个自定义控件InputUser,在用户键入姓名时提供员工姓名列表的辅助输入(type ahead)。InputUser控件的界面代码如下:
<?xml version="1.0" encoding="UTF-8"?><xp:view xmlns:xp="http://www.ibm.com/xsp/core"    style="display:inline; ">    <xp:inputText id="Users" style="float:none;width:auto">        <xp:typeAhead mode="full" minChars="1" ignoreCase="true"            id="typeAhead1">            <xp:this.valueList><![CDATA[${app.usersOptions}]]></xp:this.valueList>        </xp:typeAhead>    </xp:inputText></xp:view>

辅助输入的值列表用表达式语言(expression language)设置,来自一个类名为starrow.xsp.App的managed bean的getUsersOptions()方法:

public List getUsersOptions() throws NotesException{        Vector result=new Vector();        try {            //获得HR数据库的路径            String path = getHRDBPath();            //XSPUtil是笔者编写的一个包含很多常用方法的工具类。            Database db=XSPUtil.getDatabase(path);            result=db.getView("bySCRO").getColumnValues(1);        } catch (NotesException e) {            if (e.id==NotesError.NOTES_ERR_DBNOACCESS){                XSPUtil.feedback(e.text);            }else{                throw e;            }        }        return result;    }
起始日期使用了两个XPages日期控件。其后的三个按钮,一个是用于测试,读取和显示从InputUser控件获得的用户名,另两个分别用于搜索和清除结果,XPage的代码片断如下:
<xp:button value="Search" id="btnSearch">    <xp:eventHandler event="onclick" action="#{app.search}"        submit="true" refreshMode="complete">    </xp:eventHandler></xp:button><xp:button value="Clear" id="button1">    <xp:eventHandler event="onclick" action="#{app.clearSearch}"        submit="true" refreshMode="complete">    </xp:eventHandler></xp:button>
可以看到两个按钮的onclick事件的响应程序也都是用表达式语言绑定到同一个managed bean里,不同的是这里采用的是表示动态计算的#符号而不是上面的InputUser控件用到的设定页面载入时记算的$符号,这并不是笔者的有意选择,而是因为如果选择更高效的页面载入时计算,XPages会报错。
    public void search(){        //获得XPages视图控件        XspViewPanel viewPanel1 = (XspViewPanel) JSFUtil.findComponent("viewPanel1");        //获得视图控件绑定的的数据源        DominoViewData vd=(DominoViewData) viewPanel1.getData();        //为方便构造查询条件,创建一个字符串的Collection        Collection<String> filters=new Vector<String>();        String filter="";        //获得RecordView自定义控件        UIIncludeComposite cc=(UIIncludeComposite) JSFUtil.findComponent("recordView1");        //cc.getPropertyMap().getString("filter")        //com.ibm.xsp.FacesExceptionEx: Null value for composite component property filter        //如果设置了该控件的filter属性,则将属性值添加到查询条件里。        if (cc.getPropertyMap().get("filter")!=null){            filters.add("("+cc.getPropertyMap().get("filter")+")");            }        //获得输入起始时间的编辑框        XspInputText inpFrom=(XspInputText) JSFUtil.findComponent("inpFrom");        //获得起始时间值,格式化,并用它构造出用于全文搜索的语句        if (inpFrom.getValue()!=null && !inpFrom.getValue().equals("")){            SimpleDateFormat df=new SimpleDateFormat("MM/dd/yy");            Date from=(Date) inpFrom.getValue();            filters.add("([AccessTime]>="+df.format(from)+")");        }        //类似地处理结束时间        XspInputText inpTo=(XspInputText) JSFUtil.findComponent("inpTo");        if (inpTo.getValue()!=null && !inpTo.getValue().equals("")){            SimpleDateFormat df=new SimpleDateFormat("MM/dd/yy");            Date to=(Date) inpTo.getValue();            filters.add("([AccessTime]<="+df.format(to)+")");        }        //获得输入用户的编辑框,构造出查询语句        XspInputText inpUser=(XspInputText) JSFUtil.findComponent("Users");        if (!inpUser.getValue().equals("")){            filters.add("([StaffName]="+inpUser.getValueAsString()+")");        }        //合并出最终的查询语句,传递给Message自定义控件        filter=starrow.Commons.join(filters, " & ");        XSPUtil.getRequestMap().put("message", filter);        //设置数据源的搜索条件,即搜索。        vd.setSearch(filter);    }    public void clearSearch(){        //清空各个输入查询条件的编辑框        ((XspInputText) JSFUtil.findComponent("inpFrom")).setValue("");                ((XspInputText) JSFUtil.findComponent("inpTo")).setValue("");                ((XspInputText) JSFUtil.findComponent("Users")).setValue("");        //调用搜索方法        this.search();    }

Message自定义控件

15. 如何在XPages中提示操作成功一文里介绍了在XPages中向用户提供操作结果反馈的两类方式,其中的第二种方式——在页面的某个部分显示消息——是现在流行的风格。很容易将这项功能封装在一个自定义控件里,这样在任何页面也只需在想要的位置放置,再在运行业务逻辑结束后将给用户的提示传递到指定的RequestScope的Message变量就可以了。上面的search()方法就运用了这一点。
<?xml version="1.0" encoding="UTF-8"?><xp:view xmlns:xp="http://www.ibm.com/xsp/core">    <xp:text escape="true" id="message" value="#{requestScope.message}"        style="background-color:rgb(255,255,0)">    </xp:text></xp:view>
反馈信息的格式,如字体、颜色和背景等都可以在控件里预先设置,整个应用程序里各处的反馈信息自动具有了统一的风格。

常见的视图操作的几个按钮

这些按钮是刷新、新建和删除,是最常见的视图操作。普通的刷新只需要用JavaScript重新载入当前页面或者在XPages的语境下提交一个空操作。而我们这里的RecordView控件显示的不是一个Notes视图而是一个视图的全文搜索的结果,所以在点击刷新按钮时还更新了数据库的全文索引。
<xp:button value="Refresh" id="button5">    <xp:eventHandler event="onclick" submit="true" refreshMode="complete">        <xp:this.action><![CDATA[#{javascript:database.updateFTIndex(false);}]]></xp:this.action>    </xp:eventHandler></xp:button>
新建按钮使用浏览器端JavaScript打开一个新页面。
<xp:button value="New" id="button3" rendered="true">    <xp:eventHandler event="onclick" submit="false">        <xp:this.script><![CDATA[window.open("record.xsp", "_blank");]]></xp:this.script>    </xp:eventHandler></xp:button>
删除按钮为了简单直接调用了XPages提供的删除文档的简单操作(simple action)。
<xp:button value="Delete" id="button4"><xp:eventHandler event="onclick" submit="true" refreshMode="complete">        <xp:this.action>            <xp:deleteSelectedDocuments view="viewPanel1"                message="Are you sure to delete the selected records?">            </xp:deleteSelectedDocuments>        </xp:this.action></xp:eventHandler></xp:button>

XPages视图控件

这个视图控件的设置和普通页面上的没有什么区别,除了其中的数据源和视图列的viewName、search、showCheckbox等属性绑定到了RecordView控件的自定义属性。
    <xp:viewPanel rows="20" id="viewPanel1" viewStyle="width:99%"        pageName="/record.xsp">        <xp:this.facets>            <xp:pager partialRefresh="true" layout="Previous Group Next"                xp:key="headerPager" id="pager1">            </xp:pager>            <xp:pager partialRefresh="true" layout="Previous Group Next"                xp:key="footerPager" id="pager2">            </xp:pager>        </xp:this.facets>        <xp:this.data>            <xp:dominoView var="view1"                viewName="${javascript:compositeData.notesView;}"                search="#{javascript:compositeData.filter;}" sortOrder="descending"                sortColumn="$8">            </xp:dominoView>        </xp:this.data>        <xp:viewColumn id="viewColumn8" columnName="$8"            showCheckbox="${javascript:compositeData.showEdit}">            <xp:this.displayAs><![CDATA[${javascript:if (compositeData.showEdit) return "link";}]]></xp:this.displayAs>            <xp:this.facets>                <xp:viewColumnHeader xp:key="header"                    id="viewColumnHeader8" value="Date">                </xp:viewColumnHeader>            </xp:this.facets>            <xp:this.converter>                <xp:convertDateTime type="date"></xp:convertDateTime>            </xp:this.converter>        </xp:viewColumn>        <xp:viewColumn columnName="StaffName" id="viewColumn4">            <xp:viewColumnHeader value="Staff Name"                id="viewColumnHeader4">            </xp:viewColumnHeader>        </xp:viewColumn>        <xp:viewColumn columnName="AccessTime" id="viewColumn1">            <xp:this.converter>                <xp:convertDateTime type="time"></xp:convertDateTime>            </xp:this.converter>            <xp:viewColumnHeader value="Access Time"                id="viewColumnHeader1">            </xp:viewColumnHeader>        </xp:viewColumn>        <xp:viewColumn id="viewColumn9" columnName="Type">            <xp:this.facets>                <xp:viewColumnHeader xp:key="header"                    id="viewColumnHeader9" value="Type">                </xp:viewColumnHeader>            </xp:this.facets>        </xp:viewColumn>        <xp:viewColumn columnName="CardNo" id="viewColumn2"            rendered="false">            <xp:viewColumnHeader value="Card Number"                id="viewColumnHeader2">            </xp:viewColumnHeader>        </xp:viewColumn>        <xp:viewColumn columnName="StaffNo" id="viewColumn3"            rendered="false">            <xp:viewColumnHeader value="Staff Number"                id="viewColumnHeader3">            </xp:viewColumnHeader>        </xp:viewColumn>        <xp:viewColumn columnName="Department" id="viewColumn5">            <xp:viewColumnHeader value="Department"                id="viewColumnHeader5">            </xp:viewColumnHeader>        </xp:viewColumn>        <xp:viewColumn columnName="Office" id="viewColumn7">            <xp:viewColumnHeader value="Office"                id="viewColumnHeader7">            </xp:viewColumnHeader>        </xp:viewColumn>    </xp:viewPanel>

自定义属性

在63. XPages自定义控件(三)高级搜索之一里,我们看到使用RecordView控件的几个页面在操作和视图显示上都有不同,在异常记录和考勤记录页面上可以使用条件查询,在补卡记录页面上可以新建和选择、删除记录。这些差异都是靠RecordView控件的自定义属性控制的。同理,决定控件展示的文档列表的Notes视图名和全文搜索的语句也是由自定义属性传递。
 

RecordView控件的自定义属性的设计视图

比如在显示考勤记录的页面里,关于RecordView控件的代码如下:

<xc:RecordView id="recordView1" notesView="vwRecord"showSearch="${javascript:app.isAdmin()}"><xc:this.filter><![CDATA[${javascript:var filter="[Type] is present";if (!app.isAdmin()){filter+=" & [StaffName]=" + context.getUser().getCommonName();}return filter;}]]></xc:this.filter></xc:RecordView>

在显示补卡记录的页面里,传递给RecordView控件的属性值就有了变化:

<xc:RecordView id="recordView1" notesView="vwRecord"showSearch="${javascript:false;//app.isAdmin()}" showLink="true"showCheckbox="true" showEdit="${javascript:app.isAdmin()}"><xc:this.filter><![CDATA[${javascript:var filter="[MakeUp]=1";if (!app.isAdmin()){filter+=" & [StaffName]=" + context.getUser().getCommonName();}return filter;}]]></xc:this.filter></xc:RecordView>
app.isAdmin()是managedbean里一个判断当前用户是否管理员的方法,如果是则显示所有员工的信息,否则只显示当前用户自己的信息。

RecordView控件的各个组成部分都已介绍完毕,下一篇文章会给出它们的完整代码,并介绍使用这个自定义控件遇上的问题和反映出来的XPages的缺陷。


原创粉丝点击