原文:【ASP.NET Web API教程】2.3.5 用Knockout.js创建动态UI

注:本文是【ASP.NET Web API系列教程】的一部分,如果您是第一次看本博客文章,请先看前面的内容。

Part 5: Creating a Dynamic UI with Knockout.js

第5部分:用Knockout.js创建动态UI

本文引自:http://www.asp.net/web-api/overview/creating-web-apis/using-web-api-with-entity-framework/using-web-api-with-entity-framework,-part-5

Creating a Dynamic UI with Knockout.js

用Knockout.js创建动态UI

In this section, we'll use Knockout.js to add functionality to the Admin view.

在本小节中,我们将用Knockout.js对Admin视图添加功能。

Knockout.js is a Javascript library that makes it easy to bind HTML controls to data. Knockout.js uses the Model-View-ViewModel (MVVM) pattern.

Knockout.js是一个JavaScript库,它让HTML控件很容易与数据进行绑定。Knockout.js使用的是“模型-视图-视图模型(MVVM)”模式。

  • The model is the server-side representation of the data in the business domain (in our case, products and orders).

    模型是事务域中数据的服务器端表示(在我们的示例中,是产品和订单)。
  • The view is the presentation layer (HTML).

    视图是表现层(HTML)。
  • The view-model is a Javascript object that holds the model data. The view-model is a code abstraction of the UI. It has no knowledge of the HTML representation. Instead, it represents abstract features of the view, such as "a list of items".

    视图模型是保存了模型数据的一个JavaScript对象。视图模型是UI的一种代码抽象。它没有HTML表示方面的知识,但它表现了视图的抽象特性,如“列表项”。

The view is data-bound to the view-model. Updates to the view-model are automatically reflected in the view. The view-model also gets events from the view, such as button clicks, and performs operations on the model, such as creating an order.

视图是与视图模型数据绑定的。对视图模型的更新会自动地在视图得到反映。视图模型也会获取视图的事件,如按钮点击,并在模型上执行操作(见图2-23)。

图2-23. 模型-视图-视图模型之间的关系

First we'll define the view-model. After that, we will bind the HTML markup to the view-model.

首先,我们要定义视图模型。之后,要将HTML标记与视图模型进行绑定。

Add the following Razor section to Admin.cshtml:

对Admin.cshtml添加以下Razor片段:

@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript" src="@Url.Content("~/Scripts/knockout-2.1.0.js")"></script>
<script type="text/javascript">
// View-model will go here
// 视图模型会放在这儿
</script>
}

You can add this section anywhere in the file. When the view is rendered, the section appears at the bottom of the HTML page, right before the closing </body> tag.

可以把这个片断添加到文件的任何地方。当视图被渲染时,这个片段会出现在HTML页面的底部,</body>关闭标签的前面。

All of the script for this page will go inside the script tag indicated by the comment:

用于这个页面的所有脚本都被放在由以下注释所指示的script标签中:

<script type="text/javascript">
// View-model will go here
// 视图模型会放在这儿
</script>

First, define a view-model class:

首先,定义一个视图模型类:

function ProductsViewModel() {
var self = this;
self.products = ko.observableArray();
}

ko.observableArray is a special kind of object in Knockout, called an observable. From the Knockout.js documentation: An observable is a “JavaScript object that can notify subscribers about changes.” When the contents of an observable change, the view is automatically updated to match.

ko.observableArray是Knockout中的一种叫做observable的特殊对象(请将这种observable对象称为可见对象。这种对象往往作为视图模型与视图进行交互,对视图而言,它是透明可见的,故称为可见对象。在以下翻译中,都将这种observable对象称为可见对象 — 译者注)。根据Knockout.js文档的描述:可见对象是一种“能够通知订户数据变化情况的JavaScript对象”。当一个可见对象的内容发生变化时,视图会自动地进行匹配更新。

To populate the products array, make an AJAX request to the web API. Recall that we stored the base URI for the API in the view bag (see Part 4 of the tutorial).

