Salesforce Visualforce (基础9)自定义控制器

学习目标

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

  • 解释一下自定义控制器是什么,并描述其关键属性。
  • 创建一个自定义控制器类。
  • 在Visualforce页面上使用自定义控制器。

自定义控制器介绍

自定义控制器包含可由Visualforce页面使用的自定义逻辑和数据操作。例如,自定义控制器可以检索要显示的项目列表,向外部Web服务发出调用,验证和插入数据等等,并且所有这些操作都将可用于Visualforce页面,该页面将其用作控制器。
在其他地方介绍了Visualforce如何支持用于构建Web应用程序的模型 – 视图 – 控制器(MVC)设计模式。控制器通常检索要在Visualforce页面中显示的数据,并包含响应页面操作而执行的代码(如正在单击的按钮)。当您使用标准控制器时,平台为您提供了大量的标准功能。

但是一个尺寸并不适合所有的,并不是所有的网络应用程序都是“标准的”。当你想覆盖现有的功能,通过应用程序自定义导航,使用标注或Web服务,或者如果你需要更好地控制信息的访问方式对于您的页面,Visualforce可让您占据统治地位。您可以使用Apex编写自定义控制器,并从头到尾完全控制您的应用逻辑。

创建一个使用自定义控制器的Visualforce页面

通过在<apex:page>控制器属性中引用控制器类的名称,将自定义控制器添加到Visualforce页面。
当您的页面使用自定义控制器时,不能使用标准控制器。页面使用不同的属性来设置自定义控制器。
  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。输入ContactsListController作为页面名称。
  2. 在编辑器中,用以下替换标记。
    <apex:page controller="ContactsListController">
        <apex:form>
            <apex:pageBlock title="Contacts List" id="contacts_list">
                
                <!-- Contacts List goes here -->
    
            </apex:pageBlock>
        </apex:form>
    </apex:page>
    当你试图保存这个页面时,你会得到一个错误,因为ContactsListController还不存在。不用担心,接下来我们会解决这个问题。

创建一个自定义控制器Apex类

自定义控制器只是一个Apex类,您可以使用Developer Console编写自己的类。
有许多系统和实用程序类可以帮助您编写自定义控制器逻辑,但将类用作自定义控制器的唯一要求是它存在。
  1. 打开开发者控制台,然后点击 File | New | Apex Class 创建一个新的Apex类。输入ContactsListController作为类名。
  2. 在编辑器中,用以下代码替换任何代码。
    public class ContactsListController {
    
        // Controller code goes here
    
    }
    与Visualforce页面一样,当您更改时,您需要保存对Apex的更改。
    这并不多,而且还没有做任何事情,但它确实使错误消失在Visualforce页面上。所以…
  3. 切换回Visualforce页面并再次保存。
    错误信息应该消失,页面成功保存。
  4. 点击预览打开您的页面的预览,您可以在进行更改时查看。
    应该打开一个新窗口,显示标准的Salesforce页面标题和侧边栏元素,但没有内容。

乍一看,你创建的这两个新项目看起来并不是很有趣。但是即使它们是90%的占位符代码,Visualforce页面和Apex控制器这两个项目也是相互关联的。只要你添加更多的代码到控制器,你的页面就可以使用它。

超越基础

您可能已经注意到,这个自定义控制器类不会从另一个类继承,也不会实现一个有希望符合Visualforce控制器要求的接口。即使是复杂的控制器也不会做这些事情,因为没有任何这样的类继承或接口实现。这使您可以自由地创建自己的类和接口,随着您对Apex的经验的增加。

添加一个方法来检索记录

创建一个运行SOQL查询的getter方法,该查询返回要在页面上显示的记录。
大多数控制器的主要目的是检索显示数据或处理数据更新。在这个简单的控制器中,您只需运行一个基本的SOQL查询来查找联系人记录,然后使这些记录可用于Visualforce页面。
  1. 在ContactsListController类中,用下面的代码替换// Controller代码在这里注释行。
    private String sortOrder = 'LastName';
        
    public List<Contact> getContacts() {
        
        List<Contact> results = Database.query(
            'SELECT Id, FirstName, LastName, Title, Email ' +
            'FROM Contact ' +
            'ORDER BY ' + sortOrder + ' ASC ' +
            'LIMIT 10'
        );
        return results;
    }
    此代码添加一个私有成员变量,一个名为sortOrder的字符串和一个公共方法getContacts()。 sortOrder很容易理解,它只是通过排序联系人的字段的名称。
    getContacts()也是相当简单的,但是如果你以前没有见过Apex,可能起初很难解析。该方法的作用是执行SOQL查询以获取联系人记录列表,然后将该联系人列表返回给方法调用者。来电者是谁?当然是Visualforce页面!
  2. 在ContactsListWithController页面中,将<! – 联系人列表转到这里 – >注释行替换为以下标记。
    <!-- Contacts List -->
    <apex:pageBlockTable value="{! contacts }" var="ct">
    
        <apex:column value="{! ct.FirstName }"/>
        <apex:column value="{! ct.LastName }"/>
        <apex:column value="{! ct.Title }"/>
        <apex:column value="{! ct.Email }"/>
        
    </apex:pageBlockTable>
    当您保存此页面时,您应该看到一张熟悉的联系信息表格。
    A contacts list backed by a custom controller

ContactsListWithController页面的标记应该看起来相当熟悉。除了<apex:page>标签的控制器属性之外,它与用标准控制器创建页面的代码大致相同。

不同的是当{!联系人}表达式进行评估。在此页面上,Visualforce将该表达式转换为对控制器的getContacts()方法的调用。该方法返回联系人记录列表,这正是<apex:pageBlockTable>所期望的。

getContacts()方法被称为getter方法,它是一个通用模式,其中{!您的Visualforce标记中的someExpression}将自动连接到控制器中名为getSomeExpression()的方法。这是让页面访问需要显示的数据的最简单的方法。

添加一个新的操作方法

在自定义控制器中创建操作方法以响应用户在页面上的输入。
显示数据很棒,但是对用户操作的回应对于任何网络应用程序都是至关重要的使用自定义控制器,您可以通过编写操作方法来响应用户活动,从而创建尽可能多的自定义操作,以支持页面。
  1. 在ContactsListController类中,getContacts()方法的下面添加以下两个方法。
    public void sortByLastName() {
        this.sortOrder = 'LastName';
    }
        
    public void sortByFirstName() {
        this.sortOrder = 'FirstName';
    }
    这两个方法改变了sortOrder私有变量的值。在检索联系人的SOQL查询中使用sortOrder,并且更改sortOrder将更改结果的顺序。
  2. 在ContactsListWithController页面中,使用以下标记替换ct.FirstName和ct.LastName的两个<apex:column>标记。
    <apex:column value="{! ct.FirstName }">
        <apex:facet name="header">
            <apex:commandLink action="{! sortByFirstName }" 
                reRender="contacts_list">First Name
            </apex:commandLink>
        </apex:facet>
    </apex:column>
    
    <apex:column value="{! ct.LastName }">
        <apex:facet name="header">
            <apex:commandLink action="{! sortByLastName }" 
                reRender="contacts_list">Last Name
            </apex:commandLink>
        </apex:facet>
    </apex:column>

    尽管可视外观保持不变,但如果现在单击“名字和姓氏”列标题,它们将更改联系人列表的排序顺序。太好了!
    新的标记将两个嵌套组件添加到每个<apex:column>组件。 <apex:column>本身有一个纯文本标题,但是我们希望使标题可点击。 <apex:facet>让我们将列标题的内容设置为我们想要的任何内容。而我们想要的是一个调用正确的操作方法的链接。该链接是使用<apex:commandLink>组件创建的,action属性设置为引用控制器中action方法的表达式。 (请注意,与getter方法相比,action方法的名称与引用它们的表达式相同。)

    点击链接时,会触发控制器中的操作方法。该操作方法更改排序顺序专用变量,然后该表被重新渲染。当表格被重新渲染时,{!联系人}被重新评估,重新查询以任何排序顺序刚刚设置。最终的结果是按照用户点击所请求的顺序来使用表格。

超越基础

名字和姓氏列的标题文本在这个标记中被硬编码。但是,如果你的用户不全都使用英文呢?标准Salesforce用户界面已翻译所有标准对象的字段名称版本,并且可以为自定义对象提供自己的翻译。你将如何访问这些?试试这个标记,而不是纯文本:<apex:outputText value =“{!$ ObjectType.Contact.Fields.FirstName.Label}”/>。即使您的组织使用相同的语言,这也是引用字段标签的正确方法,因为如果字段名称被更改,它将自动更新。

告诉我更多…

自定义控制器和Apex语言让您可以在Visualforce页面中完成任何您能想到的任何事情。
Getter方法将数据从您的控制器中拖出到您的页面上。有相应的setter方法可以让你从页面提交值到你的控制器。就像getter方法一样,你在setter前面加上“set”,除此之外,它们只是一个方法。

getter和setter的替代方法是使用Apex属性。属性是一种变量与getter和setter方法的组合,它们的语法可以更清楚地将它们组合在一起。引用自定义对象的简单属性可能会这样声明。

public MyObject__c myVariable { get; set; }

属性可以是公共的或私有的,可以是只读的,甚至可以只写,通过省略get或set。你可以为get或set方法创建实现,当你想要执行额外的逻辑,除了简单地保存和检索一个值。

属性是Apex的一般功能,不是Visualfor特有的。 Apex是一种完整的编程语言,除了成为构建复杂的Visualforce页面的天然合作伙伴外,它还被用于许多其他的Force.com开发环境。请参阅此处其他位置的Apex主题以及本页末尾的资源,了解如何学习充分利用Apex。

Visualforce请求和响应的生命周期最初可能看起来很复杂。尤其重要的是要明白,没有特定的getter或setter(或属性,如果你使用它们)的顺序被调用,所以你不能在它们之间引入顺序执行的依赖关系。 Visualforce开发人员指南的相关章节中提供了更多详细信息,特别是“自定义控制器和控制器扩展”一章。

Salesforce Visualforce (基础8)静态资源

学习目标

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

  • 解释什么样的静态资源以及为什么要使用它们。
  • 解释单个和压缩静态资源之间的差异。
  • 创建并上传一个静态资源。
  • 将静态资源添加到Visualforce页面。

静态资源简介

静态资源允许您上传可在Visualforce页面中引用的内容。资源可以是档案(如.zip和.jar文件),图像,样式表,JavaScript和其他文件。
静态资源由Force.com管理和分发,Force.com充当文件的内容分发网络(CDN)。缓存和分发是自动处理的。

静态资源使用$ Resource全局变量进行引用,该变量可以由Visualforce直接使用,也可以用作诸如URLFOR()之类的函数的参数。

创建并上传一个简单的静态资源

为独立的静态资产创建一个简单的,独立的静态资源。
当您的静态资产与其他资产无关时(即不是一组类似资产(如一组图标)的一部分),创建独立静态资源是最容易的。

  1. 下载jQuery JavaScript库的当前版本。在写这个是jQuery 3.1.0。
    如果链接不起作用,或者您想确保您正在下载最新版本,请访问http://jquery.com/download/并下载最新版本。

    注意

    右键单击直接链接下载文件,而不是在浏览器窗口中打开它。

  2. 在安装程序中,在快速查找框中输入静态资源,然后选择静态资源,然后单击新建。
  3. 输入名称的jQuery。
  4. 点击选择文件,然后选择您以前下载的jQuery JavaScript文件。
    Creating a simple static resource
  5. 如果看到缓存控制菜单,请选择公共。
    此项目在所有组织中都不可见。
  6. 点击 Save.

你现在有一个jQuery的静态资源版本,你可以在你的Visualforce页面中使用,通过在表达式中引用它,比如{! $ Resource.jQuery}。真正好的是,您可以编辑静态资源并将其更新到jQuery 3.1.2,而无需更改任何Visualforce页面。静态资源引用处理细节。

将一个静态资源添加到Visualforce页面

