Магазин на Yii2, часть 18. Корзина покупателя, часть вторая
14.07.2019
Теги: AJAX • JSON • Web-разработка • Yii2 • ИнтернетМагазин • КаталогТоваров • Корзина • Практика • Фреймворк
Теперь надо изменить форму добавления в корзину на странице товара. Но вот что плохо — после добавления товара в корзину происходит редирект на страницу корзины. Это не очень удобно, поэтому будем отправлять POST-запрос с использованием AJAX. И после добавления товара в корзину будем показывать модальное окно с содержимым корзины. Кроме того, в модальном окне будут две кнопки — «Продолжить покупки» и «Оформить заказ».
Итак, изменяем форму на странице товара:
<?php /* * Страница товара, файл views/catalog/product.php */ use app\components\TreeWidget; use app\components\BrandsWidget; use app\components\ChainWidget; use yii\helpers\Url; use yii\helpers\Html; ?> <section> <div class="container"> <div class="row"> <div class="col-sm-3"> <h2>Каталог</h2> <div class="category-products"> <?= TreeWidget::widget(); ?> </div> <h2>Бренды</h2> <div class="brand-products"> <?= BrandsWidget::widget(); ?> </div> </div> <div class="col-sm-9"> <?= ChainWidget::widget(['itemCurrent' => $product['category_id']]); ?> <h1><?= Html::encode($product['name']); ?></h1> <div class="row"> <div class="col-sm-5"> <div class="product-image"> <?= Html::img( '@web/images/products/large/'.$product['image'], ['alt' => $product['name']] ); ?> </div> </div> <div class="col-sm-7"> <div class="product-info"> <p class="product-price"> Цена: <span><?= $product['price']; ?></span> руб. </p> <form method="post" action="<?= Url::to(['basket/add']); ?>" class="add-to-basket"> <label>Количество</label> <input name="count" type="text" value="1" /> <input type="hidden" name="id" value="<?= $product['id']; ?>"> <?= Html::hiddenInput( Yii::$app->request->csrfParam, Yii::$app->request->csrfToken ); ?> <button type="submit" class="btn btn-warning"> <i class="fa fa-shopping-cart"></i> Добавить в корзину </button> </form> <p>Артикул: 1234567</p> <p>Наличие: На складе</p> <p> Бренд: <a href="<?= Url::to(['catalog/brand', 'id' => $brand['id']]); ?>"> <?= Html::encode($brand['name']); ?> </a> </p> </div> </div> </div> <div class="product-descr"> <?= $product['content']; ?> </div> <?php if (!empty($similar)): /* популярные товары */ ?> <h2>Популярные товары</h2> <div class="row"> <?php foreach ($similar as $item): ?> <div class="col-sm-4"> <div class="product-wrapper text-center"> <?= Html::img( '@web/images/products/medium/'.$item['image'], ['alt' => $item['name'], 'class' => 'img-responsive'] ); ?> <h2><?= $item['price']; ?> руб.</h2> <p> <a href="<?= Url::to(['catalog/product', 'id' => $item['id']]); ?>"> <?= Html::encode($item['name']); ?> </a> </p> <a href="#" class="btn btn-warning"> <i class="fa fa-shopping-cart"></i> Добавить в корзину </a> <?php if ($item['new']) { // новинка? echo Html::img( '@web/images/home/new.png', ['alt' => 'Новинка', 'class' => 'new'] ); } if ($item['sale']) { // распродажа? echo Html::img( '@web/images/home/sale.png', ['alt' => 'Распродажа', 'class' => 'sale'] ); } ?> </div> </div> <?php endforeach; ?> </div> <?php endif; ?> </div> </div> </div> </section>
Отправляем ajax-запрос
Теперь добавим css-класс add-to-basket
для всех форм добавления товара в корзину. Он нам потребуется, когда будем писать js-код отправки ajax-запроса. Для начала все сделаем предельно просто — при отправке запроса будем отправлять обратно массив содержимого корзины.
<?php namespace app\controllers; use app\models\Basket; use Yii; class BasketController extends AppController { public function actionIndex() { $basket = (new Basket())->getBasket(); return $this->render('index', ['basket' => $basket]); } public function actionAdd() { $basket = new Basket(); /* * Данные должны приходить методом POST; если это не * так — просто показываем корзину */ if (!Yii::$app->request->isPost) { return $this->redirect(['basket/index']); } $data = Yii::$app->request->post(); if (!isset($data['id'])) { return $this->redirect(['basket/index']); } if (!isset($data['count'])) { $data['count'] = 1; } // добавляем товар и получаем содержимое корзины $basket->addToBasket($data['id'], $data['count']); if (Yii::$app->request->isAjax) { // с использованием AJAX $content = $basket->getBasket(); return print_r($content, true); } else { // без использования AJAX return $this->redirect(['basket/index']); } } }
jQuery(document).ready(function($) { /* * Добавление товара в корзину с использованием AJAX */ $('.add-to-basket').on('submit', function (event) { var action = $(this).attr('action'); var method = $(this).attr('method'); if (method == undefined) { method = 'get'; } var data = $(this).serialize(); $.ajax({ url: action, type: method, data: data, dataType: 'text', success: function (response) { console.dir(response); }, error: function () { alert('Произошла ошибка при добавлении товара в корзину'); } }); event.preventDefault(); }); });
Добавляем модальное окно
Будем использовать компонент Bootstrap «Модальное окно», тем более, что в Yii2 есть готовый виджет. Открываем на редактирование файл views/layouts/main.php
и добавляем перед закрывающим тегом </body>
:
<footer> <div class="container"> Copyright © 2018 E-SHOPPER Inc. All rights reserved. </div> </footer> <?php $footer = <<<FOOTER <button type="button" class="btn btn-default" data-dismiss="modal"> Продолжить покупки </button> <button type="button" class="btn btn-warning"> Оформить заказ </button> FOOTER; Modal::begin([ 'header' => '<h2>Корзина</h2>', 'id' => 'basket-modal', 'size'=>'modal-lg', 'footer' => $footer ]); Modal::end(); unset($footer); ?> <?php $this->endBody() ?> </body> </html> <?php $this->endPage() ?>
Этот виджет добавит на все страницы следующий html-код:
<div id="basket-modal" class="fade modal" role="dialog" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h2>Корзина</h2> </div> <div class="modal-body"> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal"> Продолжить покупки </button> <button type="button" class="btn btn-primary"> Оформить заказ </button> </div> </div> </div> </div>
И нам теперь после получения ответа сервера надо будет вставить внутрь modal-body
html-код корзины и показать модальное окно.
Показываем модальное окно, первый вариант
Давайте изменим в js-коде тип ответа сервера на json
и на стороне сервера будем отправлять ответ в формате json
:
jQuery(document).ready(function($) { /* * Аккордеон для меню каталога в левой колонке */ $('#accordion').dcAccordion({ speed: 'fast' }); /* * Добавление товара в корзину с использованием AJAX */ $('.add-to-basket').on('submit', function (event) { var action = $(this).attr('action'); var method = $(this).attr('method'); if (method == undefined) { method = 'get'; } var data = $(this).serialize(); $.ajax({ url: action, type: method, data: data, dataType: 'json', success: function (response) { /* * Создаем таблицу товаров корзины, помещаем внутрь * модального окна, а потом показываем это окно */ // создаем таблицу корзины var table = $('<table>') .addClass('table') .addClass('table-bordered') .appendTo('#basket-modal .modal-body'); var thead = $('<thead>').appendTo(table); $('<tr>') .append($('<th>').text('Наименование')) .append($('<th>').text('Количество')) .append($('<th>').text('Цена, руб.')) .append($('<th>').text('Сумма, руб.')) .appendTo(thead); var tbody = $('<tbody>').appendTo(table); var products = response.products; for (var key in products) { var cost = Number(products[key].count) * Number(products[key].price); $('<tr>') .append($('<td>').text(products[key].name)) .append($('<td>').text(products[key].count)) .append($('<td>').text(products[key].price)) .append($('<td>').text(cost)) .appendTo(tbody); } $('<tr>') .append($('<td>').attr('colspan', 3).text('Итого')) .append($('<td>').text(response.amount)) .appendTo(tbody); // показываем модальное окно $('#basket-modal').modal(); }, error: function () { alert('Произошла ошибка при добавлении товара в корзину'); } }); event.preventDefault(); }); });
<?php namespace app\controllers; use app\models\Basket; use Yii; class BasketController extends AppController { /* ... */ public function actionAdd() { /* ... */ if (Yii::$app->request->isAjax) { // с использованием AJAX $content = $basket->getBasket(); return $this->asJson($content); } else { // без использования AJAX return $this->redirect(['basket/index']); } } }
{ "products": { "123": { "name": "Мужская рубашка", "price": 1000, "count": 2 }, "456": { "name": "Мужская футблока", "price": 1200, "count": 1 } }, "amount": 3200 }
Показываем модальное окно, второй вариант
Мне не нравится формирование таблицы корзины с помощью JavaScript, поэтому давайте перенесем формирование html-кода на сервер. Для этого изменим в js-коде тип ответа сервера на html
и создадим view-шаблон view/basket/modal.php
:
jQuery(document).ready(function($) { /* * Аккордеон для меню каталога в левой колонке */ $('#accordion').dcAccordion({ speed: 'fast' }); /* * Добавление товара в корзину с использованием AJAX */ $('.add-to-basket').on('submit', function (event) { var action = $(this).attr('action'); var method = $(this).attr('method'); if (method == undefined) { method = 'get'; } var data = $(this).serialize(); $.ajax({ url: action, type: method, data: data, dataType: 'html', success: function (response) { $('#basket-modal .modal-body').html(response); $('#basket-modal').modal(); }, error: function () { alert('Произошла ошибка при добавлении товара в корзину'); } }); event.preventDefault(); }); });
<?php /* * Корзина покупателя в модальном окне, файл views/basket/modal.php */ use yii\helpers\Html; use yii\helpers\Url; ?> <?php if (!empty($basket)): ?> <div class="table-responsive"> <table class="table table-bordered"> <tr> <th>Наименование</th> <th>Количество</th> <th>Цена, руб.</th> <th>Сумма, руб.</th> </tr> <?php foreach ($basket['products'] as $item): ?> <tr> <td><?= $item['name']; ?></td> <td class="text-right"><?= $item['count']; ?></td> <td class="text-right"><?= $item['price']; ?></td> <td class="text-right"><?= $item['price'] * $item['count']; ?></td> </tr> <?php endforeach; ?> <tr> <td colspan="3" class="text-right">Итого</td> <td class="text-right"><?= $basket['amount']; ?></td> </tr> </table> </div> <?php else: ?> <p>Ваша корзина пуста</p> <?php endif; ?>
<?php namespace app\controllers; use app\models\Basket; use Yii; class BasketController extends AppController { /* ... */ public function actionAdd() { /* ... */ if (Yii::$app->request->isAjax) { // с использованием AJAX // layout-шаблон нам не нужен, только view-шаблон $this->layout = false; $content = $basket->getBasket(); return $this->render('modal', ['basket' => $content]); } else { // без использования AJAX return $this->redirect(['basket/index']); } } }
- Магазин на Yii2, часть 19. Корзина покупателя, часть третья
- Магазин на Laravel 7, часть 19. Панель управления, добавляем редактор для страниц сайта
- Магазин на Yii2, часть 22. Оформление заказа, часть третья
- Магазин на Yii2, часть 21. Оформление заказа, часть вторая
- Магазин на Yii2, часть 20. Оформление заказа, часть первая
- Магазин на Yii2, часть 17. Корзина покупателя, часть первая
- Магазин на Laravel 7, часть 10. Форма оформления, сохранение заказа в базу данных
Поиск: Web-разработка • Yii2 • Интернет магазин • Каталог товаров • Корзина • Фреймворк • AJAX • Modal • Модальное окно • JSON