Как стать автором
Обновить

Декларативная привязка данных в WinJS

Время на прочтение12 мин
Количество просмотров1.9K
Перевод статьи «Metro: Declarative Data Binding», Stephen Walther

Целью этой статьи является описание того, как декларативная привязка данных работает в библиотеке WinJS. В частности, вы научитесь использовать атрибуты data-win-bind и data-win-bindsource. Также вы научитесь использованию вычисляемых свойств и конвертеров для автоматического форматирования значения свойств при привязке данных.

Пользуясь привязкой данных в WinJS, вы можете использовать шаблон Model-View-ViewModel (MVVM), при построении приложений в стиле Metro на языке JavaScript. Используя шаблон MVVM вы защищаете свой код от обращения в хаос. Шаблон MVVM предоставляет вам стандартный способ организации JavaScript кода, что делает ваше приложение более легко-поддерживаемым.

Использование декларативной привязки


Вы можете использовать атрибут data-win-bind с любым HTML элементом на странице. Аттрибут data-win-bind позволяет вам связывать HTML аттрибут со свойством Javascript объекта.

Например, вам нужно создать страницу о некоем продукте и вам нужно отобразить информациию об этом продукте на странице.
В этом случае, вы можете создать следующую HTML страничку, чтобы показать детали о продукте:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Application1</title>
 
    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
    <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
    <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>
 
    <!-- Application1 references -->
    <link href="http://3a0ojxkezud2pogen3j4z0w18nq.wpengine.netdna-cdn.com/css/default.css" rel="stylesheet">
    <script src="http://3a0ojxkezud2pogen3j4z0w18nq.wpengine.netdna-cdn.com/js/default.js"></script>
</head>
<body> 
    <h1>Product Details</h1>
 
    <div class="field">
        Product Name:
        <span data-win-bind="innerText:name"></span>
    </div>
    <div class="field">
        Product Price:
        <span data-win-bind="innerText:price"></span>
    </div>
    <div class="field">
        Product Picture:
        <br />
        <img data-win-bind="src:photo;alt:name" />
    </div> 
</body>
</html>

Страница выше содержит три data-win-bind атрибута – по одному атрибуту на на каждое свойство продукта. Мы используем атрибут data-win-bind attribute, чтобы установить свойства HTML элемента. Атрибут data-win-bind принимает список пар <свойство элемента>: <свойство модели> разделенные точкой с запятой:

data-win-bind=”elementPropertyName:datasourcePropertyName; elementPropertyName:datasourcePropertyName;…”

На данной страничке первые два data-win-bind атрибута используются для установки свойства innerText в SPAN элементах. Последний data-win-bind атрибут используется для атрибутов src и alt элемента IMG.

Кстати говоря, использование атрибута data-win-bind является полностью валидным в HTML5. Стандарты HTML5 позволяют вам добавлять пользовательские атрибуты в HTML документ, предваряя их префиксом data-. таким образом вы можете добавлять в HTML5 документ кастомные атрибуты с именами как: data-stephen, data-funky, or data-rover-dog-is-hungry и ваш документ будет оставаться валидным.

Объект продукта, отображенного на страничке выше, создается в файле default.js:

(function () {
    "use strict";
 
    var app = WinJS.Application;
 
    app.onactivated = function (eventObject) {
        if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
 
            var product = {
                name: "Tesla",
                price: 80000,
                photo: "/images/TeslaPhoto.png"
            };
 
            WinJS.Binding.processAll(null, product);
        }
    };
 
    app.start();
})();

В данном коде, объект продукта создается со свойствами name, price и photo. Метод WinJS.Binding.processAll() вызывается для выполнения привязки модели к представлению (Не перепутайте методы WinJS.Binding.processAll() и WinJS.UI.processAll() – это совершенно разные методы).

Первый параметр метода processAll() представляет корневой элемент для привязки. Другими словами, привязка происходит к этому элементу и всем его потомкам. Если вы укажете null, то привязка произойдет ко всему телу документа (document.body).

