如何在 ajax 调用时从 laravel 控制器函数返回视图?

Posted

技术标签:

【中文标题】如何在 ajax 调用时从 laravel 控制器函数返回视图?【英文标题】:How to return a view from laravel controller function upon ajax call? 【发布时间】:2020-11-24 19:53:08 【问题描述】:

我正在做一个书店项目,可以将书籍添加到购物车,用户可以选择许多书籍将它们添加到购物车。当用户点击Add to Cart 按钮时,我将所选书籍的ID 添加到一个名为cart 的JS 数组中。当所有选定的书籍都添加到购物车时,我想将 <a> 标记与 ajax 调用链接,该调用将访问控制器函数的 url,并将 JS cart 数组对象发送到控制器函数,然后在控制器中函数,我想将视图返回给浏览器,我不希望控制器函数将响应返回给 ajax 调用,而是我想将视图返回给浏览器。

这里是把选中书籍的ID添加到cartJS数组中的JS函数:

function addToCart(id)

if(! cart.includes(id) ) cart.push(id);

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

  

这里是调用ajax函数的<a>标签,函数名是showCart():

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

这里是具有 ajax 代码的 showCart() 函数:

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

这是控制器函数 - 我希望这个函数直接将视图返回给浏览器,而不将其发送回 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
  

这是控制器功能的路由:

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

编辑:

我已经通过以下技巧暂时解决了这个问题,但这不是永久解决方案:

在从ajax 调用showCart() 函数将cart 数组变量从js 发送到laravel 控制器后,我使用以下逻辑将书籍存储在会话变量中,其ids 是存储在cart 数组中:

public function showCart(Request $request)


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

  

将查询结果存储在会话变量中后,我为/cart 创建了另一个GET 路由,如下所示:

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

然后在post ajax 调用成功后,我使用get 方法调用/cart,如下所示:

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

  )  

这是viewCart()控制器函数,它将视图返回给浏览器并将会话变量的数据发送给视图:

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

我希望控制器函数将视图返回给浏览器而不将其返回给 ajax 调用,提前感谢任何帮助。

【问题讨论】:

【参考方案1】:

您可以通过在控制器中渲染和返回视图来从 ajax 调用返回 Raw html,

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

这将返回原始 HTML,您可以进一步使用它。但是从ajax返回HTML并不是一个好办法,你可以从控制器返回JSON,并根据JSON数据在前端渲染视图。

【讨论】:

【参考方案2】:

在控制器函数中只需添加如下行的渲染方法

public function showCart(Request $request)

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

对于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);

);

【讨论】:

上面写着Internal Server Error jquery.min.js:5 POST localhost:8080/wisdom2/public/cart500(内部服务器错误)发送@jquery.min.js:5 ajax @jquery.min.js:5 showCart @main.js:84 onclick @(索引):64 The GET method is not supported for this route. 这意味着您将其称为 get 而不是 GET 路由,请从此处的路由文件中复制路由 当异常发生时你能显示来自 laravel 日志文件的日志吗?也许我们错过了什么【参考方案3】:

你正在做一个 XHR,所以你不应该从你的控制器返回整个 HTML view 除非你打算用返回的 HTML 替换你现有的元素,就像你正在做的那样addToCart。您在这里需要的是 POST 之后的重定向,而您的临时解决方案实际上并不是一个糟糕的解决方案 :) 这是一个 similar question 与您的答案相同。事实上,我强烈推荐您的临时解决方案,而不是下面的替代解决方案。


由于您希望使用从控制器返回的视图而不将其返回到您的 ajax,一个相当非正统的方法是通过 &lt;form&gt; 进行 POST。您可以使用您的数据的&lt;input&gt;s 动态创建&lt;form&gt;,然后提交。

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

我从here借用了上面的代码。你也可以使用same with vanilla JS。

【讨论】:

【参考方案4】:

正如其他人所说,您可以使用

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

在你的 jQuery 中做

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

或者您可以返回其内容应显示给用户的链接,并在您的 done 方法中重定向用户。所以在你的后端你会有

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

在您的前端,您将拥有

.done(function(response)
    location.href = response;
);

【讨论】:

以上是关于如何在 ajax 调用时从 laravel 控制器函数返回视图?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 laravel 中的 ajax 调用中获取值

Ajax 调用 Laravel 路由

从一个控制器 LARAVEL 使用 AJAX 调用不同的函数

Laravel Ajax 调用 url 到控制器

如何将数据从ajax get方法发送到laravel中的控制器?

ajax成功后用数据调用另一个控制器后的Laravel