`
从此醉
  • 浏览: 1045127 次
  • 性别: Icon_minigender_1
  • 来自: US
社区版块
存档分类
最新评论

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

 
阅读更多

现在来看看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的缺陷。


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics