Lightning-设计(4)读取数据

学习目标

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

  • 描述SLDS数据表和表单组件如何工作。
  • 使用JavaScript远程对象构建包含动态数据的列表视图页面。

将数据添加到混合

让我们面对它,Web应用程序是不是很令人兴奋,除非它们包含一些数据。这个单元是关于使我们的列表视图是真实的,并使用开发者组织的一些示例数据。

我们将使用JavaScript Remote Objects访问Salesforce数据,但您也可以使用JavaScript Remoting。请注意,设计系统尚不支持Apex标签,但Visualforce可视化设计考虑事项上的Trailhead单元解释了遗留代码样式的选项,使其看起来像新的Lightning UI。

本单元中的JavaScript不在设计系统的范围之内,但它有助于将我们的一些关键组件生命化并展示它们的使用方式。再加上它会让事情变得更有趣。

数据表组件

数据表组件是用于使用Lightning UI样式显示表格数据的HTML表格的增强版本。数据表是通过将slds-table类应用于<table>标签而创建的。使用slds-table-bordered类来应用边界。

这是一个包含两列和一个标题行的示例表。您可以看到,其应用了设计系统类的熟悉的HTML标记。再次没有任何CSS可以看到。不用担心输入,下一节我们将使用Salesforce数据动态填充真实的数据表。

<table class="slds-table slds-table--bordered slds-table--cell-buffer slds-no-row-hover">
  <thead>
    <tr class="slds-text-heading--label">
      <th scope="col">Account ID</th>
      <th scope="col">Account name</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">123</th>
      <td>Account 1</td>
    </tr>
    <tr>
      <th scope="row">456</th>
      <td>Account 2</td>
    </tr>
  </tbody>
</table>

用动态数据填充数据表

正如我们上面提到的那样,在这个版本中,设计系统不支持内置的Visualforce组件 – <apex:*>,<chatter:*>以及其他您熟悉和喜欢的组件 – 用于布置页面和访问数据。这一点很重要。不要指望将设计系统应用到您的传统Visualforce页面,并让他们立即转化为互联网上最美丽的用户界面。

目前,我们建议使用远程对象,JavaScript Remoting或REST API从基于Design System标记的Visualforce页面访问Salesforce数据。本教程中的示例将使用远程对象。我们在这里专注于设计系统,所以虽然我们将提供完整的代码,但我们不打算深入讨论远程对象部分。如果您想了解有关这些数据访问技术的更多信息,请参阅以下资源。

我们走吧。摇动你的手来预热 – 是时候编码了。使用名称Trailhead_SLDS_Listview_Data克隆您的列表视图页面作为新的Visualforce页面。然后通过在</ head>和<body>标记之间插入以下代码,将Salesforce组织的客户记录连接为远程对象:

</head>    

<apex:remoteObjects>
  <apex:remoteObjectModel name="Account" fields="Id,Name,LastModifiedDate"/>
</apex:remoteObjects>

<body>
接下来,我们用slds-p-vertical-medium类中的垂直填充替换无聊的<ul>占位符与客户列表<div>。我们的JavaScript很快将用我们完全呈现的数据表来替换这个<div>的空白内容。
<!-- PRIMARY CONTENT WRAPPER -->
<div class="myapp">

  <!-- 客户列表 -->
  <div id="account-list" class="slds-p-vertical--medium"></div>
  <!-- / 客户列表 -->

</div>
<!-- / PRIMARY CONTENT WRAPPER -->
最后在</ body>结束标记之前的文件末尾添加以下JavaScript代码。请注意,在您自己的代码中,您可能希望将此JavaScript放在单独的静态资源中。
<!-- JAVASCRIPT -->
<script>
  (function() {
    var account = new SObjectModel.Account();
    var outputDiv = document.getElementById('account-list');

    var updateOutputDiv = function() {

      account.retrieve(
        { orderby: [{ LastModifiedDate: 'DESC' }], limit: 10 },
        function(error, records) {
          if (error) {
            alert(error.message);
          } else {
            // create data table
            var dataTable = document.createElement('table');
            dataTable.className = 'slds-table slds-table--bordered slds-table--cell-buffer slds-no-row-hover';

            // add header row
            var tableHeader = dataTable.createTHead();
            var tableHeaderRow = tableHeader.insertRow();

            var tableHeaderRowCell1 = tableHeaderRow.insertCell(0);
            tableHeaderRowCell1.appendChild(document.createTextNode('Account name'));
            tableHeaderRowCell1.setAttribute('scope', 'col');
            tableHeaderRowCell1.setAttribute('class', 'slds-text-heading--label');

            var tableHeaderRowCell2 = tableHeaderRow.insertCell(1);
            tableHeaderRowCell2.appendChild(document.createTextNode('Account ID'));
            tableHeaderRowCell2.setAttribute('scope', 'col');
            tableHeaderRowCell2.setAttribute('class', 'slds-text-heading--label');

            //建立表体
            var tableBody = dataTable.appendChild(document.createElement('tbody'))
            var dataRow, dataRowCell1, dataRowCell2, recordName, recordId;
            records.forEach(function(record) {
              dataRow = tableBody.insertRow();

              dataRowCell1 = dataRow.insertCell(0);
              recordName = document.createTextNode(record.get('Name'));
              dataRowCell1.appendChild(recordName);

              dataRowCell2 = dataRow.insertCell(1);
              recordId = document.createTextNode(record.get('Id'));
              dataRowCell2.appendChild(recordId);
            });

            if (outputDiv.firstChild) {
              // replace table if it already exists
              // see later in tutorial
              outputDiv.replaceChild(dataTable, outputDiv.firstChild);
            } else {
              outputDiv.appendChild(dataTable);
            }
          }
        }
      );
    }
    updateOutputDiv();
  })();
