Что значит имя 7: Новые модули для Durandal и встроенные компоненты фреймворка

ru-RU | создано: 04.07.2014 | опубликовано: 04.07.2014 | обновлено: 29.12.2017 | просмотров за всё время: 3899

В этой статье будем использовать гаджеты (gadgets), которые предоставлены во фреймворке BreezeJS. Например, будем выводить модальное окно с информацией по значению для конкретной буквы имени.

Было… Будет

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

Новый модуль – Info

В прошло статье мы реализовали просмотр списка имен отфильтрованных по выбранной букве:

<div class="row">
    <div data-bind="foreach: namesByLetter">
        <div class="col-lg-3 col-sm-12 col-md-3 name">
            <a data-bind="attr:{href:'#info/'+ Name()}">
                <h1 data-bind="text: Name"></h1>
            </a>
        </div>
    </div>
</div>

В строке 4 можете заметить какой путь привязан (data-bind) к атрибуту href. Да, это – ‘#info/’+ Name(). Создадим два файла info.html и info.js в папках views и viewmodels соответственно. Пусть пока второй будет пустым, а первый наполним таким содержанием:

<b class="text-info" data-bind="html: gender"></b>
<h1>
    <!-- ko foreach: letters -->
    <a data-bind="text: $data, attr:{href:'#'}, click: $parent.showInfo"></a>
    <!-- /ko -->
</h1>

<p class="margin20">
    <span data-bind="html: item().Content()"></span>
</p>

В первой строке выводим информацию о половой принадлежности просматриваемого имени. То есть свойство gender у нас модели не существует (ни в классе NameInfo, ни в классе LetterInfo нет описания “мужское” или “женское” имя). Есть только одна буква “М” или “Ж”. Таким образом, мы будем вычислять, какая принадлежность на основании этих букв. В нашем viewmodel это свойство будет вычисляемым. В третьей строке через foreach выводим значения из списка letters, в котором хранятся буквы выбранного имени. Возможно вы не использовали еще виртуальный способ привязки, так вот в строках 3 и 5 используется именно виртуальный способ привязки. В строке 9 выводится содержание свойство Content класса NameInfo. Если вы помните, то в начале этого цикла статей, я приводил скриншот таблицы SQL-сервера с именами. В поле таблицы Content храниться не просто текст, а html-разметка. Именно поэтому в строке 9 привязка осуществятся через байндинг html, а не text.

На этом пока про представление (view) достаточно. Перейдем к модулю info.js.

В модуле буду снова опишу основные моменты после представления полного листинга:

define(['services/logger', 'knockout', 'services/dataServices',
    'durandal/app', 'services/busyIndicator', 'plugins/router'],
    function (logger, ko, dataService, app, indicator, router) {
        var
            currentName = ko.observable(),
            valueableLetters = ko.observableArray([]),
            gender = ko.observable(),
            selectedLetter,
            currentLetter = ko.observable(),
            item = ko.observable({}),
            success = function (data) {
                if (data && data.results) {
                    item(data.results[0]);
                    indicator.isbusy(false);
                }
            },
            loadData = function () {
                indicator.isbusy(true);
                var name = currentName();
                if (name) {
                    dataService.getName(name)
                        .then(success)
                        .fail(function () {
                            logger.logError('Не могу найти имя в списке', null, 'info', true);
                            router.navigate('#/notfoud');
                        }).fin(function () {
                            indicator.isbusy(false);
                        });
                }
            },
            activate = function (name) {
                splitName(name);
                currentLetter(name.substr(0, 1));
                currentName(name);
                loadData();
            },
            splitName = function (name) {
                var letters = [];
                for (var i = 0; i < name.length; i++) {
                    letters[i] = name.substr(i, 1).toUpperCase();
                }
                valueableLetters(letters);
            },
            showInfo = function (letter) {
                indicator.isbusy(true);
                selectedLetter = letter;
                dataService.getLettersInfo(letter, showMessageInfo);
            };

        item.subscribe(function (value) {
            if (value) {
                if (value.Gender() === 'М') gender('мужское имя');
                else gender('женское имя');
            }
        });

        function showMessageInfo(data) {
            indicator.isbusy(false);
            app.showMessage(data.results[0].Content(), 'Значение буквы \"' + selectedLetter + '\"');
        };

        return {
            showInfo: showInfo,
            letters: valueableLetters,
            activate: activate,
            currentName: currentName,
            currentLetter: currentLetter,
            item: item,
            gender: gender
        };
    });

