node命令行构建构建_构建CouchApps

node命令行构建构建

在你开始前

本教程面向有兴趣使用HTML,CSS和JavaScript来创建数据库驱动的应用程序的Web应用程序开发人员。 您应该知道如何编写JavaScript以及如何使用JavaScript操作HTML页面的文档对象模型(DOM)。 您还应该具有使用库工具(例如jQuery或Dojo)的经验。

关于本教程

Apache CouchDB是一个面向文档的开源数据库管理系统,将数据存储为JSON对象。 传统的数据库系统允许您使用一系列SQL语句执行数据检索和更新功能,这些SQL语句通过某种形式的专有客户端软件或API执行。 Apache CouchDB是不同的-您可以使用RESTful HTTP API发送查询或更新,从而几乎可以使用任何现代编程语言与Apache CouchDB进行通信。

由于建立了Apache CouchDB的体系结构,因此实际上可以构建驻留在Apache CouchDB数据库内的整个Web应用程序。 我们将这些应用程序称为CouchApps。 CouchApps允许您仅使用HTML,CSS和JavaScript来创建完全由数据库驱动的应用程序。 这些应用程序的优点在于,它们使您可以充分利用Apache CouchDB的强大复制功能来跨Apache CouchDB实例复制CouchApp。 这使您可以将CouchApp保留在多台设备上,并通过自动增量复制使其同步,从而使每台设备上的数据保持最新。

在本教程中,您将学习如何使用HTML,CSS和JavaScript创建自己的CouchApp。 您的应用程序将使用由jQuery框架提供支持的Ajax执行数据库操作。 您将构建的应用程序是联系人管理器,可让您查看,创建,编辑和删除联系人。 最后,您将学习如何在两个Apache CouchDB实例之间复制此应用程序。

先决条件

您将需要以下工具来跟随本教程:

  • 一个Apache CouchDB数据库实例,v1.0.1或更高版本
  • CouchApp工具,版本0.7.0或更高版本

请参阅相关主题下载信息和下载的资源为我们的示例应用程序的源代码。

介绍Apache CouchDB和CouchApps

在本节中,我们将探讨使用Apache CouchDB相比传统数据库解决方案的优势。

Apache CouchDB与传统数据库解决方案

Apache CouchDB是一个数据库系统,其工作方式与IBM DB2,Oracle或MySQL等传统数据库解决方案相比有所不同。 代替这些解决方案提供的数据库,表和列的结构化格式,Apache CouchDB而是通过存储文档来工作。 文档是自由格式的结构,这意味着您可以具有字段和字段结构的任意组合,并且数据库中的每个文档都可以不同。

例如,在传统的关系数据库中,您可以通过使用清单1中所示的语句定义联系人表来存储有关联系人的基本信息。

清单1.在传统的关系数据库中存储基本的联系信息
CREATE TABLE contact (
  id int(11) NOT NULL AUTO_INCREMENT,
  title char(20) DEFAULT NULL,
  firstname char(20) DEFAULT NULL,
  lastname char(20) DEFAULT NULL,
  PRIMARY KEY (id)
)

这在您的数据上放置了一个僵化的结构,它既有用又可以同时受到限制。 例如,如果您需要在表中添加中间名,该怎么办? 您将需要添加一个新字段以容纳新数据。 要考虑的另一个元素是,其他信息(例如,用于联系个人的电话号码)可能会存在于另一个表中。 要获取个人的电话号码,您需要使用联接(或子查询)执行查询,以使基本联系人表与电话号码表匹配。 您将不得不对其他数据点(例如地址和电子邮件帐户)或更灵活的数据(例如重要日期,配偶和其他链接)执行相同的操作。

在Apache CouchDB中存储信息

使用Apache CouchDB,信息可以存储在文档中,而文档是自由格式的,使用JavaScript对象表示法(JSON)编写,从而使您可以将包含列表,哈希表和传统字段的文档构建为一个文档。 例如, 清单2显示了JSON格式的联系人。

清单2. JSON格式的联系信息
{
   "firstname" : "Martin",
   "address" : {
      "home" : [
         "Some road",
         "Some town",
         "Postcode",
         "Country"
      ]
   },
   "title" : "Mr",
   "lastname" : "Brown",
   "phones" : {
      "home" : "09874978",
      "mobile" : "0892374908"
   }
}

在清单2中,有关该联系人的所有信息都在一个文档中。 但是,文档结构没有任何固定形式。 清单3显示了与同一数据库不同的联系人。

清单3.不同的联系人
{
   "email" : {
      "work" : "sample@example.com",
      "home" : "other@example.com"
   },
   "firstname" : "Paulie"
}

不要以为数据库内容使用了这种自由格式的结构就意味着您失去了执行结构的能力。 您可以使用验证例程,该例程不仅可以检查文档的结构,还可以检查那些字段的内容。

