7

I am working on a bookstore project where books can be added to cart, a user can select many books for adding them to cart. when the user clicks on the Add to Cart button, I am adding the IDs of the selected books in a JS array called cart. When all the selected books are added to the cart then I want to link <a> tag with ajax call that will hit the url of a controller function and will send the JS cart array object to the controller function and then in the controller function, I want to return view to the browser, I do not want the controller function to return the response back to the ajax call but instead I want to return the view to the browser.

Here is the JS function that adds the ID of the selected books to the cart JS array:

function addToCart(id)
{
if(! cart.includes(id) ) cart.push(id);

cartLength.html(cart.length);
$('#successCart'+id).html('Book added to cart.');

}  

Here is the <a> tag that calls the ajax function, the function name is showCart():

<a href="#" onclick="event.preventDefault(); showCart();">
  <i class="fa fa-shopping-cart"></i>
  <span id="cartLength"></span>
</a>  

Here is the showCart() function that has ajax code:

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);
 });
}  

Here is the controller function - I want this function to directly return the view to the browser without sending it back to the ajax call:

public function showCart(Request $request)
{
    return view('cart', ['cart' => $request->cart ]); // this should be returned to the browser and not to the ajax call
}  

Here is the route for the controller function:

Route::post('/cart', 'HomeController@showCart')->name('home.cart');  

EDIT:

I have temporarily solved the issue with the following tricks but that is not a permanent solution:

After calling the showCart() function from ajax for sending the cart array variable from js to laravel controller, I used the following logic to store the books in a session variable whose ids are stored in the cart array:

public function showCart(Request $request)
{

    session()->put('cart_books', Book::whereIn('id', $request->cart)->get()); 
    session()->save();
    return "success";

}  

After storing the result of the query in a session variable, I created another GET route for /cart as below:

Route::get('/cart', 'HomeController@viewCart');  

Then upon success of the post ajax call, I called /cart with get method as below:

.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.

  })  

And this is the viewCart() controller function that returns the view to the browser and sends the session variable's data to the view:

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]); 
}

I want the controller function to return the view to the browser without returning it to the ajax call, any help is appreciated in advance.

4 Answers4

2

You can return Raw html from ajax call by rendering and returning the view inside your controller as,

return view('cart', ['cart' => $request->cart])->render();

This will return the raw HTML and you can further use it. However, returning HTML from ajax is not a good way, You can return JSON from the controller and render the view in frontend according to the JSON data.

Kiran Maniya
  • 5,637
  • 4
  • 34
  • 53
0

In the controller function just add render method like the following line

public function showCart(Request $request)
{
   return view('cart', ['cart' => $request->cart ])->render();
}  

For 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);
}
});
0

You're doing a XHR, so you shouldn't return the whole HTML view from your controller unless you plan to replace your existing element with the returned HTML, like how you're doing with addToCart. What you need here is a redirection after your POST, and your temporary solution isn't actually a bad solution :) Here's a similar question as yours with the same answer. In fact, I highly recommend your temporary solution over the alternative solution below.


Since you wish to use the view returned from your controller without returning it to your ajax, a rather unorthodox approach would be to POST through a <form>. You can dynamically create a <form>, with the <input>s of your data, and submit.

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);
}

I borrowed the above code from here. You can do the same with vanilla JS too.

sykez
  • 1,606
  • 10
  • 10
0

As the others said you can use

return view('cart', ['cart' => $request->cart])->render();

and in you jQuery do

.done(function(response){
    document.write(response);
});

Or you can return the link that its content should be shown to the user and redirect the user in your done method. So in your back-end you'll have

return route('cart', ['cart' => $request->cart]);

and in your front-end you'll have

.done(function(response){
    location.href = response;
});
kodfire
  • 976
  • 1
  • 9
  • 29