Статьи

Одностраничное приложение с Knockout.js: Часть 2

Давайте начнем с того, где мы остановились. Загрузите исходный код предыдущей части, разархивируйте его и откройте в Visual Studio.

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

Давайте перейдем к следующему шагу в нашем небольшом приложении CRUD и добавим поддержку создания новых расписаний.

Содержание

модальный

Давайте представим пользователю возможность добавить новый график. Скопируйте / вставьте следующий HTML-код чуть ниже таблицы в представлении Index.cshtml.

<div class="pull-right">
    <a id="new-timesheet" class="btn btn-success"
       data-toggle="modal" href="#timesheet-modal">Add timesheet</a>
</div>

Это отобразит следующую кнопку под правым нижним углом таблицы.

Добавить расписание

Это демонстрирует некоторые из базовых CSS Twitter Bootstrap для быстрого рендеринга круто выглядящих кнопок .

Кнопка здесь является простым якорем. Заметьте атрибуты data-toggle и href на привязке? Bootstrap магия снова работает. Атрибут data-toggle в основном говорит Bootstrap, что при нажатии кнопки отображается модальное окно с id (href) «timesheet-modal». Кнопка (data-) переключает модальное окно.

Время добавить актуальный модал. Вставьте следующий HTML-код под кнопкой.

<div class="modal hide fade" id="timesheet-modal">
    <div class="modal-header">
        <button type="button" class="close" 
                data-dismiss="modal">×</button>
        <h3>Timesheet</h3>
    </div>

    <form id="Timesheet" 
     data-bind="submit: 
       function(form) { postTimesheet(form, 'timesheet-modal') }">

    <div class="modal-body">
    </div>

    <div class="modal-footer">
        <a href="#" class="btn" data-dismiss="modal">Cancel</a>
        <input type="submit" class="btn btn-primary" value="Save" />
    </div>
    </form>
</div>

Модальный div изначально скрыт из-за класса CSS hide. Он состоит из трех частей, а именно:

  • заголовок (модальный заголовок)
  • тело (модальное тело)
  • нижний колонтитул

Каждая часть украшена классом Bootstrap CSS (модальный заголовок, модальное тело и т. Д.). Заголовок содержит заголовок и кнопку (X), которая позволяет пользователю закрыть модальное окно. Атрибут кнопки data-dismiss сообщает начальной загрузке, что эта кнопка закрывает модальный режим. Тело пока пустое, в то время как нижний колонтитул содержит обычную кнопку отправки и еще одну кнопку для закрытия модального окна.

Перед запуском приложения необходимо изменить еще две вещи.

Сначала добавьте следующий CSS-код в файл site.css, который находится между bootstrap.css и bootstrap-responseive.css, чтобы удалить нижнее поле в 20px, которое начальная загрузка добавляет к формам. Обратите внимание, что тело и нижний колонтитул модала обернуты в форму.

form { margin: 0; }

Эта форма также привязана к нашей модели представления.

<form id="Timesheet" 
  data-bind="submit: function(form) { postTimesheet(form, 'timesheet-modal') }">
...
</form>

Этот атрибут указывает Knockout вызывать функцию postTimesheet модели представления при отправке формы. Добавьте эту новую функцию в модель представления.

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

postTimesheet: function (form, modalId) {

}

Хорошо, модал теперь полностью настроен. Скомпилируйте и запустите. Если вы сейчас нажмете кнопку «Добавить расписание», появится модальное окно.

модальный

Пять минут работы, и у вас есть рабочее модальное окно!

Форма

Теперь мы можем добавить форму тела тела, которую пользователь может заполнить, чтобы добавить новое расписание. Создайте частичное представление с именем _Timesheet.

Частичный вид

Визуализируйте частичное представление в теле модала.

...
<div class="modal-body">
@{ Html.RenderPartial("_Timesheet", new Timesheet()); }
</div>
...

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

@model MvcApplication.Models.Timesheet

@Html.LabelFor(m => m.FirstName)
@Html.TextBoxFor(m => m.FirstName)
@Html.LabelFor(m => m.LastName)
@Html.TextBoxFor(m => m.LastName)

@Html.LabelFor(m => m.Month)
@Html.DropDownListFor(m => m.Month, Model.Months)
@Html.LabelFor(m => m.Year)
@Html.TextBoxFor(m => m.Year, new { disabled="disabled" })

