Достаточно часто в Laravel возникает необходимость выполнять какие-то действия без перезагрузки всей страницы по осуществлению пользователем какого-то действия в браузере. Самый простой пример: нужно добавить товар в корзину при нажатии на кнопку без перезагрузки страницы. При этом кнопка должна отправить url-обработчику (методу контроллера) добавления в корзину данные формы, в которой указывается id товара и количество добавляемого товара. А url-обработчик должен добавить наш товар в корзину, после чего на странице должно появится соответствующее информационное уведомление.
Для начала нам нужно создать контроллер baskets, в котором есть метод ajax_add(). При отправке данных (product_id и quantity) этому методу, он проверяет данные, ищет товар по product_id и добавляет его в корзину в указанном количестве. Это и будет наш url-обработчик. Все это выглядит примерно так:
//файл /app/Http/Controllers/BasketsController.php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Models\Basket; use Illuminate\Http\Request; // метод ajax_add, который получает данные $request public function ajax_add(Request $request) { // здесь можно накрутить какую-нибудь валидацию данных /**/ // ищет товар по id товара $product = Product::select('id','quantity','price') ->where([ ['id','=',$request->product_id], ]) ->first(); //возвращаем ошибку если не находим товар if (!$product) { return false; } //задаем данные для записи в корзину $input = $request->all(); $input['price'] = $product->price; try { // создаем запись в корзине и если все получается то возвращаем успешное действие $basket = Basket::create($input); return true; } catch(\Illuminate\Database\QueryException $ex) { // если что-то пошло не так и запись не добавилась в корзину, то возвращаем ошибку return false; } }
Теперь, чтобы все работало, нужно не забыть добавить маршрут для этого метода контроллер. Сделаем это самым простым способом:
//файл /routes/web.php Route::post('baskets/ajax_add', 'App\Http\Controllers\BasketsController@ajax_add')->name('baskets.ajax_add');
Теперь, если мы отправим данные в правильном формате (product_id и quantity) по ссылке /baskets/ajax_add нашего сайта, то получим добавление в корзину, а в ответ получим "true". А если данные будут не правильные, то добавления в корзину не произойдет - получим в ответ "false".
Теперь нам понадобится сгенерировать в каком-нибудь шаблоне простую форму добавления товара в корзину, которая будет вызывать метод контроллера (ajax_add) и передавать ему данные. Что-то типа этого:
//HTML-пример формы, которая должна генерироваться <form method="post" class="ajaxBasket_add_48751" action="/baskets/add"> <input type="hidden" name="_token" value="jeXJknJv2elYy9QGOkhAqpRc15SWWoPcPU4XpnDF" /> <input class="ajaxBasket_productID" type="hidden" name="product_id" value="48751" /> <input type="text" class="ajaxBasket_quantity" name="quantity" value="1" /> <button type="submit">в корзину</button> </form>
В этой форме цифра 48751 (которая встречается целых два раза) - это будет id нашего товара, который мы будем добавлять в корзину. Здесь input с name=quantity это поле для ввода количества добавляемого товара. Поле input с name=_token это поле, которое автоматически генерируется при добавлении тега @csrf для формы в blade-шаблоне.
Чтобы совсем упростить задачу, приведем пример куска blade-шаблона такой формы
// файл blade шаблона, где используется добавление товара в корзину @foreach($products as $product) <form method="post" class="ajaxBasket_add_{{ $product_id }}" action="{{ route('baskets.add') }}"> @csrf <input class="ajaxBasket_productID" type="hidden" name="product_id" value="{{ $product_id }}" /> <input type="text" class="ajaxBasket_quantity" name="quantity" value="1" /> <button ype="submit">в корзину</button> </form> @endforeach
Стоит заметить, что здесь в action мы указываем не наш url-обработчик ajax-запросов /baskets/ajax_add, а ссылку /baskets/add - это аналогичный обработчик, только не ajax а стандартный, который добавляет товар в корзину но с перезагрузкой страницы. Сделано это на случай, если у посетителя сайта вдруг не работает JavaScript в браузере (такое очень редко но может случится), чтобы он все равно смог добавить товар в корзину.
Теперь нужно добавить jquery скрипт, который при отправке данных формы (нажатии на кнопку "в корзину") отменять стандартное дефолтное действие, получать информацию о id товара (product_id) и количестве добавляемого товара в корзину (quantity) и с помощью Ajax отправлять запрос данных на нужный нам url (метод контроллера), и получать ответ, после чего выполнять какое-то действие.
Выглядеть это будет так
// можно добавить в файл, где генерируется форма добавления в корзину <script type="text/javascript"> $(document).ready(function() { // при отправке формы с классом ajaxBasket_add $('.ajaxBasket_add').submit(function(event) { //получаем значение product_id из соотв. поля формы (вложенного в form) var product_id = $(this).children('.ajaxBasket_productID').attr('value'); //получаем значение quantity из соотв. поля формы (вложенного в form) var quantity = $(this).children('.ajaxBasket_quantity').attr('value'); //задаем функцию Ajax для нашего url $.ajax('/baskets/ajax_add', { //тип POST type: 'POST', //формат json dataType: 'json', //задаем передаваемые нашему url значения переменных data: { product_id: product_id, quantity: quantity }, //Laravel по умолчанию всегда генерит csrf-token //чтобы ajax запросы корректно работали нужно добавлять такую настройку headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') }, //если все сработало и ошибок нет // т.е. url /baskets/ajax_add вернул значение true success: function() { // - то пишем что добавлено alert('Добавлено в корзину'); }, //если что-то пошло не так // т.е. url /baskets/ajax_add вернул значение false error: function() { // - то выдаем ошибку alert('Ошибка добавления в корзину'); } }); //предотвращаем дефолтное событие нажатия на кнопку (отправки формы) //чтобы при нажатии на кнопку "добавить" форма не отправлялась а выполнялся скрипт event.preventDefault(); }); }); </script>
Теперь все готово, осталось только проверить, что все работает.
Стоит еще упомянуть о том, что при работе с Ajax в ходе разработке бывает сложно проверять передаваемые скрипту данные, поскольку сложно их вывести на экран стандартными привычными способами. Чтобы упростить процесс дебагинга можно, как вариант, использовать логирование переменных.
//файл /app/Http/Controllers/BasketsController.php use Illuminate\Support\Facades\Log; // метод ajax_add, который получает данные $request public function ajax_add(Request $request) { //чтобы посмотреть переданные данные //используем логирование переданных данных $request Log::debug($request->all()); }
Дальше все зависит от настроек логирования, которые указываются в файле /config/logging.php. Но если там ничего не менялось, то указанным выше способом логирования в файле /storage/logs/laravel.log будет записан массив данных из переменной $request.