Урок 14: Работа с AJAX в Yii 2. Динамическое обновление данных

В 14-ом уроке мы изучим одну из важных тем для создания современных веб-приложений, это работу с AJAX в Yii 2. AJAX (Asynchronous JavaScript and XML) позволяет обмениваться данными с сервером без перезагрузки страницы, что делает интерфейсы быстрыми и отзывчивыми. В этом уроке я расскажу, как отправлять AJAX-запросы, обрабатывать их в контроллерах, динамически обновлять контент и реализовать подгрузку данных «на лету».

Отправка AJAX-запросов в Yii 2

Yii 2 предоставляет удобные инструменты для работы с AJAX. Основной механизм строится вокруг JavaScript-библиотеки yii.js, которая уже включена в стандартные шаблоны фреймворка. Эта библиотека добавляет обработчики событий для элементов с атрибутами data-method или data-*, связанными с AJAX.

Как это работает?

Допустим, у нас есть кнопка, при нажатии на которую нужно отправить запрос на сервер. Вместо обычной формы или ссылки мы можем использовать AJAX. Для этого добавим кнопке атрибут data-method="post" и укажем URL через data-url:

php
use yii\helpers\Url;

// В представлении:
echo Html::button('Обновить данные', [
    'class' => 'btn btn-primary',
    'data-url' => Url::to(['site/refresh']),
    'data-method' => 'POST',
    'id' => 'refreshButton'
]);

Yii автоматически «поймает» такой элемент и отправит AJAX-запрос при клике. Но если вы хотите больше контроля, можно использовать jQuery напрямую:

javascript
$('#refreshButton').on('click', function() {
    $.ajax({
        url: $(this).data('url'),
        method: 'POST',
        success: function(response) {
            console.log('Ответ сервера:', response);
        }
    });
});

Всегда проверяйте, подключен ли в вашем шаблоне yii.js (обычно он добавляется через AppAsset). Без него атрибуты data-* не сработают.

Обработка AJAX в контроллере

Теперь разберемся, как обрабатывать AJAX-запросы на стороне сервера. Yii 2 упрощает эту задачу благодаря методу Yii::$app->request->isAjax.

Пример контроллера:
Предположим, у нас есть действие refresh, которое должно вернуть JSON с данными:

php
namespace app\controllers;

use Yii;
use yii\web\Controller;

class SiteController extends Controller
{
    public function actionRefresh()
    {
        if (Yii::$app->request->isAjax) {
            $data = ['time' => date('H:i:s'), 'message' => 'Данные обновлены!'];
            return $this->asJson($data);
        }

        throw new \yii\web\ForbiddenHttpException('Доступ запрещен');
    }
}

Что здесь происходит?

  1. Проверяем, является ли запрос AJAX-ом.
  2. Если да, то подготавливаем данные и возвращаем их в формате JSON.
  3. Если нет, то выбрасываем ошибку (для безопасности).

Важно:

  • Используйте return $this->asJson(), а не echo json_encode(). Yii автоматически установит правильные заголовки.
  • Для работы с AJAX-формами используйте ActiveForm::validate() это упростит валидацию без перезагрузки страницы.

Обновление данных без перезагрузки страницы

Самый частый сценарий использования AJAX это динамическое обновление контента. Давайте создадим пример: список комментариев, который обновляется после добавления нового.

Шаг 1. Форма для комментария
Создадим форму с AJAX-валидацией:

php
use yii\widgets\ActiveForm;

$form = ActiveForm::begin([
    'id' => 'comment-form',
    'enableAjaxValidation' => true,
    'validationUrl' => Url::to(['comment/validate'])
]);

echo $form->field($model, 'text')->textarea();
echo Html::submitButton('Отправить', ['class' => 'btn btn-success']);

ActiveForm::end();

Шаг 2. Действие в контроллере
Добавим обработчик для сохранения комментария:

php
public function actionCreateComment()
{
    $model = new Comment();

    if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
        if ($model->save()) {
            return $this->asJson(['success' => true, 'html' => $this->renderPartial('_comment', ['comment' => $model])]);
        }
    }

    return $this->asJson(['success' => false]);
}