Примечание . Если вы посмотрите на код модели расписания, вы заметите, что я добавил несколько аннотаций данных (требуется, отображение … и т. Д.) И IEnumerable из SelectListItem за месяцы.

Теперь ваш модал должен выглядеть следующим образом:

Форма расписания

Давайте добавим немного CSS в файл site.css, чтобы убедиться, что обязательные поля помечены красной рамкой.

select.input-validation-error,
input.input-validation-error {
    border-color: #FF0000;
    border-radius: 7px;
}

select.input-validation-error:focus,
input.input-validation-error:focus { 
    outline: none;
    border-color: #FF0000;
    box-shadow: 0 0 10px #FF0000;
}

Если вы отправите форму, не заполнив ни одного поля, вы заметите, что поля имени и фамилии будут помечены как обязательные.

Обязательное поле

Сброс формы

Закройте модальное и снова откройте его. Что ты заметил? Да, поля по-прежнему помечены как обязательные, красная рамка и все. То же самое, если вы введете некоторые данные, они останутся там в следующий раз, когда вы снова откроете модальное окно. При открытии модальных мы должны вытереть шифер; нам нужно сбросить форму.

Свяжите событие нажатия кнопки «Добавить расписание» с функцией resetForm модели представления следующим образом:

<div class="pull-right">
    <a id="new-timesheet" class="btn btn-success" 
       data-toggle="modal" href="#timesheet-modal" 
       data-bind="click: resetForm.bind($data, 'Timesheet')">
    Add timesheet</a>
</div>

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

Что касается реализации функции resetForm, то это довольно просто. Просто добавьте следующую функцию в вашу модель представления.

resetForm: function (formId) {
    var form = $('#' + formId);
    form.validate().resetForm();
    form.get(0).reset();
}

Используя проверку jQuery, информация о проверке формы сбрасывается и сама форма. Если вы снова откроете модальное поле, поля станут пустыми и больше не будут помечены как обязательные.

POST-он

Теперь все на месте. Форма закончена, давайте разместим данные, введенные пользователем, и создадим новое расписание. Время реализовать функцию postTimesheet модели представления, которую мы добавили ранее.

Давайте пройдем это шаг за шагом. Сначала мы проверяем, проходит ли форма необходимую проверку.

form = $(form);
if (!form.valid())
    return;

Затем мы извлекаем введенную информацию из формы и сериализуем ее как JSON.

var json = JSON.stringify(this._getTimesheetFromFrom(form));

_GetTimesheetsFromForm () — это «закрытый» метод в нашей модели представления, который реализован следующим образом:

_getTimesheetFromFrom: function (form) {
    form = $(form);
    var timesheet = {};
    form.find('input[type!=submit],select').each(function () {
        timesheet[this.name] = $(this).val();
    });
    return timesheet;
}

Он берет все входные элементы INPUT и SELECT из формы и возвращает информацию в виде объекта JSON.

{"FirstName":"Dan","LastName":"Harrington","Month":"11","Year":"2012"} 

Хорошо, давайте продолжим с реализацией функции postTimesheet (). Данные формы были проверены, полезная нагрузка JSON собрана. Время отправить данные на наш контроллер API Timesheets (REST).

Легкий Peasy Lemon Squeezy. Просто выполните вызов $ .ajax и поместите данные JSON. Когда вы получаете ответ, который является недавно добавленным расписанием, сериализованным как JSON, мы помещаем его в наш наблюдаемый массив расписаний. И последнее, но не менее важное: мы используем параметр modalId, чтобы скрыть модальное окно.

var self = this;
$.ajax({
    url: '@Url.RouteUrl("DefaultApi", new { httproute = "", controller = "timesheets" })',
    type: 'POST',
    data: json,
    dataType: 'json',
    contentType: 'application/json; charset=utf-8',
    success: function (jsonObject) {
        self.timesheets.push(new timesheet(jsonObject));
        $('#' + modalId).modal('hide');
    }
});

Благодаря магии Knockout наш список расписаний будет обновляться автоматически.

Новое расписание

В предыдущем посте было показано, как реализовать READ-часть нашего приложения CRUD, в то время как эта часть демонстрировала CREATE. В третьей статье этой серии мы повторно используем многое из того, что узнали здесь, и реализуем ОБНОВЛЕНИЕ. Четвертый и последний пост обернет все с УДАЛИТЬ.

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