Строки с 1 по 3 определяем новый модуль и вливаем зависимости, необходимые для работы модуля. С пятой под десятую строку определяем переменные. строка 5 хранит текущее имя пришедшее как параметр из активатора при переключении модуля (см. строки с 31 по 36). Это имя “разбирается на буквы и “складывается” в переменную valueableLetters определенную в строке 6. Разборки имени происходит в функции splitName (смотри строки 37-43). Строка 7 определяет свойство gender, которое является вычисляемым на основе параметров выбора пользователя. Строка 8 определяет переменную для хранения выбранной буквы из имени. В строке 9 определяем observable переменную, которая будет выводиться на UI, как информация о выбранной букве. Переменная item определенная в строке 10 является хранилищем полученного с сервера ответа, как результат запроса по фильтру, то есть объект типа NameInfo приходит с сервера в эту переменную. Наполнение и обработка происходит в методе success (смотри строки 11-16). Этот метод является callback-функцией для запроса метода сервиса, который вызывается в методе loadData (смотри строки 17-30). Метод showInfo, определенный в сорок четвертой строке, вызывается в четвертой строке предыдущего листинга, как раз при нажатии на конкретную букву имени. Этот метод использует метод сервиса getLettersInfo, а callback-функция showMessageinfo требует особого внимания. Вернемся к нему позже, а пока поговорим снова о маршрутах.

Не все маршруты проложены

Мы добавили новый модуль, а вот про маршрут до него не положен. На данный момент список маршрутов в роутере описан так:

var routes = [
    { route: ['', 'home/index'], moduleId: 'site/home', title: 'Выбор буквы', nav: true },
    { route: 'about', moduleId: 'site/about', title: 'О проекте', nav: true },
    { route: 'letter/:letter', moduleId: 'site/letter', title: 'Имена по букве', nav: false }
];

Добавим новый маршрут, который также должен понимать обязательный параметр:

var routes = [
    { route: ['', 'home/index'], moduleId: 'site/home', title: 'Выбор буквы', nav: true },
    { route: 'about', moduleId: 'site/about', title: 'О проекте', nav: true },
    { route: 'letter/:letter', moduleId: 'site/letter', title: 'Имена по букве', nav: false },
    { route: 'info/:name', moduleId: 'site/info', title: 'Значение имени', nav: false }
];

Обязательный параметр я назвал name, то в методе activate его же я и буду получать от активатора роутера.

activate = function (name) {
    splitName(name);
    currentLetter(name.substr(0, 1));
    currentName(name);
    loadData();
},

Новые методы в сервисе

Раз уж добавили маршрут, давайте еще и методы в dataServices добавим, тем более что они уже используются в листинге модели info.js. В этом листинге были упомянуты два новых метода, давайте добавим их реализацию в dataServices.js:

getName = function (name) {
    var byName = new Predicate('Name', filterOperator.Equals, name);
    var query = breeze.EntityQuery.from('Names').where(byName);
    return manager.executeQuery(query);
},

Этот метод создает запрос на сервер для получения информации по выбранному пользователем имени (смотри параметр name). Во второй строке создается предикат, где подставляется имя свойства и его значение, а также названия операции фильтрации. Строка 3 определяет запрос. А в четвертой строке этот запрос выполняется.

Второй метод, который был упомянут:

getLettersInfo = function (letter, successInfo) {
    var query = breeze.EntityQuery.from('LettersInfo').where('Name', filterOperator.Equals, letter);
    return manager.executeQuery(query, successInfo);    //});
},

Функционал этого метода тоже легко предугадать. Строка инициализации метода содержит параметры letter и successInfo, которые в свою очередь должны быть заданы при вызове метода. Первый параметр – это и есть буква, значение которой и требуется получить. Второй параметр – это callback-функция, которая должна обработать результат запроса при удачном его завершении.

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

150-10

Отлично, всё работает. Теперь поговорим про модальное окно.

Контролы DurandalJS: модальное окно

Строках 57-60 листинга модуля info.js определена callback-функция, которая выводит в модальном окне браузера информацию по толкованию значения буквы, которая присутствует в имени. Еще раз приведу этот отрывок листинга:

function showMessageInfo(data) {
    indicator.isbusy(false);
    app.showMessage(data.results[0].Content(), 'Значение буквы \"' + selectedLetter + '\"');
};

Обратите внимание на третью строку текущего листинга. Заметили метод showMessage у объекта app? Так вот этот самый объект и есть объект приложения DurandalJS, а метод вызывает модуль dialog. Чтобы компонент заработал в главном файле инициализации приложения main.js следует разрешить использовать данный модуль:

app.configurePlugins({
    router: true,
    dialog: true
});

Третья строка включает этот компонент. Запустим приложение, попробуем вывести информацию по имени Сергей, и кликнем на букву “р”

150-20

Получилось!

Заключение

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