Практическая лаборатория 3 из 5

Модели данных Task и TaskForm

Форма отправляет одно поле (title). Сервер отвечает полным объектом с id, createdAt и completed. Узнайте, почему граница между этими двумя моделями важна.

Что вы узнаете

Две модели: анкета и готовый билет

Прежде чем писать код, разберёмся с главной идеей. Всё строится вокруг понятия модель данных.

Модель данных — что это?

Аналогия. Модель данных — это как бланк. У бланка есть графы: «Имя», «Дата», «Номер». Когда вы его заполняете, получается упорядоченная запись, с которой удобно работать. В программе модель данных делает то же самое: задаёт, какие сведения о задаче мы храним и в каком виде.

TaskForm — черновик от пользователя

Аналогия. TaskForm — это как форму заказа: вы пишете только название задачи. Вы не придумываете номер заказа и не ставите время — об этом позаботится сервер. В нашей программе TaskForm содержит только то, что ввёл человек: title (название задачи).

Суть: TaskForm — это минимальный набор полей, который мы отправляем на сервер, чтобы создать задачу.

Task — готовый заказ от сервера

Аналогия. Task — это готовый билет с `id` и `completed`. В нём уже есть и ваше название (title), и присвоенный номер (id), и время оформления (createdAt), и статус (completed — «выполнено или нет»). Сервер сам добавляет эти поля, потому что только он знает, какой номер свободен и который час.

Суть: Task — это полная запись задачи, которую сформировал сервер и которую мы показываем пользователю и храним в списке.

Запомните разницу. Пользователь присылает форму заказа (TaskForm), а сервер возвращает готовый билет с `id` и `completed` (Task). Путать их — всё равно что подписывать незаполненный бланк.

Пошаговая инструкция

Шаг 1. Создайте файл

✍️ Действие. Создайте файл lab3.html (в любой папке, где вам удобно). Это и есть наша маленькая «лаборатория».

Шаг 2. Вставьте код

Контекст. Ниже — полный готовый файл. В нём есть форма ввода, список задач и чёрное «окошко консоли», куда выводятся два объекта: сначала TaskForm (что отправили), потом Task (что вернул сервер). Это поможет вам воочию увидеть разницу.

