Jquery Ajax загрузка в Laravel

 

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

Кейсы