使用$ Resource全局变量和点符号来引用一个独立的静态资源。
  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。输入HelloJQuery作为页面名称。
  2. 在编辑器中,用以下替换标记。
    <apex:page>
        
        <!-- Add the static resource to page's <head> -->
        <apex:includeScript value="{! $Resource.jQuery }"/>
        
        <!-- A short bit of jQuery to test it's there -->
        <script type="text/javascript">
            jQuery.noConflict();
            jQuery(document).ready(function() {
                jQuery("#message").html("Hello from jQuery!");
            });
        </script>
        
        <!-- Where the jQuery message will appear -->
        <h1 id="message"></h1>
        
    </apex:page>
  3. 点击预览打开您的页面的预览,您可以在进行更改时查看。
    应打开一个新窗口,显示标准的Salesforce页面标题和侧边栏元素,以及jQuery的简短消息。
    除了说明如何在您的Visualforce页面上包含JavaScript资源之外,此页面没有太多工作。关键是使用$ Resource全局变量。使用点符号将它与<apex:includeScript>(用于JavaScript文件),<apex:stylesheet>(用于CSS样式表)或<apex:image>(用于图形文件)标签中的资源名称相结合它到你的页面。

创建和上传压缩的静态资源

创建压缩的静态资源,将通常一起更新的相关文件分组在一起。
当您的静态资产是一组相关项目(例如,一组应用程序图标或复杂的JavaScript库)时,最好创建一个压缩的静态资源。创建一个包含所有要组合在一起的元素的压缩文件,并仅将一个压缩文件上传到Force.com。

  1. 以ZIP格式下载当前版本的jQuery Mobile JavaScript库。在写这个是jQuery Mobile 1.4.5
    如果链接不起作用,或者您想确保您正在下载最新版本,请访问http://jquerymobile.com/download/并下载最新版本的ZIP文件。
  2. 在安装程序中,在快速查找框中输入静态资源,然后选择静态资源,然后单击新建。
  3. 输入名称的jQueryMobile。
  4. 点击选择文件,然后选择您以前下载的jQuery Mobile ZIP文件。
    Creating a zipped static resource
  5. 如果看到缓存控制菜单,请选择公共。
    此项目在所有组织中都不可见。
  6. 点击 Save.

    注意

    如果jQuery Mobile ZIP文件大于5 MB,则编辑压缩文件以除去/ demo /目录及其内容,并上传较小的zip压缩文件。

现在,您可以在Visualforce页面中使用jQuery Mobile的静态资源版本。您将学习如何在压缩的静态资源中引用单个文件。

将压缩的静态资源添加到Visualforce页面

使用$ Resource全局变量和URLFOR()函数来引用压缩静态资源中的项目。
URLFOR()函数可以将对压缩的静态资源的引用以及其中的项目的相对路径组合起来,以创建可用于引用静态资产的Visualforce组件的URL。例如,URLFOR($ Resource.jQueryMobile,’images / icons-png / cloud-black.png’)将URL返回到压缩静态资源中的特定图形资源,可以由<apex:image>组件使用。您可以为<apex:includeScript>和<apex:stylesheet>组件构建JavaScript和样式表文件的类似URL。
  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。
  2. 在编辑器中,用以下替换标记。
    <apex:page showHeader="false" sidebar="false" standardStylesheets="false">
        
        <!-- Add static resources to page's <head> -->
        <apex:stylesheet value="{!
              URLFOR($Resource.jQueryMobile,'jquery.mobile-1.4.5/jquery.mobile-1.4.5.css')}"/>
        <apex:includeScript value="{! $Resource.jQuery }"/>
        <apex:includeScript value="{!
             URLFOR($Resource.jQueryMobile,'jquery.mobile-1.4.5/jquery.mobile-1.4.5.js')}"/>
    
        <div style="margin-left: auto; margin-right: auto; width: 50%">
            <!-- Display images directly referenced in a static resource -->
            <h3>Images</h3>
            <p>A hidden message:
                <apex:image alt="eye" title="eye"
                     url="{!URLFOR($Resource.jQueryMobile, 'jquery.mobile-1.4.5/images/icons-png/eye-black.png')}"/>
                <apex:image alt="heart" title="heart"
                     url="{!URLFOR($Resource.jQueryMobile, 'jquery.mobile-1.4.5/images/icons-png/heart-black.png')}"/>
                <apex:image alt="cloud" title="cloud"
                     url="{!URLFOR($Resource.jQueryMobile, 'jquery.mobile-1.4.5/images/icons-png/cloud-black.png')}"/>
            </p>
    
        <!-- Display images referenced by CSS styles,
             all from a static resource. -->
        <h3>Background Images on Buttons</h3>
        <button class="ui-btn ui-shadow ui-corner-all
             ui-btn-icon-left ui-icon-action">action</button>
        <button class="ui-btn ui-shadow ui-corner-all
             ui-btn-icon-left ui-icon-star">star</button>
        </div>
    </apex:page>
  3. 点击预览打开您的页面的预览,您可以在进行更改时查看。
    打开一个新窗口,并显示来自jQuery Mobile静态资源的一些图像。

    jQuery buttons via static resources