Apache CouchDB中的文档使用文档ID存储。 您可以使用任何字符串作为文档ID,因此您的联系人可以与文档ID“ MartinBrown”一起存储,或者可以允许Apache CouchDB创建UUID(通用唯一ID)。

Apache CouchDB系统的最后一个要素是,与传统数据库不同,您不需要特殊的库或接口系统即可访问或更新数据。 相反,整个界面围绕一个类似REST的界面构建,可通过任何可以通过HTTP访问网页的内容进行访问。 因此,我们可以通过打开Web浏览器并访问http://127.0.0.1:5984/contacts/MartinBrown来访问存储在机器“ Apache CouchDB”中的数据库“ contacts”中的MartinBrown文档。 联系人“ Paulie”将存储在URL http://127.0.0.1:5984/contacts/Paulie

什么是CouchApp?

这个简单的数据库Web界面还提供了CouchApp的基础。 CouchApp是存储在Apache CouchDB数据库中的文档的基于HTML5和JavaScript的应用程序。 构成接口和应用程序的文档和代码也作为设计文档存储在Apache CouchDB中。 结果是一个应用程序(包括显示元素)可以完全独立地包含在提供数据的数据库中,从而使构建和与应用程序进行交互的整个过程都集中在要呈现的信息上。

使用JavaScript作为CouchApps的核心部分还扩展到了服务器,在服务器上JavaScript用于构造数据库视图。 在像Oracle这样的传统数据库中,SQL和数据库结构提供了提取信息的能力。 这样可以很容易地提取firstname字段为“ Martin”的所有记录的列表。 但是,使用Apache CouchDB,数据存储在文档中,而不是表中。 为了获得相同的结果,您将需要打开数据库中的每个文档,找出其中是否包含指定的字段,然后将该文档添加到列表中(如果该字段与所需的内容相匹配)。 这是一个时间(和CPU)昂贵的过程,尤其是在您的数据库包含成千上万甚至数百万个文档的情况下。

为了提高这些类型操作的性能,Apache CouchDB使用视图。 视图执行对每个文档进行迭代并使用特定字段构建文档列表的操作。 视图建立在服务器上,结果视图存储在磁盘上,作为对基础文档的索引。 这样可以提高以这种方式检索文档列表时的性能,并且可以轻松地根据记录是否与特定字段值匹配来提取记录。

为了简化构建CouchApp的整个过程,有一个名为CouchApp的命令行工具可以为您的Apache CouchDB应用程序创建存根和模板代码,同时在本地文件系统上创建文件,然后您可以对其进行编辑和“推送”到使用CouchApp命令行工具的Apache CouchDB服务器。 这简化了整个过程,意味着您可以专注于构建应用程序而不必担心将应用程序上传到Apache CouchDB。

这里还有一些其他差异,我们将在这里详细介绍,但在本教程的其余部分中,我们将部分介绍这些差异。 例如,文档还可以包括附件(与该文档关联的一个或多个文件),并且存储所有文档修订版本,对文档的每次更新都会形成一个新的“修订版本”。 CouchApp工具隐藏了这种复杂性,使整个系统更易于使用。

安装CouchApp

在本节中,我们将安装和配置CouchApp

安装Apache CouchDB

在安装CouchApp之前,您需要安装Apache CouchDB。 您可以以多种格式下载Apache CouchDB,包括您可以自己构建的源代码或可以在Windows™,Mac OS X和Linux®上运行的独立应用程序。 例如,Mac OS X应用程序Apache CouchDBX作为标准应用程序运行。

在Linux和UNIX®上,您将获得一个二进制文件ouchdb,可以从命令行运行它(请参见清单4 )。

清单4.从命令行运行ouchdb二进制文件
$ couchdb
Apache CouchDB 1.0.1 (LogLevel=info) is starting.
Apache CouchDB has started. Time to relax.
[info] [<0.33.0>] Apache CouchDB has started on http://127.0.0.1:5984/

您现在可以出发了! 您可以通过访问给定的URL来检查数据库是否正在运行。 如果要打开服务器以便可以通过网络对其进行访问,请更改local.ini配置文件中的bind参数以使其与Apache CouchDB服务器的IP地址(而非主机名)匹配。

安装CouchApp

对于CouchApp命令行工具,你需要下载CouchApp的tar或从GitHub压缩包(参见相关主题 )。 您将需要在计算机上安装Python(如果尚未安装),但是CouchApp安装程序将为您处理其他库的所有依赖项。

下载软件包后,解压缩它,然后转到CouchApp目录: $ cd couchapp

现在运行Python安装程序工具以下载并安装所有依赖项,并安装couchapp工具: $ python setup.py install

您可以通过运行CouchApp来测试安装,该应用程序应返回该工具的帮助信息: $ couchapp

注意:通常,您不会创建允许任何人访问和更新的数据库。 Apache CouchDB确实支持身份验证以及执行不同操作的不同级别的安全性和权限,但是在本教程中我们不介绍它们。