Шаг 3. Обновление списка
В JavaScript добавим обработчик успешного ответа:

javascript
$('#comment-form').on('beforeSubmit', function(e) {
    e.preventDefault();
    $.ajax({
        url: $(this).attr('action'),
        method: 'POST',
        data: $(this).serialize(),
        success: function(response) {
            if (response.success) {
                $('#comments-list').append(response.html);
                $('#comment-form')[0].reset();
            }
        }
    });
});

Результат:
Пользователь вводит комментарий, отправляет форму, комментарий мгновенно появляется в списке без перезагрузки страницы.

Пример: динамическая подгрузка контента

Реализуем бесконечную ленту, которая подгружает посты при прокрутке до конца страницы.

Шаг 1. Добавим блок для контента

php
<div id="posts-container"></div>
<div id="loading" style="display: none;">Загрузка...</div>

Шаг 2. Настроим JavaScript

javascript
let page = 1;
let isLoading = false;

$(window).on('scroll', function() {
    if ($(window).scrollTop() + $(window).height() >= $(document).height() - 100 && !isLoading) {
        isLoading = true;
        $('#loading').show();

        $.ajax({
            url: '/post/list',
            data: {page: page},
            success: function(response) {
                if (response.html) {
                    $('#posts-container').append(response.html);
                    page++;
                }
                isLoading = false;
                $('#loading').hide();
            }
        });
    }
});

Шаг 3. Действие для подгрузки

php
public function actionList($page = 1)
{
    $perPage = 10;
    $posts = Post::find()->offset(($page - 1) * $perPage)->limit($perPage)->all();

    if (empty($posts)) {
        return $this->asJson(['html' => '']);
    }

    $html = $this->renderPartial('_posts', ['posts' => $posts]);
    return $this->asJson(['html' => $html]);
}

Итог:
При прокрутке страницы каждые 10 постов подгружаются автоматически. Пользователь не видит перезагрузок, контент появляется плавно.

Практические задачи

Чтобы закрепить материал, выполните следующие задания:

  1. AJAX-валидация формы
    Создайте форму регистрации с AJAX-валидацией. Проверяйте уникальность email без перезагрузки страницы.
  2. Кнопка «Нравится»
    Реализуйте кнопку, которая увеличивает счетчик лайков у статьи. Используйте AJAX для отправки запроса.
  3. Динамический поиск
    Сделайте поле поиска, которое показывает результаты по мере ввода текста (с задержкой 300 мс).
  4. Подгрузка товаров
    На странице каталога реализуйте подгрузку товаров при прокрутке. Добавьте анимацию загрузки.

Пример кода: Кнопка «Нравится»

Представление:

php
echo Html::button('❤️ Нравится', [
    'class' => 'like-btn',
    'data-post-id' => $post->id,
    'data-url' => Url::to(['post/like']),
]);

JavaScript:

$('.like-btn').on('click', function() {
    let $button = $(this);
    $.ajax({
        url: $button.data('url'),
        method: 'POST',
        data: {postId: $button.data('post-id')},
        success: function(response) {
            if (response.success) {
                $button.text('❤️ ' + response.likes);
            }
        }
    });
});

Контроллер:

php
public function actionLike()
{
    $postId = Yii::$app->request->post('postId');
    $post = Post::findOne($postId);
    $post->updateCounters(['likes' => 1]);

    return $this->asJson([
        'success' => true,
        'likes' => $post->likes
    ]);
}

Мы разобрали основы работы с AJAX в Yii 2, от отправки запросов до динамического обновления интерфейса. Теперь вы можете создавать современные приложения с плавными переходами и интерактивными элементами. Не забывайте тестировать код и обрабатывать ошибки, это сделает ваши проекты надежными.

Если вы хотите глубже изучить Yii 2, посмотрите полный курс с уроками по Yii 2 для начинающих. Там вы найдете еще больше примеров, проектов и лайфхаков!

Поделиться статьей:
Поддержать автора блога

Поддержка автора осуществляется с помощью специальной формы ниже, предоставленной сервисом «ЮMoney». Все платёжные операции выполняются на защищённой странице сервиса, что обеспечивает их корректность и полную безопасность.

Персональные рекомендации
Оставить комментарий