Visualforce-基础

Salesforce Visualforce (基础7)标准列表控制器

学习目标

完成本单元后,您将能够:

  • 解释Visualforce标准列表控制器是什么以及它与标准(记录)控制器有什么不同。
  • 列出标准列表控制器提供的与标准控制器不同的三个操作。
  • 在Visualforce页面上使用标准列表控制器显示记录列表。
  • 定义分页,并能够将其添加到Visualforce页面。

标准列表控制器简介

标准列表控制器允许您创建可以显示或执行一组记录的Visualforce页面。
显示记录列表是几乎所有Web应用程序的基本行为。 Visualforce使得显示相同类型的记录列表非常容易,只需使用标记,不需要后端代码。秘密,像往常一样,是标准的控制器,在这种情况下,标准的列表控制器。

标准列表控制器提供了许多强大的自动行为,例如查询特定对象的记录以及使集合变量中的记录可用,以及通过结果过滤和分页。将标准列表控制器添加到页面与添加标准(记录)控制器非常相似,但意图同时处理多条记录,而不是一次记录一条记录。

显示记录列表

使用标准列表控制器和迭代组件(如<apex:pageBlockTable>)来显示记录列表。
标准(记录)控制器可以轻松地将单个记录加载到您可以在Visualforce页面上使用的变量中。标准列表控制器是相似的,除了单个记录之外,它将记录的列表或集合加载到变量中。

因为你正在处理一个集合,而不是一个单独的记录,你需要使用一个迭代组件来显示它们。一个迭代组件与一组相似的项目一起工作,而不是一个单一的值。一个迭代组件循环遍历其集合,并且对于每个记录,基于作为组件标记的一部分提供的模板生成一些输出。这听起来很复杂,但是当你阅读标记时你会很快理解它。

使用标准列表控制器的标记与使用标准的一次一个记录控制器的标记几乎相同。为了显而易见,以下示例中以粗体突出显示了主要区别。

  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。输入ContactList作为页面名称。
  2. 在编辑器中,用以下替换标记。
    <apex:page standardController="Contact" recordSetVar="contacts">
        <apex:pageBlock title="Contacts List">
            
            <!-- Contacts List -->
            <apex:pageBlockTable value="{! contacts }" var="ct">
                <apex:column value="{! ct.FirstName }"/>
                <apex:column value="{! ct.LastName }"/>
                <apex:column value="{! ct.Email }"/>
                <apex:column value="{! ct.Account.Name }"/>
            </apex:pageBlockTable>
            
        </apex:pageBlock>
    </apex:page>
  3. 点击预览打开您的页面的预览,您可以在进行更改时查看。
    应打开一个新窗口,显示标准Salesforce页面标题和侧栏元素以及联系人列表。

    A list of contacts from the standard list controller

使用标准列表控制器与使用标准控制器非常相似。首先在<apex:page>组件上设置standardController属性,然后在同一个组件上设置recordSetVar属性。标准控制器属性设置对象使用,就像标准控制器一样。 recordSetVar设置要创建的变量的名称与记录的集合,在这里{!联系人}。按照惯例,这个变量通常被命名为对象名称的复数。

<apex:pageBlockTable>是一个迭代组件,用于生成一个数据表,并附有平台样式。这是表格标记中发生的事情。

  • 将<apex:pageBlockTable>的值属性设置为由标准列表控制器加载的变量{!联系人}。这是<apex:pageBlockTable>将使用的记录列表。
  • 对于该列表中的每个记录,一次一条记录<apex:pageBlockTable>将该记录分配给<apex:pageBlockTable>的var属性中指定的变量。在这种情况下,该变量被命名为ct。
  • 对于每个记录,<apex:pageBlockTable>使用由<apex:pageBlockTable>主体内的<apex:column>组合集定义的行在表中构造一个新行。 <apex:column>组件依次使用表示当前记录的ct变量来提取该记录的字段值。
  • 在循环之外,<apex:pageBlockTable>使用<apex:column>组件中的字段通过查找每个字段的标签来创建列标题。

这是非常重要的,迭代组件是第一次很难理解。你现在可以做的最好的事情是尝试创建你自己的。选择你想在表格中显示的字段。查找<apex:pageBlockTable>和<apex:column>的不同属性,并进行试验,直到您感觉舒适。您也可以尝试使用其他一些迭代组件,例如<apex:dataList>甚至是<apex:repeat>。

添加列表视图过滤到列表