配置数据库并创建CouchApp

为了理解Apache CouchDB的简单性,一种好方法是,您可以使用curl命令行工具从该命令在Apache CouchDB实例中创建一个新数据库。 要创建数据库,请向要创建的数据库的URL发出PUT HTTP命令。 例如,要创建联系人数据库,可以使用命令行: $ curl -X PUT http://127.0.0.1:5984/contacts

如果您检查文件联系人的内容,则应指定操作成功完成。

或者,使用http://127.0.0.1:5984/_utils进入Futon。 您可以使用Futon管理界面创建新数据库。

您现在有一个空的数据库。 要创建存根应用程序,可以使用CouchApp生成文件系统上所需的所有基本文件,以准备将其上传到Apache CouchDB数据库。 您可以通过运行以下$ couchapp generate app contacts来完成此操作: $ couchapp generate app contacts

这将创建一个目录Contacts,其中包含文件和内容的数组,我们可以使用这些文件和内容来构建Contacts应用程序。 您可以在清单5中看到一个顶级文件列表。

清单5.顶级文件列表
$ ls -al contacts/
total 605-
drwxrwxrwx 9 mcco mcco 4096 Dec  1 14:49 ./
drwxrwxrwx 3 mcco mcco 4096 Dec  1 14:49 ../
-rw-rw-rw- 1 mcco mcco  174 Dec  1 14:49 .couchappignore
-rw-rw-rw- 1 mcco mcco    2 Dec  1 14:49 .couchapprc
-rw-rw-rw- 1 mcco mcco 1660 Dec  1 11:51 README.md
drwxrwxrwx 3 mcco mcco 4096 Dec  1 14:49 _attachments/
-rw-rw-rw- 1 mcco mcco   16 Dec  1 14:49 _id
-rw-rw-rw- 1 mcco mcco   70 Dec  1 11:51 couchapp.json
drwxrwxrwx 4 mcco mcco 4096 Dec  1 14:49 evently/
-rw-rw-rw- 1 mcco mcco   10 Dec  1 11:51 language
drwxrwxrwx 2 mcco mcco 4096 Dec  1 14:49 lists/
drwxrwxrwx 2 mcco mcco 4096 Dec  1 14:49 shows/
drwxrwxrwx 2 mcco mcco 4096 Dec  1 14:49 updates/
drwxrwxrwx 3 mcco mcco 4096 Dec  1 14:49 vendor/
drwxrwxrwx 3 mcco mcco 4096 Dec  1 14:49 views/

其中的一些主要元素是:

  • views —包含数据库上的视图。 这些JavaScript函数可构建要返回的键和数据的列表,相当于典型的数据库查询。
  • lists —包含用于构建视图输出的格式化版本的列表。 列表是JavaScript函数,它们从视图中获取信息并格式化信息(通常为HTML)以进行显示。
  • shows —显示单个文档,而不是视图提供的文档列表。 像列表一样,节目定义为JavaScript函数。
  • attachments -包含应用程序的附件,包括index.html和JavaScript文件。

当您不知道要加载的文档的文档ID时,视图对于从数据库访问信息的方式至关重要。 列表和显示提供了用于显示信息的内置方法。 但是,您可以使用其他方法(例如jQuery库)使用视图从数据库中获取信息,以返回由jQuery Apache CouchDB库处理的文档列表。

编辑index.html

默认文档index.html包含在数据库附件目录contact / _attachments / index.html中。 您应该对其进行编辑以包含一些到数据库的默认链接。

为了充分利用jQuery和Apache CouchDB提供的环境,我们将动态定义Contacts应用程序的整个接口。 这将使用JavaScript动态提供不同的元素,包括显示视图结果和用于编辑联系信息的表单。

为此,您需要将index.html文件编辑为清单6所示的文件。

清单6.编辑index.html文件
<!DOCTYPE html>
<html>
  <head>
    <title>Contacts</title>
    <link rel="stylesheet" href="style/main.css" type="text/css">
    <script src="vendor/couchapp/loader.js"></script>
    <script src="recordedit.js"></script>

  </head>
  <body>
    <div id="account"></div>

    <h1>Contacts</h1>

    <div id="items"><div id="add"><a href="#" 
class="add">Add Contact</a></div>
      <div id="contacts"></div>
      <div id="contactform"></div>

  </body>
</html>

结构的关键要素是:

  • 供应商/couchapp/loader.js脚本的加载。 反过来,这会加载jQuery和jQuery Couch库等。
  • 加载recordedit.js脚本。 这是我们将使用用于构建应用程序JavaScript函数填充的脚本。
  • 一个按钮,将用于触发“添加”表单以创建新联系人。
  • 具有id联系人的div元素,将用于显示联系人列表。
  • 具有id contactform的div元素,将用于显示联系表。

编辑完文件后,需要使用CouchApp命令行工具将应用程序推送到Apache CouchDB数据库: $ couchapp push contacts http://127.0.0.1:5984/contacts