为了填充Products数组,需要形成一个发送到Web API的请求。调回我们在视图包(View Bag)中存储的、用于此API的基URI(见本教程的第4部分)。

function ProductsViewModel() {
var self = this;
self.products = ko.observableArray();

// New code
// 新代码
var baseUri = '@ViewBag.ApiUrl';
$.getJSON(baseUri, self.products);
}

Next, add functions to the view-model to create, update, and delete products. These functions submit AJAX calls to the web API and use the results to update the view-model.

下一步,对视图模型添加创建、更新以及删除产品的函数。这些函数会对Web API递交AJAX调用,并使用(所得到的)结果对视图模型进行更新。

function ProductsViewModel() {
var self = this;
self.products = ko.observableArray();

var baseUri = '@ViewBag.ApiUrl';

// New code
// 新代码
self.create = function (formElement) {
// If the form data is valid, post the serialized form data to the web API.
// 如果表单数据有效,把序列化的表单数据递交给Web API
$(formElement).validate();
if ($(formElement).valid()) {
$.post(baseUri, $(formElement).serialize(), null, "json")
.done(function (o) {
// Add the new product to the view-model.
// 将新产品添加到视图模型
self.products.push(o);
});
}
}

self.update = function (product) {
$.ajax({ type: "PUT", url: baseUri + '/' + product.Id, data: product });
}

self.remove = function (product) {
// First remove from the server, then from the view-model.
// 首先从服务器删除,然后从视图模型删除
$.ajax({ type: "DELETE", url: baseUri + '/' + product.Id })
.done(function () { self.products.remove(product); });
}

$.getJSON(baseUri, self.products);
}

Now the most important part: When the DOM is fulled loaded, call the ko.applyBindings function and pass in a new instance of the ProductsViewModel:

现在,最重要的部分:当DOM全部装载时,调用ko.applyBindings函数,并在其中传递一个新的ProductsViewModel实例:

$(document).ready(function () {
ko.applyBindings(new ProductsViewModel());
})

The ko.applyBindings method activates Knockout and wires up the view-model to the view.

ko.applyBindings方法会激活Knockout,并将视图模型与视图连接起来。

Now that we have a view-model, we can create the bindings. In Knockout.js, you do this by adding data-bind attributes to HTML elements. For example, to bind an HTML list to an array, use the foreach binding:

现在,我们有了一个视图模型,于是可以创建绑定(这里的绑定含义是将视图模型中的数据项与视图中的各个HTML控件进行绑定 — 译者注)。在Knockout.js中,通过把data-bind标签属性(标签属性是指HTML元素的属性,这样翻译的目的也是与类的属性有所区别 — 译者注)添加到HTML元素的办法来做这件事。例如,要把一个HTML列表绑定到一个数据,使用foreach绑定:

<ul id="update-products" data-bind="foreach: products">

The foreach binding iterates through the array and creates child elements for each object in the array. Bindings on the child elements can refer to properties on the array objects.

foreach绑定会遍历数组,并为数组中的每个对象创建子元素。在子元素上的绑定可以指向数组对象上的属性。

Add the following bindings to the "update-products" list:

对“update-products”列表添加以下绑定:

<ul id="update-products" data-bind="foreach: products">
<li>
<div>
<div class="item">Product ID</div> <span data-bind="text: $data.Id"></span>
</div>
<div>
<div class="item">Name</div>
<input type="text" data-bind="value: $data.Name"/>
</div>
<div>
<div class="item">Price ($)</div> <!-- 这里的$表示的美元符字符 — 译者注 -->
<input type="text" data-bind="value: $data.Price"/>
</div>
<div>
<div class="item">Actual Cost ($)</div>
<input type="text" data-bind="value: $data.ActualCost"/>
</div>
<div>
<input type="button" value="Update" data-bind="click: $root.update"/>
<input type="button" value="Delete Item" data-bind="click: $root.remove"/>
</div>
</li>
</ul>