为简单起见,此页面仅显示如何在Visualforce页面上引用压缩的静态资源。例如,如果您想了解更多关于如何结合Visualforce和JavaScript库(如jQuery Mobile)的更多资源,请参阅附加资源。

告诉我更多…

静态资源通常是将设计和脚本资产包含在Force.com应用程序中的最佳方式,并且可以通过多种方式将这些资源与Visualforce页面结合使用。
如果您喜欢为jQuery和jQuery Mobile组合一些静态资源,您将会喜欢我们预先打包的静态资源集合。 Salesforce Mobile Packs允许您使用行业标准网络技术(如HTML5,CSS3和JavaScript)以及流行的框架(如jQuery Mobile,AngularJS和Backbone.js)构建与Salesforce Platform集成的Web和混合应用程序。

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代码量并不是很大,但它确实需要自定义代码。查看一些起点的附加资源。

Salesforce Visualforce (基础6)输入数据

学习目标

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

  • 解释Visualforce表单的基本要求。
  • 使用不包含平台视觉样式的Visualforce表单元素进行区分。
  • 列出四个或更多的标准输入表单标签。
  • 创建一个Visualforce窗体来编辑和保存一条记录。

Visualforce表单介绍

创建和编辑数据是任何应用程序的基本方面。 Visualforce提供了您需要的所有功能,可以轻松创建可创建新记录或检索记录,编辑其值并将更改保存回数据库的页面。
在这里,我们将标准控制器与<apex:form>组件和一些易于理解的表单元素结合起来,创建一个相当复杂的记录编辑页面。

创建一个基本表单

使用<apex:form>和<apex:inputField>创建一个页面来编辑数据。将<apex:commandButton>与标准控制器中内置的保存操作组合起来,以创建新记录或将更改保存到现有记录。

让某人编辑和更新记录的页面需要执行以下所有操作。

  • 查找记录以便从数据库中进行编辑和检索。
  • 把相关的记录数据以编辑的形式放在页面上。
  • 通过更改的数据接收表单提交。
  • 验证新的值。
  • 将有效的更改保存回数据库。
  • 向提交更改的人员提供适当的消息,无论新数据是成功保存还是存在错误。

当您使用标准控制器和<apex:form>组件时,Visualforce会自动为您执行大部分这些操作。

让我们从基础开始。

  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。输入AccountEdit作为页面名称。
  2. 在编辑器中,用以下替换标记。
    <apex:page standardController="Account">
        
        <h1>Edit Account</h1>
        
        <apex:form>
        
            <apex:inputField value="{! Account.Name }"/>
            
            <apex:commandButton action="{! save }" value="Save" />
        
        </apex:form>
        
    </apex:page>
  3. 点击预览打开您的页面的预览,您可以在进行更改时查看。
    一个新的窗口应该打开,显示一个形式与一个单一的空领域的身体。
  4. 在预览窗口中,将客户的ID添加到URL,然后按ENTER。
    URL应该是这样的: https://SalesforceInstance/apex/AccountEdit?core.apexpages.request.devconsole=1&id=001D000000JRBes

    您现在应该在表单字段中看到该客户的名称。

    A basic form to edit account name

    这验证你已经有了标准的控制器工作和一个有效的记录ID。

它看起来可能不是很多,但是在六十多行标记中,您已经获得了用于更新客户名称的完整功能表单。给它一个旋转!

这些是这种形式要理解的基本方面。

  • 该页面使用<apex:page>组件中定义的客户的标准控制器。
  • <apex:form>是一个Visualforce组件,它将其中的所有内容打包成可以作为页面操作的一部分发送回服务器的东西。如果您需要将数据发送回Salesforce,大部分时间您都会在<apex:form>中执行此操作。
  • <apex:inputField>为与其关联的记录数据字段创建屏幕表单字段。您可以通过提供一个表达式来引用value属性中的相关字段。这里的表达是{! Account.Name},你应该没有困难猜测客户的名称字段。
  • 最后,<apex:commandButton>在页面的用户界面上添加一个按钮。这个按钮点击时触发一个动作。在这种情况下,该操作是标准控制器中的save()操作方法。与<apex:inputField>类似,通过引用提供给<apex:commandButton>操作属性的表达式中要调用的操作方法,可以将<apex:commandButton>与其操作连接起来。