Второй параметр представляет контекст данных. Это объект свойства, которого отображаются при помощи атрибутов data-win-bind. В коде представленном ниже, объект продукта передан как параметр контекста данных. Другими словами контекст данных это модель представления.

Создание сложных моделей представления


В предыдущем разделе, мы использовали атрибут data-win-bind, чтобы отобразить свойства простого объекта: одиночного продукта. Но также, мы можем использовать привязку с более сложными моделями представления, в том числе модели представления, которые представляют иерархию объектов.

Например, модель представления в следующем default.js файле представляет два объекта customer и product. В свою очередь, объект customer содержит объект address:

(function () {
    "use strict";
 
    var app = WinJS.Application;
 
    app.onactivated = function (eventObject) {
        if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
            var viewModel = {
                customer: {
                    firstName: "Fred",
                    lastName: "Flintstone",
                    address: {
                        street: "1 Rocky Way",
                        city: "Bedrock",
                        country: "USA"
                    }
                },
                product: {
                    name: "Bowling Ball",
                    price: 34.55
                }
            };
 
            WinJS.Binding.processAll(null, viewModel);
 
        }
    };
 
    app.start();
})();

Следующая страница отображает информацию о пользователе (включая адрес), а также продукт. Обратите внимание на использование точки для доступа к дочерним объектам модели, как например: customer.address.street.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Application1</title>
 
    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
    <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
    <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>
 
    <!-- Application1 references -->
    <link href="http://3a0ojxkezud2pogen3j4z0w18nq.wpengine.netdna-cdn.com/css/default.css" rel="stylesheet">
    <script src="http://3a0ojxkezud2pogen3j4z0w18nq.wpengine.netdna-cdn.com/js/default.js"></script>
</head>
<body>
    <h1>Customer Details</h1>
 
    <div class="field">
        First Name:
        <span data-win-bind="innerText:customer.firstName"></span>
    </div>
    <div class="field">
        Last Name:
        <span data-win-bind="innerText:customer.lastName"></span>
    </div>
    <div class="field">
        Address:
        <address>
            <span data-win-bind="innerText:customer.address.street"></span>
            <br />
            <span data-win-bind="innerText:customer.address.city"></span>
            <br />
            <span data-win-bind="innerText:customer.address.country"></span>
        </address>
    </div>
 
    <h1>Product</h1>
 
    <div class="field">
        Name:
        <span data-win-bind="innerText:product.name"></span>
    </div>
 
    <div class="field">
        Price:
        <span data-win-bind="innerText:product.price"></span>
    </div>
</body>
</html>

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

Создание вычисляемых свойств


Иногда вам может понадобиться модифицировать свойства при их отображении.

Например, вам нужно форматировать цену продукта при ее отображении. Вам не хочется отображать цену продукта в таком виде “80000”. Вместо этого, вам нужно отображать цену предварительно отформатировав ее: “$80 000”.

Также вам может быть нужно отображать несколько свойств скомбинировано. Как например ФИО, состоит из полей Фамилия, Имя и Отчество.

В таких случаях будет удобно вызывать методы в привязке данных. Например вы можете создать метод fullName(), который будет конкатенировать имя и фамилию. К сожалению, WinJS не поддерживает следующий синтаксис:

<span data-win-bind=”innerText:fullName()”></span>

Вместо этого, в таких случаях, вам нужно создать в модели представления свойство с геттером(getter). Например объект customer в файле default.js содержит свойство fullName которое конкатенирует свойства firstName и lastName:

(function () {
    "use strict";
 
    var app = WinJS.Application;
 
    app.onactivated = function (eventObject) {
        if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
            var customer = {
                firstName: "Fred",
                lastName: "Flintstone",
                get fullName() {
                    return this.firstName + " " + this.lastName;
                }
            };
 
            WinJS.Binding.processAll(null, customer);
 
        }
    };
 
    app.start();
})();

Таким образом, объект customer содержит свойства firstName, lastName и fullName. Обратите внимание, что свойство fullName объявлено с геттер(getter) функцией. Когда вы используете свойство fullName, значения свойств firstName и lastName контатеннируются и возвращаются единой строкой.