The <li> element occurs within the scope of the foreach binding. That means Knockout will render the element once for each product in the products array. All of the bindings within the <li> element refer to that product instance. For example, $data.Name refers to the Name property on the product.

<li>元素出现在foreach绑定的范围之内。这意味着Knockout会对products数组中的每个产品渲染一个元素。在<li>元素中的所有绑定指向这个产品实例。例如,$data.Name是指该产品上的Name属性。

To set the values of the text inputs, use the value binding. The buttons are bound to functions on the model-view, using the click binding. The product instance is passed as a parameter to each function. For more information, the Knockout.js documentation has good descriptions of the various bindings.

设置文本输入框的值,要使用value绑定。按钮要绑定到视图模型上的函数,需使用click绑定。产品实例是作为参数传递给每个函数的。对于更多信息,Knockout.js文档对各种绑定有很好的描述。

Next, add a binding for the submit event on the Add Product form:

下一步,为“添加产品”表单上的submit(递交)事件添加一个绑定:

<form id="addProduct" data-bind="submit: create">

This binding calls the create function on the view-model to create a new product.

这个绑定调用视图模型上的create函数,以创建一个新产品。

Here is the complete code for the Admin view:

以下是Admin视图的完整代码:

@model ProductStore.Models.Product

@{
ViewBag.Title = "Admin";
}

@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript" src="@Url.Content("~/Scripts/knockout-2.0.0.js")"></script>
<script type="text/javascript">
function ProductsViewModel() {
var self = this;
self.products = ko.observableArray();

var baseUri = '@ViewBag.ApiUrl';

self.create = function (formElement) {
// If valid, post the serialized form data to the web api
// 如果有效,把序列化的表单数据递交(post)给Web API
$(formElement).validate();
if ($(formElement).valid()) {
$.post(baseUri, $(formElement).serialize(), null, "json")
.done(function (o) { self.products.push(o); });
}
}

self.update = function (product) {
$.ajax({ type: "PUT", url: baseUri + '/' + product.Id, data: product });
}

self.remove = function (product) {
// First remove from the server, then from the UI
// 先从服务器删除,然后从UI删除
$.ajax({ type: "DELETE", url: baseUri + '/' + product.Id })
.done(function () { self.products.remove(product); });
}

$.getJSON(baseUri, self.products);
}

$(document).ready(function () {
ko.applyBindings(new ProductsViewModel());
})
</script>
}

<h2>Admin</h2>
<div class="content">
<div class="float-left">
<ul id="update-products" data-bind="foreach: products">
<li>
<div>
<div class="item">Product ID</div> <span data-bind="text: $data.Id"></span>
</div>
<div>
<div class="item">Name</div>
<input type="text" data-bind="value: $data.Name"/>
</div>
<div>
<div class="item">Price ($)</div>
<input type="text" data-bind="value: $data.Price"/>
</div>
<div>
<div class="item">Actual Cost ($)</div>
<input type="text" data-bind="value: $data.ActualCost"/>
</div>
<div>
<input type="button" value="Update" data-bind="click: $root.update"/>
<input type="button" value="Delete Item" data-bind="click: $root.remove"/>
</div>
</li>
</ul>
</div>

<div class="float-right">
<h2>Add New Product</h2>
<form id="addProduct" data-bind="submit: create">
@Html.ValidationSummary(true)
<fieldset>
<legend>Contact</legend>
@Html.EditorForModel()
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
</form>
</div>
</div>

Run the application, log in with the Administrator account, and click the "Admin" link. You should see the list of products, and be able to create, update, or delete products.

运行应用程序,用Administrator账号登录,并点击“Admin”链接。应当看到产品列表,并能够创建、更新或删除产品。

看完此文如果觉得有所收获,恳请给个推荐

