Estoy trabajando en un proyecto de librería donde se pueden agregar libros al carrito, un usuario puede seleccionar muchos libros para agregarlos al carrito. cuando el usuario hace clic en el botón Add to Cart , estoy agregando las ID de los libros seleccionados en una matriz JS llamada cart . Cuando todos los libros seleccionados se agregan al carrito, quiero vincular la etiqueta <a> con una llamada ajax que llegará a la URL de una función de controlador y enviará el objeto de matriz de cart JS a la función de controlador y luego en la función de controlador, Quiero devolver la vista al navegador, no quiero que la función del controlador devuelva la respuesta a la llamada ajax, sino que quiero devolver la vista al navegador.
Aquí está la función JS que agrega la ID de los libros seleccionados a la matriz JS del cart :
function addToCart(id) { if(! cart.includes(id) ) cart.push(id); cartLength.html(cart.length); $('#successCart'+id).html('Book added to cart.'); } Aquí está la etiqueta <a> que llama a la función ajax, el nombre de la función es showCart():
<a href="#" onclick="event.preventDefault(); showCart();"> <i class="fa fa-shopping-cart"></i> <span id="cartLength"></span> </a> Aquí está la función showCart() que tiene código ajax:
function showCart() { $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }); $.ajax({ url:"cart", method:'post', data:{cart:cart}, dataType: 'html' }) .done(function(msg){ }); .fail(function(msg){ alert(msg.responseJSON.errors); }); }Aquí está la función del controlador: quiero que esta función devuelva directamente la vista al navegador sin enviarla de vuelta a la llamada ajax:
public function showCart(Request $request) { return view('cart', ['cart' => $request->cart ]); // this should be returned to the browser and not to the ajax call }Aquí está la ruta para la función del controlador:
Route::post('/cart', 'HomeController@showCart')->name('home.cart');EDITAR:
He resuelto temporalmente el problema con los siguientes trucos, pero esa no es una solución permanente:
Después de llamar a la función showCart() desde ajax para enviar la variable de la matriz del cart desde js al controlador laravel , utilicé la siguiente lógica para almacenar los libros en una variable de sesión cuyas ids se almacenan en la matriz del cart :
public function showCart(Request $request) { session()->put('cart_books', Book::whereIn('id', $request->cart)->get()); session()->save(); return "success"; } Después de almacenar el resultado de la consulta en una variable de sesión, creé otra ruta GET para /cart como se muestra a continuación:
Route::get('/cart', 'HomeController@viewCart'); Luego, tras el éxito de la llamada post ajax, llamé a /cart con el método get como se muestra a continuación:
.done(function(msg){ console.log('calling cart'); location.href = "cart"; // Here I call the `/cart` with `get` method which will hit the `viewCart()` function of HomeController which will return the view back to the browser along with the results that were stored in the session variable. }) Y esta es la función del controlador viewCart() que devuelve la vista al navegador y envía los datos de la variable de sesión a la vista:
public function viewCart() { $random_books = Book::all()->random(4); $categories = Category::all(); return view('cart', ['cart_books' => session()->get('cart_books'), 'random_books' => $random_books, 'categories' => $categories]); }Quiero que la función del controlador devuelva la vista al navegador sin devolverla a la llamada ajax, cualquier ayuda se agradece de antemano.
En la función del controlador simplemente agregue el método de renderizado como la siguiente línea
public function showCart(Request $request) { return view('cart', ['cart' => $request->cart ])->render(); }Para js:
$.ajax({ method: 'POST', // Type of response and matches what we said in the route url: '{{ route('home.cart') }}', // This is the url we gave in the route data: {'cart' : cart}, // <-- this is your POST data success: function(response){ // What to do if we succeed console.log(response); }, error: function(jqXHR, textStatus, errorThrown) { // What to do if we fail console.log(JSON.stringify(jqXHR)); console.log("AJAX error: " + textStatus + ' : ' + errorThrown); } });Está haciendo un XHR, por lo que no debe devolver la vista HTML completa desde su controlador a menos que planee reemplazar su elemento existente con el HTML devuelto, como lo está haciendo con addToCart . Lo que necesita aquí es una redirección después de su POST, y su solución temporal en realidad no es una mala solución :) Aquí hay una pregunta similar a la suya con la misma respuesta. De hecho, recomiendo encarecidamente su solución temporal sobre la solución alternativa a continuación.
Dado que desea utilizar la vista devuelta por su controlador sin devolverla a su ajax, un enfoque bastante poco ortodoxo sería POST a través de un <form> . Puede crear dinámicamente un <form> , con los <input> s de sus datos y enviarlo.
function postData(actionUrl, method, data) { var mapForm = $('<form id="mapform" action="' + actionUrl + '" method="' + method.toLowerCase() + '"></form>'); for (var key in data) { if (data.hasOwnProperty(key)) { mapForm.append('<input type="hidden" name="' + key + '" id="' + key + '" value="' + data[key] + '" />'); } } $('body').append(mapForm); mapForm.submit(); } function showCart() { postData('cart', 'post', cart); }Tomé prestado el código anterior de aquí . También puedes hacer lo mismo con Vanilla JS .
Puede devolver Raw html desde una llamada ajax renderizando y devolviendo la vista dentro de su controlador como,
return view('cart', ['cart' => $request->cart])->render();Esto devolverá el HTML sin procesar y podrá usarlo más. Sin embargo, devolver HTML desde ajax no es una buena manera. Puede devolver JSON desde el controlador y representar la vista en la interfaz de acuerdo con los datos de JSON.
Como los otros dijeron que puedes usar
return view('cart', ['cart' => $request->cart])->render();y en ti jQuery hacer
.done(function(response){ document.write(response); });O puede devolver el enlace cuyo contenido debe mostrarse al usuario y redirigir al usuario en su método hecho. Así que en tu back-end tendrás
return route('cart', ['cart' => $request->cart]);y en tu front-end tendrás
.done(function(response){ location.href = response; });