На следующей HTML странице отображено свойство fullName в H1 элементе. Вы можете использовать свойство fullName в data-win-bind атрибуте так же, как и любое другое свойство.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Application1</title>
 
    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
    <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
    <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>
 
    <!-- Application1 references -->
    <link href="http://3a0ojxkezud2pogen3j4z0w18nq.wpengine.netdna-cdn.com/css/default.css" rel="stylesheet">
    <script src="http://3a0ojxkezud2pogen3j4z0w18nq.wpengine.netdna-cdn.com/js/default.js"></script>
</head>
<body> 
    <h1 data-win-bind="innerText:fullName"></h1>
 
    <div class="field">
        First Name:
        <span data-win-bind="innerText:firstName"></span>
    </div>
    <div class="field">
        Last Name:
        <span data-win-bind="innerText:lastName"></span>
    </div>
</body>
</html>

Создание конвертеров


В предыдущем разделе вы научились преобразовывать значения свойств при помощи создания getter свойств. Этот подход имеет смысл, когда логика форматирования является частной для данной модели представления.

Если же вам нужно применить одни действия по форматированию для разных моделей, тоогда есть смысл создать функцию-конвертер. Конвертер это функция, которую вы можете применить при любом использовании атрибута data-win-bind.

Представьте, например, что вам нужно создать общий метод для отображения дат. И вы хотите всегда отображать даты в коротком формате 12/25/1988. Следующий файл под названием converters.js – содержит конвертер shortDate():

(function (WinJS) { 
    var shortDate = WinJS.Binding.converter(function (date) {
        return date.getMonth() + 1 +
            "/" + date.getDate() +
            "/" + date.getFullYear();
    });
 
    // Export shortDate
    WinJS.Namespace.define("MyApp.Converters", {
        shortDate: shortDate
    });
})(WinJS);

В файле приведенном выше используется шаблон Модуль, этот используется повсеместно в библиотеке WinJS. Чтобы узнать больше о шаблоне Модуль, читайте мою заметку о пространствах имен и модулях:
http://stephenwalther.com/blog/archive/2012/02/22/windows-web-applications-namespaces-and-modules.aspx

Файл содержит определение функции shortDate(). Эта функция преобразует встроенный в JavaScript объект даты в короткую строку даты 12/1/1988.

Конвертер создан при помощи метода создания конвертеров WinJS.Binding.converter(). Этот метод принимает обычную функцию и возвращает конвертер.

И наконец, конвертер shortDate() добавляется в пространство имен MyApp.Converters. Вы можете вызвать функцию shortDate() вызвав MyApp.Converters.shortDate().

Файл default.js содержит объект пользователя, который мы хотим привязать. Объект пользователя содержит свойства firstName, lastName и birthday. Мы воспользуемся нашим новым новым конвертером shortDate() при отображении свойства birthday объекта пользователя:

(function () {
    "use strict";
 
    var app = WinJS.Application;
 
    app.onactivated = function (eventObject) {
        if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
 
            var customer = {
                firstName: "Fred",
                lastName: "Flintstone",
                birthday: new Date("12/1/1988")
            };
 
            WinJS.Binding.processAll(null, customer);
        }
    };
 
     app.start();
})();

И в результате мы используем наш конвертер shortDate в HTML документе. Следующий HTML документ отображает все свойства объекта пользователя:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Application1</title>
 
    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
    <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
    <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>
 
    <!-- Application1 references -->
    <link href="http://3a0ojxkezud2pogen3j4z0w18nq.wpengine.netdna-cdn.com/css/default.css" rel="stylesheet">
    <script src="http://3a0ojxkezud2pogen3j4z0w18nq.wpengine.netdna-cdn.com/js/default.js"></script>
    <script type="text/javascript" src="js/converters.js"></script>