【ASP.NET Web API教程】2.3.5 用Knockout.js创建动态UI的更多相关文章

  1. 【ASP.NET Web API教程】3.2 通过.NET客户端调用Web API(C#)

    原文:[ASP.NET Web API教程]3.2 通过.NET客户端调用Web API(C#) 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的 ...

  2. 【ASP.NET Web API教程】3 Web API客户端

    原文:[ASP.NET Web API教程]3 Web API客户端 Chapter 3: Web API Clients 第3章 Web API客户端 本文引自:http://www.asp.net ...

  3. 【ASP.NET Web API教程】2.4 创建Web API的帮助页面

    原文:[ASP.NET Web API教程]2.4 创建Web API的帮助页面 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. 2.4 ...

  4. 【ASP.NET Web API教程】2.3.7 创建首页

    原文:[ASP.NET Web API教程]2.3.7 创建首页 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. Part 7: Crea ...

  5. 【ASP.NET Web API教程】2.3.6 创建产品和订单控制器

    原文:[ASP.NET Web API教程]2.3.6 创建产品和订单控制器 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. Part 6 ...

  6. 【ASP.NET Web API教程】2.3.4 创建Admin视图

    原文:[ASP.NET Web API教程]2.3.4 创建Admin视图 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. Part 4: ...

  7. 【ASP.NET Web API教程】2.3.3 创建Admin控制器

    原文:[ASP.NET Web API教程]2.3.3 创建Admin控制器 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. Part 3 ...

  8. 【ASP.NET Web API教程】2.3.2 创建域模型

    原文:[ASP.NET Web API教程]2.3.2 创建域模型 Part 2: Creating the Domain Models 第2部分:创建域模型 本文引自:http://www.asp. ...

  9. 【ASP.NET Web API教程】2.3 与实体框架一起使用Web API

    原文:[ASP.NET Web API教程]2.3 与实体框架一起使用Web API 2.3 Using Web API with Entity Framework 2.3 与实体框架一起使用Web ...

随机推荐

  1. CentOS服务器下对mysql的优化

    原文链接: CentOS服务器下对mysql的优化 一.mysql的优化思路 mysql的优化分为两方面: 1. 服务器使用前的优化 2. 服务使用中的优化 二.mysql的基础优化步骤 1. 硬件级 ...

  2. Python框架 Flask 项目实战教程

    本文目的是为了完成一个项目用到的flask基本知识,例子会逐渐加深.最好对着源码,一步一步走.下载源码,运行pip install -r requirements.txt 建立环境python db_ ...

  3. POJ 3675 Telescope 简单多边形和圆的面积交

    这道题得控制好精度,不然会贡献WA  QAQ 还是那个规则: int sgn(double x){ if(x > eps) return 1; else if(x < - eps) ret ...

  4. mul8_unsigned multipliter

    李亚民老师更注重硬件设计思想的训练.他给出的硬件设计方法更贴近底层硬件,下面看看他的设计思想:                                                      ...

  5. ascii码所有字符对照表(包含汉字和外国文字)

    http://www.0xaa55.com/thread-398-1-1.html看到了0xaa55的这个帖子,想起了2年前我在51cto发的一个帖子http://down.51cto.com/dat ...

  6. NodeJS用Express建立project

    1.通过下面命令建立站点基本结构: <span style="margin: 0px; padding: 0px; font-family: Verdana, Arial, Helve ...

  7. java socket线程通信

    关于socket线程通信的一些知识整理 一般我们需要要让两台机子进行通信,需要创建一个Server 类,一个Client类,还需要创建一个线程类 server public class Server ...

  8. ListView优化问题

    可以参考:http://blog.csdn.net/bill_ming/article/details/8817172和http://blog.csdn.net/xiangjai/article/de ...

  9. 自己用js写的两个日历控件

    前一阵写了两个日历控件,做了简单的封装,发出来共朋友们参考. 第一个日历控件,条状的日历. (使用方法:调用initBarTime(id,evn),第一个参数是要渲染div的id,第二个参数是点击日期 ...

  10. docker学习笔记3:镜像操作(查找和下载)

    一.查看本地镜像 只有下载后,镜像才会保存在本地(docker环境所在的主机),通过如下命令可以查看本地已经存在的镜像. 命令:dokcer images 上面命令列出本地所有已经存在的镜像,显示的信 ...