简介
在许多情况下,Web应用必须显示一个及一个数据项,我们可以采用NetUI标签集中的repeater标签实现这一功能,该标签可方便的显示JSP要显示的数据集内容。简单说来,一个repeater就是一个标签,在给定数据集的情况下,该标签显示数据集中的每一个数据项内容。此外,开发人员还可控制repeater标签显示的内容,灵活呈现关系的、XML的以及许多其他各种类型的重复数据结构。
在这里,我们将要介绍repeater标签集。本文假定您熟悉WebLogic Workshop 8.1 UI数据绑定的基础知识。本文中引用的所有代码都在本文附件(点击此处下载)中。
一个简单的repeater
让我们来看一个简单的例子,其中的repeater用于将一个String数组中的各项以清单的方式在一个HTML页面上显示出来。
<ul>
<netui-data:repeater dataSource="{pageFlow.colors}">
<li><netui:label value="{container.item}"/></li>
</netui-data:repeater>
</ul>
[simple/unstructured.jsp]
|
在这个例子中,我们可以看到一个绑定到String数组的repeater标签,它使用一个NetUI表达式作为标签的dataSource属性的值。如果您不熟悉数据绑定,您可以参考《数据绑定101》这篇文档。数据绑定表达式引用了一个属性,该属性在与JSP相关的页面流上是可用的。repeater标签绑定到这个数组,并开始显示其内容。
repeater开始显示之后,它便为数组中的每一项显示一次它的主体。每一次经由主体时,当前的数据项便在带有名称项的容器数据绑定上下文中变为可用。在这个例子中,label标签使用表达式{container.item}来访问repeater的当前数据项,即数组中的一个String数据项。
结果是一个无序的HTML清单,它呈现为:
· Red
· Orange
· Yellow
· Green
· Blue
· Indigo
· Violet
· White
· Gray
· Black
因为在这个简单repeater的主体中,repeater标签集中没有其他的标签,这被称为非结构化的repeater。接下来,让我们看一个稍微 复杂的例子。
一个结构化的repeater
让我们来仔细看看上面这个简单的repeater,您可能注意到了,<ul>和</ul>标签在repeater外部被呈现为JSP中的文字正文。netui-data:repeater标签由三个部分构成,它们分别是header、item和footer标签。
这些标签相当简单;它们用于repeater主体内容的显示。在内容开始和结束的时候,header和footer标签分别针对每个repeater显示一次,而item标签则针对repeater数据集中的每一数据项被循环显示出来。稍稍修改一下上面的例子,我们可以产生同样的输出:
<netui-data:repeater dataSource="{pageFlow.colors}">
<netui-data:repeaterHeader>
<ul>
</netui-data:repeaterHeader>
<netui-data:repeaterItem>
<li>
<netui:label value="{container.item}"/>
</li>
</netui-data:repeaterItem>
<netui-data:repeaterFooter>
</ul>
</netui-data:repeaterFooter>
</netui-data:repeater>
[simple/structured.jsp]
|
结果与前面的HTML清单相同。
以这种方式使用时,这便是一个结构化的repeater,因为repeater所显示内容的结构受到了主体中的这些子标签的限制。正如您所想像的那样,以这种方式使用repeater在显示HTML表格时很有帮助。
容器绑定上下文
repeater主体内部的标签进行数据访问时,采用容器数据绑定上下文公开的信息。在Workshop 8.1中,repeater使用了下列属性:
|
属性名称
|
说明
|
|
container
|
如果存在的话,即为父repeater
|
|
index
|
当前项的索引
|
|
item
|
“当前的”数据项
|
我们已经了解到,当repeater用于显示数据集时,属性item被用于访问当前的数据项。这个标识符在非结构化的repeater中或在<netui-data:repeaterItem>标签中可用,因为数据集中的数据只能在这两种情况下才能呈现出来。在这个例子中,我们只显示了container.item本身,这是因为,在上述例子中,container.item只引用了一个简单的String型的数据,而不是一个复杂的数据类型如JavaBean。container.item还可以用于显示复杂的数据类型;下面给出了一个简单的例子,它显示了来自一个任务列表中的信息。
<td>
<netui:anchor action="details">
<netui:label value="{container.item.name}"/>
<netui:parameter name="taskId" value="{container.item.id}"/>
</netui:anchor>
</td>
[complex/index.jsp]
|
index属性可以被用于为数据集中的各项编号。例如:
<netui-data:repeaterItem>
<tr>
<td><netui:label value="{container.index}"/></td>
<td><netui:label value="{container.item}"/></td>
</tr>
</netui-data:repeaterItem>
[complex/containerIndex.jsp]
|
上述代码将显示出:
|
Index
|
Color
|
|
0
|
Red
|
|
1
|
Orange
|
|
2
|
Yellow
|
|
3
|
Green
|
|
4
|
Blue
|
注意,只有在某些特定的环境下,属性index才能够被POST为的惟一标识符,或者是在后续页面上标识出数据集中某一数据项项时使用。如果这种功能是必需的,那么数据集中的每一项都应该拥有它自己的状态和惟一标识符。例如,从Database Control中提取出来的有关产品的关系数据能够使用产品标识符作为惟一标识符。
container属性可以用于呈现来自父repeater的信息。当作为被嵌套标签的repeater在JSP中是结构化的,而且内部repeater需要访问或呈现来自外部repeater的数据时,这一点相当有用。例如:
<netui-data:repeaterItem>
<tr>
<td><netui:label value="{container.container.item.color}"/></td>
<td><netui:label value="{container.item}"/></td>
</tr>
</netui-data:repeaterItem>
[complex/containerParent.jsp]
|
上述代码将部分地呈现:
这里使用了一个表达式{container.container.item.color},从而将左边一栏中的颜色名称绑定到最外部repeater标签的值。
一个复杂的例子
让我们再看一个更复杂的情况。我们将显示来自一份任务列表(tasklist)中的XML文档的信息。该文档是通过一个在Schemas项目中定义的XML Schema生成的XMLBean来表示的;任务列表的简单实例文档已经位于WEB-INF/classes/xml目录中。如果您不熟悉XMLBean,那么请参考相关文档。或者你可以将XMLBean简单理解为处理XML文档数据的JavaBean。
示例XMLBean包含一个任务元素的列表,这些任务元素都包含任务的基本信息。id用于惟一地表示一个任务,而一个任务又具有一个所有者、任务描述、任务起始/结束日期。这里所描述的任务是比较简单的,我们将构建一个repeater,它将以彩色视图的方式呈现每一个任务,并且带有一些链接,这些链接指向的页面负责显示关于每个任务更加详细的内容。
为此,我们将要获得页面流的一个公共属性(任务列表),该repeater将直接绑定到的这个任务列表上。
<netui-data:repeater dataSource="{pageFlow.taskList.taskArray}">
[complex/index.jsp]
|
当用repeater来做显示时,它为任务列表的taskArray中的每个任务都显示一次其repeaterItem的主体。提请注意:任务列表与每个任务的详细描述信息视图之间的链接的那一栏,这在JSP中表示为:
<td>
<netui:anchor action="details">
<netui:label value="{container.item.name}"/>
<netui:parameter name="taskId" value="{container.item.id}"/>
</netui:anchor>
</td>
[complex/index.jsp]
|
URL链接到页面流的details动作(action)上,即搜索taskId参数的动作。这个值用于查找特定的任务,而动作则以转到包含详细信息的页面宣告结束。显然,在一个完整的Web应用中,还需要添加处理无效的订单标识符的代码,但是我们为了保持例子的简单性,就省略了这一步。
瞧!我们已经呈现了一个原始表的数据集及相关的详细信息。
高级显示功能
repeater标签集提供了两项高级显示功能——基于choice的项显示,以及项填充。
基于choice的显示
基于choice的显示允许repeater为每一项需特殊显示的数据项显示出不同的用户界面,即将显示的用户界面可能会因为特定项中包含数据的不同而显示的不同。
这是以一种特殊的方式来完成显示的处理——要么全部选中,要么全不被选中;处理时choice标签必须被完全包含在一个repeaterItem标签中,显示出被包含在起始choice标签和结束choice标签之间的内容,而且对于每一个显示项来说,只能有一个choice被显示出来。
这里给出了一个例子,它突出显示了一个已经超出预计的结束日期的to-do项。
<netui-data:choiceMethod method="isOverdue" object="{pageFlow}">
<netui-data:methodParameter value="{container.item.endDate}"/>
</netui-data:choiceMethod>
<!-- rendered if the current task's end date is past due -->
<netui-data:choice value="true">
<tr>
<td><netui:label value="{container.item.name}"/></td>
<td class="tablerow-error" colspan="3">
<netui:label value="Task past due; contact {container.item.owner}"/>
</td>
</tr>
</netui-data:choice>
<netui-data:choice default="true">
...
</netui-data:choice>
</netui-data:repeaterItem>
[advanced/choice.jsp]
|
在这里,netui-data:choiceMethod标签调用了页面流上的isOverdue方法,并传递每个任务的endDate作为其参数。结果是一个String,它与每个netui-data:choice标签的值都进行了比较。第一个匹配的choice标签被显示出来。如果没有找到相匹配的choice那就显示接下来的默认值为true的choice。
当这开始显示时,已经超过其结束日期的项将以红色背景显示出来:
这是一个简单的例子,但是用于显示不同的类别的数据项时,这功能相当有用。
填充
填充repeater标签用于从不规则数据中创建一个规则数据集。例如,假定有四个repeater必须在单个页面上呈现数据,而且为了保持页面的布局,呈现的尺寸需要相同,而如果数据集尺寸不同,这是不可能实现的。如果数据集没有达到最小尺寸或超出了最大尺寸,填充标签允许相应地填充或截断数据集。
现介绍repeater标签集的另一个标签:netui-data:pad。pad使用一个属性值或它的主体来构建空的模板文本,该模板文本在需要时将被重复进行显示,从而将项的数目增大到minRepeat个。下面给出了一个例子,“填充”任务列表,使其满足minRepeat=10的要求:
<netui-data:pad minRepeat="10">
<tr class="tablerow"><td colspan="4">Open Task Slot</td></tr>
</netui-data:pad>
[advanced/padding.jsp]
|
当这显示出来的时,任务列表的最后5个空位被“填充”:
提示与技巧
如何针对当前项编写scriptlet?
有时候,页面作者会遇到这样一种情况,即当创建丰富多样的Web用户界面时,NetUI标签库无法完成所有必需的任务。当需要在JSP页面中使用scriptlet时,可以使用netui-data:getData标签来取得repeater中的当前项。这个标签对一个NetUI表达式求值,并将结果对象放到PageContext中,在那里该对象可以通过页面上下文的属性映射被访问。例如,下面的代码将从颜色数组中取出当前String,而scriptlet则将直接呈现该标记:
<netui-data:repeater dataSource="{pageFlow.colors}">
<netui-data:getData resultId="currentColor" value="{container.item}"/>
<%
String color = (String)pageContext.getAttribute("currentColor");
out.write("<span style=\"width=75;background=" +
color +
";\">" + color + "</span><br/>");
%>
</netui-data:repeater>
[howdy/index.jsp]
|
在浏览器中看起来是这个样子:
如何显示repeater上的交替行样式?
因为repeater不显示任何它自己的标记,所以编写代码以显示repeater中的交替行样式的任务就落到了JSP页面的作者肩上。使用choice可以完成这个任务,但是除非每个行类型所展现的用户界面存在显著差异,否则choice可能造成大量的重复代码。
使用netui-data:getData标签和{container.index}表达式找到当前行的索引之后,scriptlet一行简单的代码可以用于呈现行的交替样式:
<tr class="<%=
((Integer)pageContext.getAttribute("currentIndex")).intValue()
% 2 == 0 ?
"tablerow" :
"tablerow-alt"
%>">
[howdoi/index.jsp]
|
结果是一个具有交替行样式的表,如下图所示:
注意,currentIndex引用的值的类型是Integer。因为PageContext的属性映射只能保存对象类型,所以netui-data:getData标签引用的所有原始类型都可以用作它们的原始包装类型。
一个JSP文件使用了repeater choice标签,而现在页面太长,导致页面不被编译。我应该怎么办呢?当每个choice的主体太长或者存在许多更短的choice主体时,上述情况就可能会发生。这个问题的原因是生成的页面有太多行需要编译。针对这个问题的一种解决方案是,查看每个choice的主体,了解它们之中是否存在重复的JSP/HTML段。如果存在,那么考虑使用一个不同的方法来进行数据的显示。
另一种解决方案是将页面分解为几个页面,与分解前的页面相比,分解后的页面可以显示更多详细信息。
结束语
在本文中,我们考察了repeater标签集的功能,该标签集可以用于将简单的数组表示为列表、表或者其他复杂的标记结构。这对于您开始使用repeater显示数据集很可能极有帮助。 |