第一个参数是推送(发布)应用程序的指令,第二个参数是存储应用程序的本地目录,联系人,第三个参数是您要在其中上传数据库的Apache CouchDB数据库的URL。 推送成功完成后,您可以使用以下网址查看上载的应用程序: http://127.0.0.1:5984/contacts/_design/contacts/index.html : http://127.0.0.1:5984/contacts/_design/contacts/index.html : http://127.0.0.1:5984/contacts/_design/contacts/index.html

值得剖析以下URL:

  • 127.0.0.1:5984是Apache CouchDB服务器的主机名和端口号。 默认情况下,服务器在端口5984上运行。
  • contacts是数据库的名称。
  • _design是Apache CouchDB的特殊标识符,指示您要访问设计文档。 设计文档包含视图,列表和显示定义。 一个给定的数据库可以有多个设计文档。
  • contacts是设计文档的名称。 默认情况下,CouchApp工具使用与您的应用程序相同的名称创建设计文档。
  • index.html是联系人设计文档的附件名称。

CouchDB还包括一个重写模块,它将这些URL简化为更友好的名称。 请参阅相关主题关于这一主题的文章。

有了基本文档后,就可以开始构建应用程序的其余部分了。

显示联系人列表

在本节中,我们将创建并显示联系人列表。

创建一个视图

要构建联系人列表,您首先需要创建一个视图。 这是一个JavaScript函数,它接受文档作为唯一参数。 该函数由Apache CouchDB在数据库中的每个文档上执行,并且应在此视图中输出键(用于显示和过滤信息)以及要为每个文档输出的对应值。 当您将文档内容映射到要提取的信息时,此过程称为映射。 还有另一个步骤称为reduce,可用于汇总或简化信息,但对于Contacts应用程序则不需要。

例如,要将联系人文档中的名称作为键输出,并将整个联系人记录作为值输出,则需要编写清单7所示的视图。

清单7.编写视图
function(doc) {
    if (doc.name) {
emit(doc.name,doc);
    }
}

匿名函数接受一个参数,即文档。 然后,该函数检查以确保记录具有名为name的字段,如果为true,则emit()函数将返回两个值:第一个为键,第二个为值,在这种情况下为文档的副本。 键和值都可以是任何有效的JSON结构。 在搜索和分页期间,Apache CouchDB使用密钥。 这些值仅包含您要在访问该视图时在此视图中公开的信息。

在CouchApp中,可以使用generate命令在命令行上创建一个新视图: $ couchapp generate view contacts byname

这将在contacts / views / byname目录中创建view byname ,并创建两个文件map.js和reduce.js。 编辑map.js文件,并将其更改为清单6中的函数。

现在,您可以再次将应用程序推送到您的Apache CouchDB数据库。 可通过浏览器界面访问视图。 您可以访问视图byname通过访问URL上的触点设计文件http://127.0.0.1:5984/contacts/_design/contacts/_view/byname 。 再次,我们使用设计文档联系人,这一次请求在路径中输出视图(由_view标识),视图名称为byname。

在此阶段,视图将为空: {"total_rows":0,"offset":0,"rows":[]}

在应用程序中显示视图

为了在我们的应用程序中显示视图,我们可以使用jQuery Couch库访问视图,遍历视图返回的每个记录,然后打印记录信息。

清单8中显示了用于此功能的函数。

清单8.在我们的应用程序中显示视图
db = $.couch.db("contacts");
function updatecontacts() {
$("#contacts").empty();

db.view("contacts/byname", {success: function(data) {
    for (i in data.rows) {
        $("#contacts").append('<div id="' + data.rows[i].value._id 
+ '" class="contactrow"><span>' +
                              data.rows[i].value.name +
                              "</span><span>" +
                              data.rows[i].value.phone +
                              "</span><span>" +
                              '<a href="#" id="' + data.rows[i].value._id 
+ '" class="edit">Edit Contact</a>' +
                              "</span><span>" +
                              '<a href="#" id="' + data.rows[i].value._id 
+ '" class="remove">Remove Contact</a>' +
                              "</span></div>"
                             );
    }
}
});
}

清单7中的第一行设置了一个用于访问数据库的变量。 updatecontacts()函数首先清空将用于显示联系人列表的div元素,然后访问刚刚创建的视图的结果。 如果视图访问成功,则将使用返回的视图数据作为JSON结构调用匿名函数。 然后,该函数遍历内容,并构建一个联系人行,该行输出联系人姓名和电话号码。

视图结果表示为一个数组(行),该数组的每个元素都是JSON结构,其中包含视图返回的键的内容以及视图返回的值。 因此,我们可以通过访问数组元素的value.field部分来访问视图返回的联系人记录的电话号码。

输出产生一个Edit Contact和Remove Contact链接,该链接还包括基础Apache CouchDB文档的ID。 这将用于在更新和删除联系人时提供信息。

要将此功能添加到通讯录应用程序,请创建一个新文件,contacts / _attachments / recordedit.js,然后将该功能添加到该文件。

第二步是确保已加载文档,并调用updatecontacts()函数以显示当前联系人列表。 jQuery通过在文档上提供ready()函数使此操作变得容易。 文档加载完成后,将分配给您分配给该操作的功能中的所有内容。 您可以在清单9中看到定义。

清单9. ready()函数
$(document).ready(function() {

updatecontacts();

}

再次推送应用程序,然后重新加载索引页面。 不应对显示的内容进行任何更改,但是优良作法是确保添加新组件时不会损坏应用程序。

当然,列表仍然是空的,因此让我们创建一个可用于查看某些联系人的表单。

创建,编辑和删除联系人

在本节中,我们将向您展示如何创建,编辑和删除联系人。

建立新联络人

作为Web应用程序,创建新联系人需要向用户提供一个可以填写的表单,然后可以将表单的内容写入Apache CouchDB数据库。 第一步是一个新函数,它将动态生成表单HTML,然后将其附加到index.html中定义的contactform div元素(请参见清单10)

清单9显示了此功能。

清单10.动态生成HTML作为表单
function contactform(doctoedit) {
var formhtml;
formhtml =
'<form name="update" id="update" action="">';

if (doctoedit) {
formhtml = formhtml +
    '<input name="docid" id="docid" type="hidden" value="' 
+ doctoedit._id + '"/>';
}

formhtml = formhtml +
'<table>';

formhtml = formhtml +
'<tr><td>Name</td>' +
'<td><input name="name" type="text" id="name" value="' +
(doctoedit ? doctoedit.name : '') +
'"/></td></tr>';
formhtml = formhtml +
'<tr><td>Phone</td>' +
'<td><input name="phone" type="text" id="phone" value="' +
(doctoedit ? doctoedit.phone : '') +
'"/></td></tr>';
formhtml = formhtml + '<tr><td>Email</td>' +
'<td><input name="email" type="text" id="email" value="' +
(doctoedit ? doctoedit.email : '') +
'"/></td></tr>';

formhtml = formhtml +
'</table>' +
'<input type="submit" name="submit" class="update" value="' +
(doctoedit ? 'Update' : 'Add') + '"/>' +
'</form>';
$("#contactform").empty();
$("#contactform").append(formhtml);
}

清单9中的最后一行是关键。 $()构造是使用jQuery函数的简写,这里我们使用它来将表单附加到现有元素上。 jQuery使访问HTML页面的DOM元素变得容易。 在这种情况下,使用#前缀在页面DOM中查找具有指定id属性的元素。 这遵循与CSS格式化相同的格式,这使得查找不同元素变得容易。 句点前缀将查找具有指定类别的项目。 稍后我们将看到一个示例。

该函数本身接受一个参数,即要编辑的文档。 在编辑现有联系人时将使用此功能。 在首先构建表单以引入联系人的文档ID(在更新联系人记录时将需要)以及在表单中设置每个字段的值时,在函数中使用它。

但是,表单的基础很简单。 我们会生成带有字段名称和ID(名称,电话,电子邮件等)的文本输入元素。

对于要激活的表单,您需要启用index.html文件中的“ 添加联系人”链接,以便它调用该函数。 您可以通过将操作添加到ready()函数中来实现。 这样可以确保在加载文档之前该按钮不处于活动状态。 请参见清单11,获取单击链接时更新操作的jQuery代码。

清单11.显示联系表单
$("a.add").live('click', function(event) {
contactform();
});

再次将应用程序推送到Apache CouchDB。 现在,您应该发现“ 添加联系人”按钮会使用空值填充表单。 您可以在图1中看到一个示例。

图1.空的联系表单
空联系表格

创建联系人的第二部分实际上是在按下“ 提交”按钮时将文档保存到数据库中。 清单12中显示了处理此问题的函数。

清单12.按下Submit按钮将文档保存到数据库
$("input.update").live('click', function(event) {
var form = $(event.target).parents("form#update");

    db.saveDoc(builddocfromform(null,form), {
        success: function() {
            $("form#update").remove();
            updatecontacts();
        },
    });
return false;
});

该JavaScript片段应添加到现有的ready()函数中。 该片段添加了单击“更新”按钮时将调用的函数。 内联函数的第一行创建一个变量,通过该变量我们可以访问表单的字段。

saveDoc()函数会将JSON结构作为文档保存到Apache CouchDB。 第一个参数应该是文档数据,第二个参数是JavaScript对象,该JavaScript对象定义如果成功保存文档会发生什么情况。 请记住,用于访问信息JavaScript操作是异步的,也就是说,请求已发送到主机(Apache CouchDB),在处理信息之前,您必须等待响应返回。

该函数的第一个参数是另一个函数builddocfromform()的返回值。 这是用来简化从表单数据构造文档的过程,无论是创建新文档还是编辑现有文档。 清单13中显示了此代码。

清单13. builddocfromform()函数
function builddocfromform(doc,form) {
if (!doc) {
doc = new Object;
}
doc.name = form.find("input#name").val();
doc.phone = form.find("input#phone").val();
doc.email = form.find("input#email").val();

return(doc);
}

该函数接受现有的文档对象,如果未定义文档,则将其初始化为空JavaScript对象。 然后,它使用提供的表单jQuery对象访问表单中的每个字段,并在返回文档之前填充文档对象。 您可以在此处向函数添加更多字段(前提是您还向HTML表单添加了字段定义)。

如果文档已成功写入数据库,则将调用成功字段附带的匿名函数。 如果发生这种情况,则通过清空contactform div元素内容来删除联系人表单HTML,然后将调用updatecontacts()函数,该函数将更新显示中的活动联系人列表。

现在,您可以再次将应用程序推送到您的Apache CouchDB实例,然后尝试将联系人添加到系统中。 您最终应该在Apache CouchDB中获得一个或多个联系人, 如图2所示。

图2.一些联系人
屏幕截图显示了浏览器中联系人记录的显示,并带有指向“添加联系人”的链接。

编辑现有联系人

我们已经为编辑现有联系人奠定了许多基础。 用于输出表单JavaScript函数已经接受了现有文档,并且该表单中填充了Apache CouchDB文档ID和该对象中的现有值。

首先需要进行两项更改,以针对列表中的每个联系人启用“ 编辑联系人”链接输出。 单独创建所有这些都是一个噩梦,但是jQuery提供了通过识别目标DOM对象来识别何时单击任何链接的功能。 该信息可用于访问嵌入链接中的文档ID,然后从Apache CouchDB加载记录并调用form函数。 您可以在清单14中看到这一点。

清单14.通过确定目标DOM对象来确定何时单击了链接
$("#contacts").click(function(event) {

var target = $(event.target);
if (target.is('a')) {
id = target.attr("id");

if (target.hasClass("edit")) {
    db.openDoc(id, { success: function(doc) {
        contactform(doc);
    }});
}

}
});

这应该添加到ready()函数中。 依次执行以下代码行:

  • 第一行标识#contacts DOM元素内的点击事件。
  • 第二行标识了被单击的目标。
  • 第三行检查单击的内容是否为“ A”可点击元素。
  • 第四行标识id属性。 在联系人列表中,每个链接的id属性都包含相应联系人的文档ID。
  • 第五行标识单击的链接的类别。 “ 编辑联系人”链接具有一类edit ,“删除”链接具有一类“ remove 。 如果该链接是“编辑”链接,请访问Apache CouchDB来加载文档(使用openDoc() ),并在成功加载文档后,使用文档数据调用contactform()函数。 这将显示一个联系表单,其中包含要编辑的现有联系信息。

结果是,当您单击联系人的“编辑联系人”链接时,将显示一个包含联系人详细信息的表单。

您可能想知道为什么不使用所显示的联系信息直接填充表单。 原因是,作为一个潜在的多用户应用程序,您要确保在编辑文档之前没有其他用户更新(或删除)该文档。 因此,您要确保文档存在,并且具有存储在数据库中的最新版本。

该过程的另一半是更改当按下表单上的Submit按钮时调用的函数。 在这里,您需要确定现有记录是否正在更新。 由于contactform()函数仅在更新现有文档时才包含文档ID,因此您可以使用它来确定操作类型。 如果我们要更新现有文档,则应先从数据库中加载该文档,然后再更新表单值,然后再将文档保存回数据库。 结果代码如清单15所示。

清单15.更改按下表单上的Submit按钮时调用的函数
$("input.update").live('click', function(event) {
var form = $(event.target).parents("form#update");

var id = form.find("input#docid").val();
if (id) {
    db.openDoc(id, {
        success: function(doc) {
            db.saveDoc(builddocfromform(doc,form), {
                success: function() {
                    $("form#update").remove();
                    updatecontacts();
                }});
        },
    });
}
else
{
    db.saveDoc(builddocfromform(null,form), {
        success: function() {
            $("form#update").remove();
            updatecontacts();
        },
    });
}
return false;
});

同样,我们加载现有文档并使用builddocfromform()函数更新内容。 这样可以确保我们正在更新文档的最新版本。 这很重要,因为Apache CouchDB会记录所有文档中的修订和更改。 因此,您需要确保正在更新最新版本-版本号用作检查以确保您正在更新正确的版本。

在更新字段并将其保存回来之前,我们加载文档还有另一个原因。 就目前而言,该表单仅支持文档的名称,电话和电子邮件字段。 但是,如果文档包含此表单尚不支持的其他字段怎么办? 通过加载整个现有文档,并仅更新表单上的字段,您将不会丢失表单不知道的任何字段。

当然,有时候您想删除一条记录。

删除现有联系人

删除现有联系人应该很简单。 您可以将另一个挂钩添加到“删除联系人”链接,例如“编辑联系人”链接。 但是,您不希望意外单击“删除联系人”链接,因此您可以提供确认过程以确保需要删除。

您可以使用已经展示的一些原理来输出一组新的链接,然后使用click事件使这些新链接确认或取消删除请求。

该代码应在清单14中的edit函数之后添加。代码如清单16所示。

清单16.删除现有联系人
if (target.hasClass("remove")) {
    html = '<span class="confirm">Really Delete? ' +
        '<a href="#" id="' + id + '" class="actuallydel">Delete</a>' +
        '<a href="#" id="' + id + '" class="canceldel">Cancel</a></span>';
    target.parent().append(html);
}

if (target.hasClass("actuallydel")) {

    db.openDoc(id, {
        success: function(doc) {
            db.removeDoc(doc, { success: function() {
            target.parents("div.contactrow").remove();
            }
                               });
        }
    }
               );
}

if (target.hasClass("canceldel")) {
    target.parents("span.confirm").remove();
}

当用户单击“ 删除联系人”链接时,该联系人旁边又添加了两个链接。 如果单击“ 删除”链接,则将加载文档(以确认文档仍然存在),并removeDoc()函数将其删除。 如果成功,则将删除整个联系人行,并通过查找父DOM元素进行标识。 如果用户单击“取消”,则只需删除确认链接。

您可以在图3中看到一个等待确认删除的联系人。

图3.等待删除确认的联系人
屏幕截图显示了在浏览器中运行的应用程序,确认删除了特定联系人

最终申请

由于该过程具有所有不同的元素,因此很难看到整个应用程序。 清单17显示了recordsit.js文件,其中包含该应用程序的所有JavaScript。

清单17.recordit.js文件
db = $.couch.db("contacts");
function updatecontacts() {
    $("#contacts").empty();

    db.view("contacts/byname", {
        success: function(data) {
            for (i in data.rows) {
                $("#contacts").append('<div id="' + data.rows[i].value._id
+ '" class="contactrow"><span>' +
                                      data.rows[i].value.name +
                                      "</span><span>" +
                                      data.rows[i].value.phone +
                                      "</span><span>" +
                                      '<a href="#" id="' + data.rows[i].value._id 
+ '" class="edit">Edit Contact</a>' +
                                      "</span><span>" +
                                      '<a href="#" id="' + data.rows[i].value._id 
+ '" class="remove">Remove Contact</a>' +
                                      "</span></div>"
                                     );
            }
        }
    });
}

function contactform(doctoedit) {
var formhtml;
    formhtml =
'<form name="update" id="update" action="">';

    if (doctoedit) {
formhtml = formhtml +
    '<input name="docid" id="docid" type="hidden" value="' + doctoedit._id 
+ '"/>';
    }

    formhtml = formhtml +
'<table>';

    formhtml = formhtml +
        '<tr><td>Name</td>' +
'<td><input name="name" type="text" id="name" value="' +
(doctoedit ? doctoedit.name : '') +
'"/></td></tr>';
    formhtml = formhtml +
'<tr><td>Phone</td>' +
'<td><input name="phone" type="text" id="phone" value="' +
(doctoedit ? doctoedit.phone : '') +
'"/></td></tr>';
    formhtml = formhtml + '<tr><td>Email</td>' +
'<td><input name="email" type="text" id="email" value="' +
(doctoedit ? doctoedit.email : '') +
'"/></td></tr>';

formhtml = formhtml +
'</table>' +
'<input type="submit" name="submit" class="update" value="' +
        (doctoedit ? 'Update' : 'Add') + '"/>' +
'</form>';
    $("#contactform").empty();
    $("#contactform").append(formhtml);
}

function builddocfromform(doc,form) {
if (!doc) {
        doc = new Object;
    }
    doc.name = form.find("input#name").val();
    doc.phone = form.find("input#phone").val();
    doc.email = form.find("input#email").val();

return(doc);
}

$(document).ready(function() {

    updatecontacts();

    $("#contacts").click(function(event) {

    var target = $(event.target);
    if (target.is('a')) {
        id = target.attr("id");

        if (target.hasClass("edit")) {
            db.openDoc(id, { success: function(doc) {
        contactform(doc);
            }});
        }

if (target.hasClass("remove")) {
            html = '<span class="confirm">Really Delete? ' +
        '<a href="#" id="' + id + '" class="actuallydel">Delete</a>' +
                '<a href="#" id="' + id + '" class="canceldel">Cancel</a>
</span>';
            target.parent().append(html);
        }

if (target.hasClass("actuallydel")) {

    db.openDoc(id, {
        success: function(doc) {
            db.removeDoc(doc, { success: function() {
                    target.parents("div.contactrow").remove();
                    }
                                       });
                }
            }
                       );
        }

if (target.hasClass("canceldel")) {
            target.parents("span.confirm").remove();
        }
    }
    });

    $("a.add").live('click', function(event) {
contactform();
    });

    $("input.update").live('click', function(event) {
var form = $(event.target).parents("form#update");

        var id = form.find("input#docid").val();
        if (id) {
            db.openDoc(id, {
                success: function(doc) {
            db.saveDoc(builddocfromform(doc,form), {
                        success: function() {
                    $("form#update").remove();
                            updatecontacts();
                        }});
                },
            });
        }
        else
        {
            $db.saveDoc(builddocfromform(null,$form), {
                success: function() {
            $("form#update").remove();
                    updatecontacts();
                },
            });
        }
        return false;
    });
});

更新文件后,使用CouchApp将应用程序推送到您的Apache CouchDB实例,然后尝试一下。

还有一件事-复制您的CouchApp

Apache CouchDB的主要功能之一是,您可以将数据库中的文档复制到另一个数据库,而不管该数据库是在同一Apache CouchDB实例上还是在一个远程实例上。 同步在两个方向上进行,这意味着您可以将联系人数据库从台式机复制到便携式计算机,在离开时在便携式计算机上进行更改,然后将这些更改同步回桌面,以便两个数据库保持同步。 。

另外,作为文档存储在Apache CouchDB数据库中的CouchApps也可以同步。 这意味着,当您复制联系人数据库时,您还将复制组成CouchApp应用程序的应用程序代码。 在更传统的环境中,这将很难实现。 使用CouchApps,该功能作为Apache CouchDB功能的一部分提供。

您可以通过使用命令行工具(例如curl)将请求发送到Apache CouchDB服务器来设置复制,但是另一种方法是使用Futon工具,它是每个Apache CouchDB实例中内置的CouchApp,提供了完整的管理和编辑界面。 Apache CouchDB和存储在Apache CouchDB中数据库中的文档。

您可以通过访问http://127.0.0.1:5984/_utils访问Futon。 这显示了Futon界面, 如图4所示

图4. Futon界面
屏幕截图显示了在浏览器中运行的Futon,左侧是现有数据库列表,右侧是工具菜单

单击右侧的Replicator链接,将显示如图5所示的表单。

图5.复制器表单
屏幕快照显示了用于复制数据库的屏幕,其中包含用于选择源和目标的字段

复制既可以通过推送(从当前Apache CouchDB实例到远程数据库)进行,也可以通过拉取(从远程Apache CouchDB实例到本地Apache CouchDB实例)进行。 复制也可以执行一次,也可以将复制设置为连续复制,这意味着一个数据库上的更改将自动复制到另一个数据库(如果可用)。

例如,如果您在笔记本电脑上启动Apache CouchDB实例,则可以将联系人数据库从CouchDB服务器复制到本地联系人数据库。 您可以在图6中看到填写的表单以及启动复制过程的结果。

图6:成功复制
屏幕快照显示了成功复制后的复制窗口,其中控制台消息显示在窗口底部的事件框中

在将应用程序放在Apache CouchDB的便携式计算机实例上之后,您可以使用完全相同的界面来编辑和更新数据库,因为您已经复制了整个应用程序。 而且,您甚至可以在回家后将更改复制回桌面。

建议的改进

本教程中的屏幕快照示例可能看起来与您的应用程序有所不同,因为CSS已更新,以略微改善布局。 幸运的是,由于我们在所有不同组件(包括表单,联系人列表和链接)上使用了类和ID,因此更改格式应该很简单。 CSS是在本地文件系统上的contacts / _attachments / style / main.css文件中定义的,当您通过couchapp推送应用程序时会包含该CSS。 更改CSS可能是您可以进行的最简单的更改,以改进您的应用程序。

之后,您可能需要改善捕获的数据(可以通过更新表单和用于存储该数据的结构来对其进行修复)。 例如,如简介中所述,您可以通过将电话号码存储在文档中的单独结构中来添加对添加多个电话号码的支持。

扩展显示的信息后,您可能要开始改进联系人列表,以便可以在页面中显示它。 Apache CouchDB中的分页功能使用返回的密钥作为视图的一部分。 您可能还希望构造不同的视图并提供搜索功能,所有这些都可以通过构建和构造用于构建联系人列表的不同表示形式的其他视图来实现。

摘要

CouchApps和Apache CouchDB提供了用于构建Web应用程序的丰富环境。 构建表单,保存数据和报告数据库内容的整个过程完全存储在Apache CouchDB数据库中。 使用JavaScript和jQuery库简化了构建应用程序的许多复杂性。 同时,Apache CouchDB消除了担心定义表或编写复杂查询以获取已存储信息的麻烦。 最后,使用Apache CouchDB,您可以轻松地将整个应用程序(包括其所有数据)复制到另一个Apache CouchDB实例(包括笔记本电脑或手机)。


翻译自: https://www.ibm.com/developerworks/opensource/tutorials/os-couchapp/index.html

node命令行构建构建

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值