使用 {! listViewOptions}来获取可用于对象的列表视图过滤器的列表。使用 {! filterId}设置列表视图过滤器用于标准列表控制器的结果。
标准列表控制器提供了许多可用于更改列表显示的功能。其中最强大的是列表视图过滤器。您可以声明式地创建列表视图过滤器,使用点击代替代码,标准列表控制器允许您使用页面上任何已定义的列表视图过滤器。

  1. 将整个<apex:pageBlock>包装在<apex:form>标记中。
    要更改标准列表控制器的列表视图过滤器,您需要将新值提交回服务器。执行此提交的标准方法是使用使用<apex:form>组件创建的表单。
  2. 在<apex:pageBlock>标签中添加以下属性。
    id="contacts_list"
    这给了<apex:pageBlock>一个“名字”,我们可以使用它来获得一个很酷的Ajax效果,我们稍后会解释一下。
  3. 打开<apex:pageBlock>标记后,在<apex:pageBlockTable>上方,添加以下标记。
    Filter: 
    <apex:selectList value="{! filterId }" size="1">
        <apex:selectOptions value="{! listViewOptions }"/>
        <apex:actionSupport event="onchange" reRender="contacts_list"/>
    </apex:selectList>
    您的页面的完整代码应该是这样的。
    <apex:page standardController="Contact" recordSetVar="contacts">
        <apex:form>
    
            <apex:pageBlock title="Contacts List" id="contacts_list">
            
                Filter: 
                <apex:selectList value="{! filterId }" size="1">
                    <apex:selectOptions value="{! listViewOptions }"/>
                    <apex:actionSupport event="onchange" reRender="contacts_list"/>
                </apex:selectList>
    
                <!-- Contacts List -->
                <apex:pageBlockTable value="{! contacts }" var="ct">
                    <apex:column value="{! ct.FirstName }"/>
                    <apex:column value="{! ct.LastName }"/>
                    <apex:column value="{! ct.Email }"/>
                    <apex:column value="{! ct.Account.Name }"/>
                </apex:pageBlockTable>
                
            </apex:pageBlock>
    
        </apex:form>
    </apex:page>
    一个新的过滤器控件出现在列表上方。
    Contacts list with list views filter
  4. 从菜单中选择一个不同的过滤器。联系人列表发生了什么?

从刚刚创建的“滤镜”菜单中进行新选择时,应该注意两点。首先,当您选择一个新的过滤器时,记录列表会发生变化。 (您可能需要尝试几个不同的选项,在标准DE组织中使用示例数据时,某些列表视图将显示相同的记录。)

其次,更微妙的是,该列表正在更新,无需重新加载整个页面。这个“Ajax”效果是由<apex:actionSupport>组件中的reRender =“contacts_list”属性提供的。组件和reRender的联合作用是仅更新reRender属性中指定的页面部分。由于您已将id =“contacts_list”添加到<apex:pageBlock>,因此操作完成后,只更新<apex:pageBlock>,而不重新加载整个页面。

此页面上新功能的完整生命周期就像这样。

  • 当页面加载时,<apex:selectList>通过从{!中获取列表来构建可用过滤器的菜单。 listViewOptions}表达式。 listViewOptions是由标准列表控制器提供的属性。
  • 当您从菜单中选择新选项时,onchange:event将由<apex:actionSupport>组件触发。
  • 当onchange激发时,页面通过将新项目提交给在<apex:selectList>中设置的filterId属性来提交选定的新列表视图。
  • 当属性更新时,页面从服务器获得一个新的响应,在contacts变量中有一个新的匹配记录集合。
  • 但是因为<apex:actionSupport>指定仅渲染页面的一部分,所以页面使用Ajax异步JavaScript更新,而不是整页重新加载。

最终结果是,只需添加几行标记即可获得复杂而复杂的行为。

将分页添加到列表中

使用标准列表控制器的分页功能,允许用户一次查看一个“页面”的长记录列表。
到目前为止,您开发的功能非常好,并且可以很好地处理在Developer Edition组织中作为样本数据提供的记录的简短列表。但是当你拥有一个真正的组织,拥有数百甚至数千甚至数百万条记录时会发生什么?在一个页面上查看它们并不是很好!

实际上,默认情况下,标准列表控制器仅显示符合过滤条件的前20条记录(如果有的话)。你怎么能让人们访问超过前20条记录,或每页更多的记录,而不仅仅是20?

