Статьи

Доступ к внешним данным

Для большинства веб-приложений сбор пользовательского ввода относительно бесполезен, если вы не можете передать эти данные на сервер. В этом уроке мы узнаем, как отправлять и получать информацию с сервера с помощью запросов AJAX. Это возвращает модель обратно в шаблон проектирования Model-View-ViewModel, лежащий в основе Knockout.js.

Рисунок 27: Добавление модели обратно в наш шаблон MVVM

Помните, что Knockout.js разработан для совместимости с любой другой клиентской или серверной технологией. В этой серии используются функции $.getJSON() и $ .post () jQuery , но вы можете свободно использовать любую среду JavaScript, которая может отправлять и получать данные JSON. Точно так же язык сценариев на стороне сервера полностью зависит от вас. Вместо представления примеров внутреннего кода этот урок просто включает данные JSON, ожидаемые Knockout.js. Генерация этого вывода должна быть тривиальной для реализации на любом современном языке сценариев.


Мы собираемся использовать новую HTML-страницу, чтобы поэкспериментировать с интеграцией Knockout.js / AJAX. Поскольку эта страница должна взаимодействовать с некоторым серверным кодом, убедитесь, что он доступен из корня документа вашего локального сервера. Мы начнем с чего-то похожего на предыдущий урок:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<html lang=’en’>
<head>
  <title>External Data</title>
  <meta charset=’utf-8′ />
  <link rel=’stylesheet’ href=’style.css’ />
</head>
<body>
  <h2>
 
  <form action=»#» method=»post»>
    <p>First name: <input data-bind=’value: firstName’ /></p>
    <p>Last name: <input data-bind=’value: lastName’ /></p>
    <div>
      Your favorite food:
      <select data-bind=’options: activities,
          value: favoriteHobby’></select>
    <em>Load Data</button></em></div></div>
  </form>
 
  <script src=’knockout-2.1.0.js’></script>
  <script src=’jquery-1.7.2.js’></script>
  <script>
    function PersonViewModel() {
      var self = this;
      self.firstName = ko.observable(«»);
      self.lastName = ko.observable(«»);
      self.activities = ko.observableArray([]);
      self.favoriteHobby = ko.observable(«»);
    }
 
    ko.applyBindings(new PersonViewModel());
  </script>
</body>
</html>

Это базовая форма с несколькими полями <input> чтобы мы могли видеть, как отправлять и получать информацию с сервера. Обратите внимание, что мы также включаем библиотеку jQuery перед нашим пользовательским элементом <script>.


Вы, наверное, заметили, что в отличие от предыдущих уроков, все наши наблюдаемые пустые. Вместо жесткого кодирования данных в нашу ViewModel, мы собираемся загрузить их с сервера, используя метод $.getJSON() jQuery. Во-первых, давайте создадим кнопку для загрузки данных (обычно вы автоматически загружаете данные при запуске приложения, но таким образом мы можем увидеть, как все работает пошагово):

1
<p><button data-bind=’click: loadUserData’>Load Data</button></p>

Обработчик этой кнопки использует $.getJSON() для вызова серверного скрипта:

1
2
3
4
5
self.loadUserData = function() {
  $.getJSON(«/get-user-data», function(data) {
    alert(data.firstName);
  });
}

Строка /get-user-data должна быть путем к сценарию. Опять же, поскольку он может кодировать и декодировать JSON, любой файл на стороне сервера можно использовать с Knockout.js. Для нашего примера он должен вернуть строку в формате JSON, которая выглядит примерно так:

1
2
3
4
5
6
7
8
{«firstName»:»John»,
 «lastName»:»Smith»,
 «activities»:[
    «Golf»,
    «Kayaking»,
    «Web Development»],
  «favoriteHobby»:»Golf»
}

Метод $.getJson() автоматически переводит эту строку обратно в объект JavaScript и передает ее методу-обработчику через параметр data. Тривиально обновить нашу ViewModel новой информацией:

1
2
3
4
5
6
7
8
self.loadUserData = function() {
  $.getJSON(«/get-user-data», function(data) {
    self.firstName(data.firstName);
    self.lastName(data.lastName);
    self.activities(data.activities);
    self.favoriteHobby(data.favoriteHobby);
  });
}

После нажатия кнопки « Загрузить данные» $.getJSON() загружает данные с сервера и использует их для обновления всех наблюдаемых нашей ViewModel. Как всегда, Knockout.js автоматически обновляет поля формы для соответствия.


Для обычных веб-приложений сохранение данных — это простая задача преобразования объектов в JSON и отправки их на сервер с помощью метода jQuery $.post() . Вещи несколько сложнее для приложений Knockout.js. Невозможно использовать стандартный сериализатор JSON для преобразования объекта в строку, потому что ViewModels использует наблюдаемые вместо обычных свойств JavaScript. Помните, что наблюдаемые на самом деле являются функциями, поэтому попытка их сериализации и отправки результата на сервер может привести к неожиданным результатам.

К счастью, Knockout.js предоставляет простое решение этой проблемы: служебная функция ko.toJSON() . Передача объекта в ko.toJSON () заменяет все наблюдаемые свойства объекта их текущим значением и возвращает результат в виде строки JSON.

Создайте еще одну кнопку под названием «Сохранить данные» и укажите ее на метод saveUserData() в ViewModel. Затем вы можете увидеть JSON, сгенерированный ko.toJSON () со следующим:

1
2
3
self.saveUserData = function() {
  alert(ko.toJSON(self));
}

Нажатие на эту кнопку должно отобразить текущие данные в полях формы, преобразованных в строку JSON. Теперь, когда мы избавились от всех наших наблюдаемых, мы можем отправить это на сервер для обработки:

1
2
3
4
5
6
self.saveUserData = function() {
  var data_to_send = {userData: ko.toJSON(self)};
  $.post(«/save-user-data», data_to_send, function(data) {
    alert(«Your data has been posted to the server!»);
  });
}

Это отправляет строку JSON, представляющую вашу ViewModel, в скрипт с именем /save-user-data с использованием метода POST. В результате ваш скрипт должен найти строку в записи userData в своем словаре POST. Затем вы можете десериализовать строку JSON в объект, сохранить ее в своей базе данных или выполнить любой тип обработки на стороне сервера, который вам необходим.


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

Подключаемый модуль для Knockout.js решает эту проблему, позволяя автоматически сопоставлять объекты JSON, загруженные с сервера, с наблюдаемыми объектами ViewModel. По сути, отображение является общей версией наших saveUserData() и loadUserData ().

Подключаемый модуль mapping выпущен как отдельный проект, поэтому нам необходимо загрузить его и включить в нашу HTML-страницу перед его использованием:

1
<script src=’knockout.mapping-latest.js’></script>

Далее мы собираемся полностью заменить нашу PersonViewModel . Вместо этого мы будем использовать метод $.getJSON() jQuery, чтобы загрузить некоторые исходные данные с сервера и позволить подключаемому модулю отображения динамически генерировать наблюдаемые. Замените весь пользовательский элемент <script> следующим:

1
2
3
4
5
6
<script>
  $.getJSON(«/get-user-data», function(data) {
    var viewModel = ko.mapping.fromJS(data);
    ko.applyBindings(viewModel);
  });
</script>

Когда наше приложение загружается, оно немедленно делает AJAX-запрос на исходные пользовательские данные. Ваш серверный скрипт для /get-intial-data должен возвращать то же, что и пример выходных данных JSON из раздела « Загрузка данных » этого урока. Как только данные загружены, мы создаем ViewModel через ko.mapping.fromJS() . Это берет собственный объект JavaScript, сгенерированный скриптом, и превращает каждое свойство в наблюдаемое. Помимо методов saveUserData () и loadUserData (), этот динамически генерируемый ViewModel имеет те же функции, что и PersonViewModel.

На данный момент мы только инициализировали нашу ViewModel с данными с сервера. Подключаемый модуль сопоставления также позволяет обновлять существующую ViewModel таким же образом. Давайте продолжим и добавим явный loadUserData() обратно во ViewModel:

1
2
3
4
5
viewModel.loadUserData = function() {
  $.getJSON(«/get-user-data», function(data) {
    ko.mapping.fromJS(data, viewModel);
  });
}

В старой версии loadUserData() нам приходилось вручную присваивать каждое свойство данных его соответствующей наблюдаемой. Но теперь подключаемый модуль mapping делает все это за нас. Обратите внимание, что передача объекта данных в качестве первого аргумента ko.mapping.fromJS () заставляет его обновить ViewModel вместо его инициализации .

Подключаемый модуль сопоставления относится только к загрузке данных, поэтому saveUserData() остается неизменным, за исключением того факта, что его необходимо назначить объекту viewModel:

1
2
3
4
5
6
viewModel.saveUserData = function() {
  var data_to_send = {userData: ko.toJSON(viewModel)};
  $.post(«/save-user-data», data_to_send, function(data) {
    alert(«Your data has been posted to the server!»);
  });
}

И теперь мы должны вернуться к тому, с чего начали в начале этого раздела — должны работать кнопки « Загрузить данные» и « Сохранить данные» , а Knockout.js должен поддерживать синхронизацию представления и ViewModel.

Хотя плагин mapping не является обязательным для всех проектов Knockout.js, он позволяет масштабировать сложные объекты без добавления дополнительной строки кода для каждого нового свойства, добавляемого в ViewModel.


На этом уроке мы узнали, как Knockout.js может взаимодействовать со сценарием на стороне сервера. Большая часть функциональности, связанной с AJAX, пришла из веб-инфраструктуры jQuery, хотя Knockout.js действительно предоставляет полезную функцию для преобразования своих наблюдаемых в нативные свойства JavaScript. Мы также обсудили подключаемый модуль отображения , который предоставил общий способ преобразования нативного объекта JavaScript в ViewModel с наблюдаемыми свойствами.

Помните, Knockout.js — это чисто клиентская библиотека. Это только для соединения объектов JavaScript (ViewModels) с элементами HTML. Установив эти отношения, вы можете использовать любую другую технологию, которая вам нравится, для связи с сервером. На стороне клиента вы можете заменить jQuery на Dojo, Prototype, MooTools или любую другую инфраструктуру, поддерживающую запросы AJAX. На стороне сервера у вас есть выбор ASP.NET, PHP, Django, Ruby on Rails, Perl, JavaServer Pages … вы понимаете, что это. Такое разделение интересов делает Knockout.js невероятно гибким инструментом разработки пользовательского интерфейса.

Этот урок представляет собой главу от Knockout Succinctly , бесплатной электронной книги от команды Syncfusion .