添加字段标签和平台样式

在<apex:pageBlock>和<apex:pageBlockSection>标签中放置表单元素进行组织和分组,并使表单采用平台视觉风格。
让我们修改你的表格,使它看起来更熟悉。
  1. 在<apex:form>组件的内部,将两个表单元素包装在<apex:pageBlock>和<apex:pageBlockSection>标记中,以便您的标记看起来像这样。
    <apex:page standardController="Account">
        <apex:form>
        
        <apex:pageBlock title="Edit Account">
    
            <apex:pageBlockSection>
                <apex:inputField value="{! Account.Name }"/>        
            </apex:pageBlockSection>
    
            <apex:pageBlockButtons>
                <apex:commandButton action="{! save }" value="Save" />        
            </apex:pageBlockButtons>
    
        </apex:pageBlock>
        
        </apex:form>
    </apex:page>
    这个版本的表单的样式是完全不同的!与输出组件一样,当您在<apex:pageBlock>和<apex:pageBlockSection>标签中使用输入组件时,它们将采用平台视觉样式。
  2. 在客户名称字段下方,添加三个字段,以便您的标记看起来像这样。
    <apex:pageBlockSection columns="1">
        <apex:inputField value="{! Account.Name }"/>
        <apex:inputField value="{! Account.Phone }"/>        
        <apex:inputField value="{! Account.Industry }"/>        
        <apex:inputField value="{! Account.AnnualRevenue }"/>
    </apex:pageBlockSection>
    现在你有了一个更完整,更现实的形式来使用。
    Edit account form with platform styling

<apex:inputField>组件根据标准或自定义对象字段的类型呈现适当的输入小部件。例如,如果您使用<apex:inputField>标记显示日期字段,则日历小部件将显示在表单上。如果您使用<apex:inputField>标签来显示选取列表字段,就像我们在这里为行业字段所做的一样,则会显示一个下拉列表。

<apex:inputField>可用于捕获任何标准或自定义对象字段的用户输入,并且尊重在字段定义上设置的任何元数据,例如字段是必需的还是唯一的,或者当前用户是否有权查看或编辑它。

显示表单错误和消息

使用<apex:pageMes​​sages>显示任何表单处理错误或消息。
出现问题时,您的页面应提供有用的反馈,例如缺少必填字段或字段值未通过验证时。标准控制器实际上为您处理所有这些。所有你需要做的是告诉它在哪里把信息放在页面上。
  1. 在<apex:pageBlock>标记下,添加以下行。
    <apex:pageMessages/>
  2. 尝试删除客户的名称,并用空白名称保存记录。

    显示页面的验证错误。

    Edit account with page error messages

正如你所看到的,<apex:inputField>显示了它自己的字段的错误,但是对于更长的表单来说,将页面的所有错误列在页面顶部的一个地方是一个很好的方法。

标准的控制器已经收集了表格处理后的所有页面的消息。 <apex:pageMes​​sages>组件使您能够在合适的地方显示这些消息。

告诉我更多…

显然还有很多东西需要学习如何为您的Web应用程序构建有用的可用表单。
对于初学者,Visualforce提供了十几个输入组件,而不仅仅是<apex:inputField>。 <apex:inputField>与标准控制器配合使用,可直接编辑记录数据。对于使用自定义控制器代码的页面,或者表单输入不直接映射到记录上的字段时,您需要了解其他一些信息。大多数这些组件的名称都以“apex:input”开头,您可以在组件参考中找到它们。对于选择列表和单选按钮控件,请查找名称以“apex:select”开头的组件。

对于准备在移动设备上使用的用户界面,您需要查看专门用于HTML5页面的<apex:input>,并允许您使用各种功能来生成输入用户元素移动友好。