答案是分页。这是一个标准的Web应用程序用户界面元素,它允许您一次使用“下一个”和“上一个”链接一次向前和向后浏览一长串记录,即“页面”。您可以使用标准列表控制器将其添加到您的页面,以及方便程度(如进度指示器和菜单)来更改每页的记录数。

  1. 在联系人列表<apex:pageBlockTable>下方,添加以下标记。
    <!-- Pagination -->
    <table style="width: 100%"><tr>
    
        <td>
            <!-- Page X of Y -->
        </td>            
    
        <td align="center">
            <!-- Previous page -->
            <!-- Next page -->
        </td>
        
        <td align="right">
            <!-- Records per page -->
        </td>
    
    </tr></table>
    
    这将创建一个HTML表格,它将包含要添加的三个分页控件。

    注意

    在真实的网页中,您可能会使用更多的语义标记和单独的样式,但是现在,简单的HTML是简洁明了的。

  2. <!– Page X of Y –>替换为以下标记
    Page: <apex:outputText 
        value=" {!PageNumber} of {! CEILING(ResultSize / PageSize) }"/>
    这会将进度指示器添加到列表中,指示用户正在查看哪个页面,以及有多少人在那里。如果你在DE组织中尝试这个,可能会说“第1页,共1页”。
  3. 用下面的标记替换<! – 上一页 – >和<! – 下一页 – >注释行。
    <!-- Previous page -->
    <!-- active -->
    <apex:commandLink action="{! Previous }" value="« Previous"
         rendered="{! HasPrevious }"/>
    <!-- inactive (no earlier pages) -->
    <apex:outputText style="color: #ccc;" value="« Previous"
         rendered="{! NOT(HasPrevious) }"/>
    
    &nbsp;&nbsp;  
    
    <!-- Next page -->
    <!-- active -->
    <apex:commandLink action="{! Next }" value="Next »"
         rendered="{! HasNext }"/>
    <!-- inactive (no more pages) -->
    <apex:outputText style="color: #ccc;" value="Next »"
         rendered="{! NOT(HasNext) }"/>
    这个标记提供页面上的上一个和下一个链接。标记包含两种可能性:当在给定方向上有更多记录要查看时,则链接处于活动状态;并且当给定方向上没有更多页面时,该链接被禁用。
  4. 用下面的标记替换<! – 记录每页 – >注释行。
    Records per page:
    <apex:selectList value="{! PageSize }" size="1">
        <apex:selectOption itemValue="5" itemLabel="5"/>
        <apex:selectOption itemValue="20" itemLabel="20"/>
        <apex:actionSupport event="onchange" reRender="contacts_list"/>
    </apex:selectList>
    这个标记提供了一个菜单来改变每页记录的数量。这里我们只添加了一个选项,可以在页面上显示更少的记录。从列表中选择“5”,看看列表和其他控件发生了什么。
结果是一个列表页面,具有相当多的标准列表控制器提供的功能。

Contacts list with pagination controls

在进度指示器中,有三个属性用于指示有多少页:PageNumber,ResultSize和PageSize。最后两个实际用于公式表达式,将数字四舍五入到最接近的整数。这可以防止指标说一些无意义的东西,比如“1.6的第2页”。

在分页控件中,<apex:commmandLink>组件引用标准列表控制器Previous和Next提供的两个操作方法。结果是执行“上一个”或“下一个”操作的链接。

但是,这个呈现的属性是什么,有如{! HasPrevious}?这是Visualforce使您能够有条件地显示组件的方式,也就是说,取决于布尔表达式的结果。这里的页面标记是引用由标准列表控制器HasPrevious和HasNext提供的布尔属性,它让你知道在给定的方向上是否有更多的记录。通过在呈现属性中使用表达式,可以在页面上显示或隐藏该组件的结果。这是上次链接在第一次加载页面时变灰的方法,但是如果您通过单击“下一步”链接前进,则“前一个”链接变为活动状态。

每个页面选择菜单的记录使用了前面使用过的<apex:selectList>,但不是调用控制器方法来获取菜单值,而是使用<apex:selectOption>元素来获取所需的值。同样,<apex:actionSupport>标签会导致菜单在所选值更改时触发其操作,并且会再次使用reRender =“contacts_list”更新<apex:pageBlock>。这里的新部分是<apex:selectList>设置标准列表控制器的PageSize属性。

告诉我更多…

标准列表控制器提供了许多在网络应用程序中常见的功能,这里已经涵盖了许多功能。
例如,除了一次往回移动一页的“上一页”和“下一页”操作之外,还有第一个和最后一个操作将转到记录列表的开头或结尾。

在标记的背后,标准列表控制器基于StandardSetController Apex类。您可以在Force.com Apex Code开发人员指南中阅读更多关于它以及它提供的所有功能。

房间里有一头小象,我们在这里创建的例子,它的名字是排序。通常需要为列表设置默认的排序顺序,并且还需要具有排序影响的列标题,以便您即时更改排序顺序。简单的事实是,您无法单独使用Visualforce来影响排序顺序。尽管支持排序和可点击列标题所需的附加Visualforce标记和Apex代码量并不是很大,但它确实需要自定义代码。查看一些起点的附加资源。

你可能也会喜欢...