Достаточно часто в 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.