Часть 5. Создание динамического пользовательского интерфейса с помощью Knockout.js

Рик Андерсон

Скачать завершенный проект

Создание динамического пользовательского интерфейса с помощью Knockout.js

В этом разделе мы будем использовать Knockout.js для добавления функциональных возможностей в представление Администратор.

Knockout.js — это библиотека JavaScript, которая упрощает привязку элементов управления HTML к данным. Knockout.js использует шаблон MVVM.

  • Модель — это представление данных на стороне сервера в бизнес-области (в нашем случае это продукты и заказы).
  • Представление представляет собой слой представления (HTML).
  • Модель представления — это объект JavaScript, содержащий данные модели. Модель представления — это абстракция кода пользовательского интерфейса. Он не знает представления HTML. Вместо этого он представляет абстрактные признаки представления, такие как "список элементов".

Представление привязано к модели представления. Обновления в модель представления автоматически отражаются в представлении. Модель представления также получает события из представления, такие как нажатие кнопки, и выполняет операции с моделью, такие как создание заказа.

Схема взаимодействия между данными H T M L, моделью представления, j son и контроллером Web A P I.

Схема, показывающая взаимодействие между данными H T M L, моделью представления, j son и контроллером Web A P I. Поле данных H T M L имеет метку представления. Привязка данных с двойной стрелкой связывает поле данных H T M L с полем модели представления. Двойная стрелка с меткой H T TP requests and j son model from server связывает модель представления с контроллером Web A P I.

Сначала мы определим модель представления. После этого мы привяжем разметку HTML к модели представления.

Добавьте следующий раздел Razor в файл Администратор.cshtml:

@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>
}

Этот раздел можно добавить в любом месте файла. При отображении представления раздел отображается в нижней части HTML-страницы прямо перед закрывающим <тегом /body> .

Весь скрипт для этой страницы будет находиться внутри тега скрипта, указанного в примечании:

<script type="text/javascript">
  // View-model will go here
  </script>

Сначала определите класс модели представления:

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

ko.observableArray — это особый вид объекта в Нокауте, называемый наблюдаемым. Из документации поKnockout.js: наблюдаемый объект — это "объект JavaScript, который может уведомлять подписчиков об изменениях". При изменении содержимого наблюдаемого изменения представление автоматически обновляется в соответствии с данными.

Чтобы заполнить products массив, сделайте запрос AJAX к веб-API. Напомним, что мы сохранили базовый URI для API в контейнере представлений (см . часть 4 руководства).

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

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

Затем добавьте функции в модель представления для создания, обновления и удаления продуктов. Эти функции передают вызовы AJAX в веб-API и используют результаты для обновления модели представления.

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.
        $(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);
}

Теперь самая важная часть: При заполнении модели DOM вызовите функцию ko.applyBindings и передайте новый экземпляр ProductsViewModel:

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

Метод ko.applyBindings активирует Knockout и подключает модель представления к представлению.

Теперь, когда у нас есть модель представления, мы можем создать привязки. В Knockout.js это можно сделать путем добавления data-bind атрибутов в элементы HTML. Например, чтобы привязать список HTML к массиву, используйте привязку foreach :

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

Привязка foreach выполняет итерацию по массиву и создает дочерние элементы для каждого объекта в массиве. Привязки дочерних элементов могут ссылаться на свойства объектов массива.

Добавьте следующие привязки в список 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>

Элемент <li> находится в область привязки foreach. Это означает, что Knockout будет отображать элемент один раз для каждого продукта в массиве products . Все привязки в элементе <li> ссылаются на этот экземпляр продукта. Например, $data.Name ссылается на Name свойство продукта.

Чтобы задать значения входных текстовых данных, используйте привязку value . Кнопки привязаны к функциям в представлении модели с помощью привязки click . Экземпляр продукта передается в качестве параметра каждой функции. Дополнительные сведения см. в документации поKnockout.js с хорошим описанием различных привязок.

Затем добавьте привязку для события отправки в форму Добавить продукт:

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

Эта привязка вызывает функцию create в модели представления для создания нового продукта.

Ниже приведен полный код для представления Администратор.

@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
              $(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
              $.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>

Запустите приложение, войдите в систему с учетной записью администратора и щелкните ссылку "Администратор". Вы увидите список продуктов и сможете создавать, обновлять или удалять продукты.