您在此处编写的代码使用标准控制器为页面提供的许多操作。我们把这些标准的行动称为,其中也有不少。有一个核心集合可用于标准控制器的所有对象,但许多内置的标准对象还有其他可供使用的操作。

说到行动,您可以添加操作来编辑和删除现有的相关联系人。你如何添加创建新的相关联系人的能力?这不像使用创建动作创建链接那样简单,就像编辑和删除一样。这是因为这些操作对现有记录起作用,这些记录与相关客户已经有关系。但是当你创建一个新的记录时,你需要自己创建这个关系。这将要求你写一些你自己的自定义控制器代码。

Salesforce Visualforce (基础5)显示记录

学习目标

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

  • 解释粗粒度和细粒度组件之间的区别,以及为什么您可能需要使用其中一个或另一个。
  • 解释什么是迭代组件,以及它的用途。
  • 使用相关的粗粒度组件显示记录详细信息和相关列表。
  • 使用相关的细粒度组件来替换和定制粗粒度组件。

输出组件简介

Visualforce包含近150个内置组件,您可以在页面上使用它们。请求页面时,组件呈现为HTML,CSS和JavaScript。粗粒度的组件在一个单独的组件中提供了大量的功能,并且可能为它所使用的页面添加了大量的信息和用户界面。细粒度的组件提供了更加专注的功能,并使您能够设计页面,使其看起来和行为符合您的需要。
在这里,我们将重点讨论输出组件,也就是从记录中输出数据的组件,并使您能够设计一个仅供查看的用户界面。


用标准控制器创建一个Visualforce页面

将输出组件与标准控制器一起使用,以便于访问和显示记录详细信息。
您将在此页面中尝试多个不同的输出组件。现在,让我们创建一个大部分空白的页面。

  1. 打开开发者控制台,然后点击 File | New | Visualforce Page 创建一个新的Visualforce页面。输入页面名称的AccountDetail。
  2. 在编辑器中,用以下替换标记。
    <apex:page standardController="Account">
        
        {! Account.Name }
        
    </apex:page>
  3. 点击预览打开您的页面的预览,您可以在进行更改时查看。
    应打开一个新窗口,显示标准的Salesforce页面标题和侧边栏元素,但没有任何内容。
  4. 在预览窗口中,将客户的ID添加到URL中,然后按回车键。
    该URL应该是这样的:https://SalesforceInstance/apex/AccountDetail?core.apexpages.request.devconsole=1&id=001D000000JRBes
    您现在应该在正文中看到该客户的名称。这验证你已经有了标准的控制器工作和一个有效的记录ID。

显示记录详情

使用<apex:detail>快速将记录详细信息添加到使用标准控制器的页面。
一些输出组件给聚会带来了很多。这些“粗粒度”组件提供了许多功能,显示许多字段,标签和其他用户界面元素。它们使您可以快速构建内置Salesforce用户界面的变体页面。

  1. 将行替换为{! Account.Name},使用以下标记,并保存您的更改。
    <apex:detail />
    哇,这是一个很大的改变!使用一行标记,您可以复制客户对象的整个标准视图页面!
    The <apex:detail/> component

<apex:detail>是一个粗粒度输出组件,它只在一行标记中向页面添加许多字段,部分,按钮和其他用户界面元素。还要注意,它添加到页面的所有内容都使用Salesforce Classic样式。定制<apex:detail>的外观有相当多的属性。现在花几分钟,尝试改变几个看看他们做什么。要创建与Lightning Experience的风格更加一致的页面,请参阅了解Visualforce&Lightning Experience模块中的重要视觉设计注意事项。

显示个别字段