Аналогия. Представьте, что вы отправляете только форму заказа (TaskForm), а сервер возвращает готовый билет с `id` и `completed` (Task). Код ниже имитирует именно этот обмен.

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <title>Лаборатория 3: Task и TaskForm</title>
  <style>
    /* --- Оформление страницы (на вид не влияет, только красота) --- */
    body { font-family: Arial, sans-serif; max-width: 600px;
           margin: 40px auto; padding: 20px; }
    .form-area { display: flex; gap: 10px; margin-bottom: 20px; }
    .form-area input { flex: 1; padding: 10px; font-size: 15px;
                       border: 1px solid #d8dee8; border-radius: 6px; }
    .form-area button { padding: 10px 20px; font-size: 15px;
                        background: #159957; color: white;
                        border: none; border-radius: 6px; cursor: pointer; }
    #taskList { list-style: none; padding: 0; }
    #taskList li { background: #f8f9fa; padding: 14px; margin-bottom: 8px;
                   border-radius: 6px; border-left: 4px solid #2d5bff; }
    .meta { font-size: 13px; color: #526071; margin-top: 4px; }
    /* Чёрное окошко "консоли" — туда мы будем выводить объекты */
    #console { background: #0f172a; color: #f8fafc; padding: 16px;
               border-radius: 8px; font-family: monospace; font-size: 13px;
               margin-top: 20px; white-space: pre-wrap; max-height: 300px;
               overflow: auto; }
  </style>
</head>
<body>
  <h2>Создать задачу</h2>
  <div class="form-area">
    <!-- Поле ввода: сюда пользователь пишет название задачи -->
    <input type="text" id="taskInput" placeholder="Например: Купить молоко">
    <!-- Кнопка "Создать": по нажатию запускается весь процесс -->
    <button id="addBtn">Создать</button>
  </div>

  <h3>Список задач</h3>
  <ul id="taskList"></ul>

  <h3>Консоль (откройте F12 → Console)</h3>
  <div id="console">Здесь будут видны два разных объекта...</div>

  <script>
    // Счётчик для выдачи новых номеров задач (имитация сервера)
    let nextId = 1;
    var logBox = document.getElementById('console');

    // Вывод строки в чёрное окошко консоли
    function logToBox(text) {
      logBox.textContent += text + '\n';
      logBox.scrollTop = logBox.scrollHeight;
    }

    // Имитация сервера: принимает TaskForm, возвращает Task
     // Это как сервер: получил форму заказа, вернул готовый билет с id и completed
    function mockServerCreate(formData) {
      return new Promise(function(resolve) {
        setTimeout(function() {
          // Сервер САМ добавляет поля, которых не было в форме
          var newTask = {
            id: nextId++,                       // номер заказа (сервер)
            title: formData.title,              // название (от пользователя)
            completed: false,                   // статус: пока не выполнено
            createdAt: new Date().toISOString() // время создания (сервер)
          };
          resolve(newTask); // "возвращаем готовый билет" обратно в программу
        }, 400);
      });
    }

    // Обработчик нажатия кнопки "Создать"
    document.getElementById('addBtn').addEventListener('click', async function() {
      var input = document.getElementById('taskInput');
      var title = input.value.trim();
      if (!title) { alert('Введите название задачи!'); return; }

      // Шаг 1: создаём TaskForm (только title — то, что ввёл человек)
      var formPayload = { title: title };
      logToBox('Отправляем (TaskForm): ' + JSON.stringify(formPayload));

      // Шаг 2: отправляем "на сервер", получаем полный Task
      var createdTask = await mockServerCreate(formPayload);
      logToBox('Получили (Task): ' + JSON.stringify(createdTask));

      // Шаг 3: рисуем задачу в списке на странице
      var li = document.createElement('li');
      li.innerHTML = '<div style="font-weight:bold">' + createdTask.title + '</div>'
        + '<div class="meta">ID: ' + createdTask.id
        + ' | Создано: ' + new Date(createdTask.createdAt).toLocaleTimeString()
        + ' | Статус: ' + (createdTask.completed ? 'Выполнено' : 'В ожидании')
        + '</div>';
      document.getElementById('taskList').appendChild(li);

      input.value = ''; // очищаем поле ввода для следующей задачи
    });
  </script>
</body>
</html>

Пошаговый разбор того, что происходит при работе кода:

Что увидит пользователь. Внизу страницы в чёрном окошке появятся две строки, например:

Отправляем (TaskForm): {"title":"Купить молоко"}
Получили (Task): {"id":1,"title":"Купить молоко","completed":false,"createdAt":"2026-08-27T10:00:00.000Z"}

Обратите внимание: во второй строке появились поля, которых не было в первой. Это и есть работа «сервера».

Шаг 3. Откройте в браузере

Дважды щёлкните по файлу lab3.html — он откроется в браузере. Введите текст в поле и нажмите «Создать». Чтобы увидеть «настоящую» консоль разработчика, нажмите F12 и откройте вкладку Console.

💡 Попробуйте создать 2–3 задачи подряд и посмотрите, как растёт номер id.

Шаг 4. Сравните два объекта

В консоли (и в чёрном окошке) вы видите две строки. Вот их суть в таблице:

ОбъектПоляОткуда
TaskFormtitleВвёл пользователь
Taskid, title, completed, createdAtСгенерировал «сервер»

Аналогия. Как при оформлении заказа: в форме заказа только название, а в готовом билете с `id` и `completed` — ещё и номер, время и статус.

Зачем это нужно

Ключевая идея. Форма создания не обязана знать id и createdAt — это ответственность сервера. Разделяя модели, вы избегаете путаницы: что отправляем, а что получаем.

Аналогия. Если бы каждый пользователь сам придумывал номер задачи, два человека могли бы выбрать один и тот же — и началась бы каша. Поэтому номер всегда выдаёт сервер. Так же и в коде: пусть сервер сам назначает id и время, а форма (TaskForm) занимается только вводом названия.

💡 Позже, когда будете фильтровать задачи (показывать «только выполненные»), вы будете проверять именно поле completed. А слово done встретится вам как значение фильтра (например, фильтр 'done'), но не как имя поля задачи.

Интерактивная песочница

▶️ Посмотрите, как работает преобразование TaskForm → Task прямо здесь:

Контекст. В песочнице ниже тот же принцип, но в упрощённом виде: мы создаём form (это TaskForm) и на его основе собираем task (это Task), добавляя поля, которые «прислал бы сервер».

Аналогия. Как если бы вы взяли форму заказа, вписали туда «Изучить TypeScript», а потом сервер добавил сверху `id` (как номер билета) и дату — вот вам и готовый билет с `id` и `completed`.

Песочница: нажми «Запустить» — и увидишь рядом два объекта: короткий TaskForm (только название) и полный Taskid, временем и статусом). Меняй код и запускай снова.
Песочница: модели данных

Пошаговый разбор песочницы:

Что увидит пользователь. В правой части песочницы появятся два блока: сначала короткий TaskForm (только title), а под ним — полный Task с длинным id, временем и статусом. Нажмите «Запустить» ещё раз — id будет новым каждый раз.

Лаборатория 3 из 5. ← Лаборатория 2 | Лаборатория 4 →

Куда дальше: как модели живут в сервисах — в Уроке 6 и практике к уроку 6.

📖 Глоссарий

ТерминЖизненная аналогияКоротко
TaskFormФорма заказа / черновик анкеты без номераЧто ввёл пользователь: только title.
TaskГотовый билет с id и completedПолная запись от сервера: номер, название, статус, время.
Модель данныхБланк с графами (Имя, Дата, Номер)Задаёт, какие сведения о задаче мы храним.
СерверКассир, выдающий номер билетаСам добавляет id и createdAt.
ВалидацияПроверка, не забыли ли заполнить бланкУбеждаемся, что title не пуст.
completedГалочка «выполнено» в билетеПоле задачи: true/false.

🧠 Самопроверка

1. В объекте TaskForm уже есть поле id. Верно или неверно?

2. Поле completed показывает, выполнена задача или нет. Верно или неверно?

3. Слово done — это имя поля задачи. Верно или неверно?

Прогресс курса