</script>
<!-- / JAVASCRIPT -->

此代码通过远程对象访问客户记录,updateOutputDiv()函数使用它们在客户列表<div>中呈现表。

请注意表是如何用slds-scrollable -x工具类包装在一个div中的。如果数据太宽而无法在屏幕上显示,则会为该表提供一个水平滚动条。

预览你的页面,应该看起来像下面这样。不过希望你的客户名更具创意。

Populated data table

填充的数据表

我们在这里仍然可以做得更好。让我们互动吧。在这一步中,您将在Visualforce页面的顶部添加一个基本表单,允许用户创建一个新客户。将以下代码插入到您的主要内容包装中,在客户列表上方

<!-- PRIMARY CONTENT WRAPPER -->
<div class="myapp">

  <!-- 创建新客户  -->
  <div aria-labelledby="newaccountform">

    <!-- 创建新客户表单 -->
    <form class="slds-form--stacked" id="add-account-form">
      <!-- BOXED AREA -->
      <fieldset class="slds-box slds-theme--default slds-container--small">

        <legend id="newaccountform" class="slds-text-heading--medium slds-p-vertical--medium">Add a new account</legend>

        <div class="slds-form-element">
          <label class="slds-form-element__label" for="account-name">Name</label>
          <div class="slds-form-element__control">
            <input id="account-name" class="slds-input" type="text" placeholder="New account"/>
          </div>
        </div>
        <button class="slds-button slds-button--brand slds-m-top--medium" type="submit">Create Account</button>
      </fieldset>
      <!-- / BOXED AREA -->
    </form>
    <!-- 创建新客户表单 -->

  </div>
  <!-- / 创建新客户 -->

</div>
<!-- / PRIMARY CONTENT WRAPPER -->
...
这里还有很多新的标记。让我们一步一步的审查。

表单标记被封装到一个<div>包装器中以添加页面结构。

现在我们发现另一个设计系统组件:表单。设计系统为多种表单布局提供样式,包括水平,堆叠和内联。在这个例子中,我们使用slds-form-stacked类将一个垂直堆叠布局应用于<form>。

在表单里面是第二个包装元素,一个<fieldset>包含三个类:slds-box,slds-theme-default和slds-container-small。这三个班级创造了一个白色的,盒装的,小的区域,以保持视觉的美观和整洁。 <legend>标签中的标题在框的顶部添加了一个标题。 <legend>元素的id属性对应于包装器<div>元素的aria-labelledby属性,以实现可访问性。

每个标签和输入对都放在一个包含slds-form-element的包装盒中,以提供最佳的间距。在包装器中,<label>元素有一个slds-form-element__label类。 <input>字段放置在另一个包装器<div>中,并带有slds-form-element__control类,以提供最佳的间距。 <input>字段本身具有slds-input类。

在你的表单中添加所有这些标记和类,几乎可以自动地将所有的Lightning样式应用于自己。您添加类,我们提供所有的CSS。

我们不要忘记,用户必须能够提交表单。因此,我们包含一个<按钮>类slds-button,slds-button-brand和slds-m-top-medium。这些现在应该是不言自明的。如果没有,请参阅链接的文档。

最后,我们需要通过一种方式来连接表单,以实际保存表单的数据。我们将使用一个createAccount()JavaScript函数来完成此工作,该函数再次使用远程对象来完成这项工作。在updateOutputDiv()函数下面添加以下内容:

var accountForm = document.getElementById('add-account-form');
var accountNameField = document.getElementById('account-name');

var createAccount = function() {
  var account = new SObjectModel.Account();
  account.create({ Name: accountNameField.value }, function(error, records) {
    if (error) {
      alert(error.message);
    } else {
      updateOutputDiv();
      accountNameField.value = '';
    }
  });
}
accountForm.addEventListener('submit', function(e) {
  e.preventDefault();
  createAccount();
});
提交表单调用了createAccount()函数,它调用我们的远程对象来创建一个新记录。

预览您的页面,然后尝试添加一些客户。 每次您使用有效的客户名称提交表格时,表格应自动更新:

Populated data table

那真是个单位! 如果你有一切工作,现在就马上做一个胜利圈。 真的,你应得的!

在本单元中,我们了解了数据表和表单组件,然后使用远程对象将它们连接到实际数据。 然而,这里缺少的东西不是吗? 我们已经有了一个闪电式的桌子,但是有点儿单调乏味。 该网页真的需要一些图标和图像来活跃起来,你不觉得吗? 在下一节中,我们将给你的页面设计TLC值得。