使用<apex:outputField>显示记录中的各个字段。
当你需要更多的控制你的页面布局时,你可以单独添加字段。 <apex:outputField>组件是专门为此而设计的。

  1. 用下面的标记替换<apex:detail />行。
    <apex:outputField value="{! Account.Name }"/>
    <apex:outputField value="{! Account.Phone }"/>
    <apex:outputField value="{! Account.Industry }"/>
    <apex:outputField value="{! Account.AnnualRevenue }"/>
    
    这四个字段被添加到页面。但格式化可能不是你所期望的。字段值全部显示在一行中,没有标签,也没有其他格式。这不是我们想要的,与<apex:detail>和<apex:relatedList>组件形成了鲜明的对比,这些组件自动使用平台样式。
    本身,<apex:outputField>只输出字段的值。但是,当您将其封装在<apex:pageBlock>和<apex:pageBlockSection>组件中时,其行为会发生相当大的变化。

  2. 用<apex:pageBlock>和<apex:pageBlockSection>组件包装<apex:outputField>行,以便您的标记看起来像这样。
    <apex:pageBlock title="Account Details">
        <apex:pageBlockSection>
            <apex:outputField value="{! Account.Name }"/>
            <apex:outputField value="{! Account.Phone }"/>
            <apex:outputField value="{! Account.Industry }"/>
            <apex:outputField value="{! Account.AnnualRevenue }"/>
        </apex:pageBlockSection>
    </apex:pageBlock>
    这还差不多!
    Output fields inside a page block

    需要<apex:pageBlock>和<apex:pageBlockSection>组件来激活平台外观。当在<apex:pageBlockSection>中使用<apex:outputField>时,它将采用两列布局,很好地添加字段标签,对齐和样式字段和标签等等。

    尽管<apex:outputField>看起来像一个细粒度的组件,因为它只输出一个字段,但实际上却做了很多。它知道是否在某些其他组件中使用它,并适当地更改其输出和样式。格式和显示也很聪明。请注意,年收入字段被格式化为货币。 <apex:outputField>自动适应正在显示的字段的数据类型。尝试添加一个日期,清单,或选择列表字段到页面,看看会发生什么。

显示一个表

使用<apex:pageBlockTable>将数据表添加到页面。
什么是相关列表?当您将其添加到页面时,<apex:relatedList>会执行什么操作?
  • 它抓取了一个类似数据元素的列表。例如,该客户的联系人列表。
  • 它为每个字段设置一个列,每个列上面都有标题,等等。
  • 对于列表中的每个项目(对于每个相关联系人),它将向表格添加一行,并使用该记录中的适当字段填充每列。

您可以使用迭代组件在自己的Visualforce标记中执行相同的操作。一个迭代组件与一组相似的项目一起工作,而不是一个单一的值。例如,{!Account.contacts}是一个表达式,用于计算一个客户的联系人列表。您可以将此表达式与迭代组件一起使用来创建列表或表格,其中包含这些相关联系人的详细信息。

  1. 用下面的标记替换两个<apex:relatedList />行。
    <apex:pageBlock title="Contacts">
       <apex:pageBlockTable value="{!Account.contacts}" var="contact">
          <apex:column value="{!contact.Name}"/>
          <apex:column value="{!contact.Title}"/>
          <apex:column value="{!contact.Phone}"/>
       </apex:pageBlockTable>
    </apex:pageBlock>
    列出客户联系人的表格会添加到页面中,只有您选择的列。
    Contacts list using pageBlockTable
<apex:pageBlockTable>是一个迭代组件,用于生成一个数据表,并附有平台样式。这是你的标记发生了什么。

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

这是非常重要的,迭代组件是第一次很难理解。你现在可以做的最好的事情是尝试创建你自己的。使用<apex:pageBlockTable>将与机会相关的记录列表添加到页面。选择你想在表格中显示的字段。查找<apex:pageBlockTable>和<apex:column>的不同属性,并进行试验,直到您感觉舒适。

告诉我更多…

粗粒度的组件使您可以快速地为页面添加大量的功能,而精细的组件可以让您更好地控制页面的特定细节。
<apex:enhancedList>和<apex:listViews>是您可能要用于或代替<apex:relatedList>的其他粗粒度组件。还有许多其他组件将很多功能包装到一个标签中。如果你还没有做,请查看标准组件参考,看看可能的范围。

<apex:pageBlockTable>是一个迭代组件,用于获取Salesforce Classic样式。 <apex:dataTable>和<apex:dataList>是用于创建表格和列表的迭代组件,无需创建样式。 <apex:repeat>是一个迭代组件,您可以使用它来为记录集合生成任意标记。

您可能已经注意到,手动创建的相关列表缺少一些添加到由<apex:relatedList>创建的表中的内容。例如,用于编辑和删除单个记录的编辑和删除链接缺失,新联系人按钮也是如此。要创建这些用户界面元素,您需要了解更多的Visualforce,特别是关于表单和操作。你会在其他地方了解到。