</head>
<body> 
    <h1>Customer Details</h1>
 
    <div class="field">
        First Name:
        <span data-win-bind="innerText:firstName"></span>
    </div>
    <div class="field">
        Last Name:
        <span data-win-bind="innerText:lastName"></span>
    </div>
    <div class="field">
        Birthday:
        <span data-win-bind="innerText:birthday MyApp.Converters.shortDate"></span>
    </div> 
</body>
</html>

Заметьте, как атрибут data-win-bind используется для отображения свойства birthday:

<span data-win-bind="innerText:birthday MyApp.Converters.shortDate"></span>

Конвертер shortDate применяется к свойству birthday когда оно привязывается к свойству innerText элемента SPAN.

Использование data-win-bindsource


Обычно вы определяете модель представления (контекст данных), которую вы будете использовать на в атрибутах data-win-bind, передавая ее параметром в метод WinJS.Binding.processAll() таким образом:

WinJS.Binding.processAll(null, viewModel);

Как вариант, вы можете декларативно указывать модель в вашей разметке при помощи атрибута data-win-datasource. Например, в скрипте default.js мы предоставляем доступ к модели представления. Мы можем получить модель, при помощи указания полного пути — MyWinWebApp.viewModel:

(function () {
    "use strict";
 
    var app = WinJS.Application;
 
    app.onactivated = function (eventObject) {
        if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
 
            // Create view model
            var viewModel = {
                customer: {
                    firstName: "Fred",
                    lastName: "Flintstone"
                },
                product: {
                    name: "Bowling Ball",
                    price: 12.99
                }
            };
 
            // Export view model to be seen by universe
            WinJS.Namespace.define("MyWinWebApp", {
                viewModel: viewModel
            });
 
            // Process data-win-bind attributes
            WinJS.Binding.processAll();
        }
    };

    app.start();
})();

В коде выше модель представления с полями пользователь и продукт представлена как MyWinWebApp.viewModel.

Следующая HTML страница показывает, как можно использовать атрибут data-win-bindsource чтобы привязаться в этой модели представления:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Application1</title>
 
    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
    <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
    <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>
 
    <!-- Application1 references -->
    <link href="http://3a0ojxkezud2pogen3j4z0w18nq.wpengine.netdna-cdn.com/css/default.css" rel="stylesheet">
    <script src="http://3a0ojxkezud2pogen3j4z0w18nq.wpengine.netdna-cdn.com/js/default.js"></script>
</head>
<body>
 
    <h1>Customer Details</h1>
    <div data-win-bindsource="MyWinWebApp.viewModel.customer">
        <div class="field">
            First Name:
            <span data-win-bind="innerText:firstName"></span>
        </div>
        <div class="field">
            Last Name:
            <span data-win-bind="innerText:lastName"></span>
        </div>
    </div>
 
    <h1>Product</h1>
    <div data-win-bindsource="MyWinWebApp.viewModel.product">
        <div class="field">
            Name:
            <span data-win-bind="innerText:name"></span>
        </div>
 
        <div class="field">
            Price:
            <span data-win-bind="innerText:price"></span>
        </div>
    </div>
 
</body>
</html>

Атрибут data-win-bindsource дважды используется на странице выше: он используется в элементе, который содержит детали пользователя а также в элементе, который содержит детали о продукте.

Контекст модели заданной атрибутом data-win-bindsource передается во все дочерние элементы. Атрибуты data-win-bind дочерних элементов привязываются к контексту заданному атрибутом data-win-bindsource.

Итоги


Эта заметка была посвящена привязке данных в библиотеке WinJS. Вы научились использовать аттрибут data-win-bind для связывания атрибутов HTML элементов к модели представления. Также мы рассмотрели несколько дополнительных фич привязки данных. Мы разобрались с использованием вычисляемых свойств, при помощи использования свойств с гетерами (getter) в модели представления. Также мы рассмотрели, как можно создавать конвертеры для форматирования значения модели представления при привязке свойств. И наконец, вы изучили, как использовать атрибут data-win-bindsource для декларативного указания модели представления.
Теги:
Хабы:
+2
Комментарии1

Публикации

Изменить настройки темы

Истории

Работа

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн