如何使用 ajax 提交带有 3 个提交按钮的表单而不重定向到 Laravel 中的表单操作 url?

Posted

技术标签:

【中文标题】如何使用 ajax 提交带有 3 个提交按钮的表单而不重定向到 Laravel 中的表单操作 url?【英文标题】:How to submit a form with 3 submit buttons using ajax without redirecting to the form action url in Laravel? 【发布时间】:2021-11-18 05:19:49 【问题描述】:

我这里有一个数据表,里面有一个表单,里面有 3 个提交按钮。我做了一个 switch 语句,它检查单击了哪个提交按钮,然后在我的 store() 函数上执行该提交按钮的操作。目前,我正在尝试使用 ajax 提交表单。如果我删除 switch 语句,只返回一个操作/函数。例如saveCredit(),然后将数据保存在数据库中。但是,使用switch 语句,它不会保存任何数据。

另外,另一个例子是如果我删除e.preventDefault(),它会将数据保存在数据库中,但它会重定向到不应该的make-a-sale/save-purchase 路由。它必须重定向到同一页面。即使有switch 语句和e.preventDefault(),如何让提交按钮将数据保存在数据库中?如何让它重定向到当前页面?我在这里做错了什么?

请看我的控制器:

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\
    Customer\BillingInfo, 
    Customer, 
    Product, 
    Purchases,
    SetupBusiness
;
use App\Traits\PrintReceiptTrait;
use Carbon\Carbon;
use Picqer;
use Auth;

class PurchasesController extends Controller

    use PrintReceiptTrait;

    public function index()
    
        return view('make-a-sale.index', ['has_id' => false]);
    

    public function indexWithId($product_id)
    
        return view('make-a-sale.index', ['product_id' => $product_id, 'has_id' => true]);
    

    public function create()
    
        return view('make-a-sale.index');
    

    public function computeAndConvertData(Request $request)
    
        $qty_per_item = array_map('intval', $request->qty);
        $zero = floatval('0.00');
        $payment = floatval($request->payment);
        $total = floatval($request->total);
        $balance = $total - $payment;

        $new_data = array(
            'qty_per_item' => $qty_per_item, 
            'zero' => $zero, 
            'payment' => $payment, 
            'total' => $total, 
            'balance' => $balance
        );

        return $new_data;
    

    public function saveCredit(Request $request)
    
        $product_ids = array_map('intval', $request->product_id);
        $cod = $this->computeAndConvertData($request);
        $data = $this->createData($request, $product_ids, $cod['qty_per_item'], $cod['balance']);
        $this->createPurchaseData($data, $product_ids, $cod['qty_per_item'], $cod['zero'], $cod['total']);
        $this->updateProductQtyOnHand($product_ids, $cod['qty_per_item']);

        return redirect()->route('make-a-sale.index');
    

    public function savePurchaseAndPrint(Request $request)
    
        $product_ids = array_map('intval', $request->product_id);
        $cod = $this->computeAndConvertData($request);

        $payment = $cod['payment'] == $cod['zero'] ? $cod['zero'] : $request->payment;
        $balance = $cod['balance'] != $cod['zero'] ? $request->total : $cod['balance'];

        $data = $this->createData($request, $product_ids, $cod['qty_per_item'], $balance);
        $purchase = $this->createPurchaseData($data, $product_ids, $cod['qty_per_item'], $payment, $balance);
        $this->updateProductQtyOnHand($product_ids, $cod['qty_per_item']);

        return $this->printReceipt($purchase->code, $purchase->barcode, $purchase->product_id, $purchase->qty_per_item, $purchase->balance);
    

    public function savePurchase(Request $request)
    
        $product_ids = array_map('intval', $request->product_id);
        $cod = $this->computeAndConvertData($request);
        $data = $this->createData($request, $product_ids, $cod['qty_per_item'], $cod['balance']);
        $this->createPurchaseData($data, $product_ids, $cod['qty_per_item'], $request->payment, $cod['balance']);
        $this->updateProductQtyOnHand($product_ids, $cod['qty_per_item']);

        return redirect()->route('make-a-sale.index');
    

    public function store(Request $request)
     
        switch($request->get('action_create')) 
            case 'credit':
                $this->saveCredit($request);
                break;
            case 'save_and_print':
                $this->savePurchaseAndPrint($request); 
                break;
            case 'save':
                $this->savePurchase($request); 
                break;
            default:
                return redirect()->route('make-a-sale.index');
        
    

    private function generateRandomNumbers($length = 12) 
    
        $num = '0123456789';
        $num_length = strlen((string)$num);
        $random_number = '';
        for ($i = 0; $i < $length; $i++) 
            $random_number .= $num[rand(0, $num_length - 1)];
        
        return $random_number;
    

    private function generateBarcode($code_to_convert)
    
        $generator = new Picqer\Barcode\BarcodeGeneratorhtml();
        $barcode = $generator->getBarcode($code_to_convert, $generator::TYPE_CODE_128, 2, 35);
        return $barcode;
    

    public function createData(Request $request, $product_ids, $qty_per_item, $balance)
    
        $code = $this->generateRandomNumbers();

        $validation = $request->validate([
            'code' => 'unique:purchases',
            'product_id' => 'required', 
            'customer_id' => 'required'
        ]);

        $data = array_merge($validation, [
            'code' => $code,
            'barcode' => $this->generateBarcode($code),
            'status' => 'Regular', 
            'type' => $balance == floatval('0.00') ? 'Sale' : 'Accounts Receivables', 
            'cashier_id' => Auth::user()->id, 
            'customer_id' => $request->customer_id, 
            'product_id' => $product_ids, 
            'no_of_items' => $request->no_of_items, 
            'qty_per_item' => $qty_per_item, 
            'payment_type' => $balance <= 0 ? 'cash' : 'credit', 
            'total' => $request->total, 
            'created_at' => Carbon::now()->timestamp
        ]);

        return $data;
    

  

    public function createPurchaseData($data, $product_id, $qty_sold, $payment, $balance)
    
        $purchases = Purchases::create(array_merge($data, [
            'payment' => $payment, 
            'balance' => $balance, 
            'product_details' => $this->createProductsDetails($product_id, $qty_sold)
        ]));
        return $purchases;
    

    public function updateProductQtyOnHand($product_ids, $qty_per_item)
    
        $products = array_combine($product_ids, $qty_per_item);

        foreach ($products as $product_id => $receive_item_qty) 
            $qty_on_hand = Product::where('id', '=', $product_id)->value('qty_on_hand');
            $difference = $qty_on_hand - $receive_item_qty;

            Product::select('qty_on_hand')->where('id', '=', $product_id)->update(['qty_on_hand' => $difference]);
        
    

这是我的路线:

Route::post('make-a-sale/save-purchase', [PurchasesController::class, 'store'])->name('make-a-sale.store');

这是我的一些 Ajax:

var CSRF_TOKEN = $('meta[name="csrf-token"]').attr('content');
$(document).ready(function() 
    $.noConflict();
    
    var tableId = '#tbl-make-a-sale';

    // Footer button group actions
    saveCredit(tableId);
    savePurchase(tableId);
);
    function saveCredit(tableId) 
        $('#btn-credit').on('click', function(e)  
            e.preventDefault(); 
            if (!$("input[name='product_id[]']").val()) 
                toastr.error('The table is empty. Please add some products first.');
             else 
                let productIds = $("input[name='product_id[]']").map(function() return $(this).val(); ).get();
                let qtyPerItem = $("input[name='qty[]']").map(function() return $(this).val(); ).get();
                let params = 
                    product_id: productIds,
                    qty: qtyPerItem,
                    no_of_items: $("input[name='no_of_items']").val(),
                    customer_id: $("input[name='customer_id']").val(),
                    payment: parseFloat($('input[name="payment"]').val()), 
                    total: parseFloat($('input[name="total"]').val()),
                    _token: $('meta[name="csrf-token"]').attr('content')
                
    
                $.ajax(
                    url: 'make-a-sale/save-purchase',
                    type: 'POST',
                    data: params,
                    success: function(data) 
                        toastr.success("A new ledger has been created!");
                        $(tableId).DataTable().clear().draw(false);
                        $('#search-customers').val('0').trigger('change.select2').prop('disabled', true);
                        $('#cash-container, #txt-amount-due').hide();
                    ,
                    error: function(xhr, status, error) 
                        let errors = xhr.responseJSON.errors;
                        for (var key in errors) 
                            if (errors.hasOwnProperty(key)) 
                                toastr.error(errors[key]);
                            
                        
                    
                );
            
        );
    
    
    function savePurchase(tableId) 
        $('#btn-save').on('click', function(e) 
            e.preventDefault();
            if (!$("input[name='product_id[]']").val()) 
                toastr.error('The table is empty. Please add some products first.');
             else 
                let productIds = $("input[name='product_id[]']").map(function() return $(this).val(); ).get();
                let qtyPerItem = $("input[name='qty[]']").map(function() return $(this).val(); ).get();
                let params = 
                    product_id: productIds,
                    qty: qtyPerItem,
                    no_of_items: $("input[name='no_of_items']").val(),
                    customer_id: $("input[name='customer_id']").val(),
                    payment: parseFloat($('input[name="payment"]').val()), 
                    total: parseFloat($('input[name="total"]').val()),
                    _token: $('meta[name="csrf-token"]').attr('content')
                
    
                $.ajax(
                    url: 'make-a-sale/save-purchase',
                    type: 'POST',
                    data: params,
                    success: function(data) 
                        toastr.success("Products have been sold successfully!");
                        $(tableId).DataTable().clear().draw(false);
                        $('#search-customers').val('0').trigger('change.select2').prop('disabled', true);
                        $('#cash-container, #txt-amount-due').hide();
                    ,
                    error: function(xhr, status, error) 
                        let errors = xhr.responseJSON.errors;
                        for (var key in errors) 
                            if (errors.hasOwnProperty(key)) 
                                toastr.error(errors[key]);
                            
                        
                    
                );
            
        );
    

这是我的 HTML:

 <form id="form-make-a-sale" action=" route('make-a-sale.store') " method="post" enctype="multipart/form-data">
                        @csrf                   
                        <table id="tbl-make-a-sale" class="w-full tbl-responsive overflow-x-auto rounded-lg border-none tbl-default">
                            <thead class="w-min">
                                <tr>
                                    <th
                                        class="px-6 py-0 bg-persian-blue h-16 text-left text-xs text-white uppercase tracking-wider border-none">Actions</th>
                                    <th
                                        class="px-6 py-0 bg-persian-blue h-16 text-left text-xs text-white uppercase tracking-wider border-none">
                                        Barcode
                                    </th>
                                    <th
                                        class="px-6 py-0 bg-persian-blue h-16 text-left text-xs text-white uppercase tracking-wider border-none">
                                        Name
                                    </th>
                                    <th
                                        class="px-6 py-0 bg-persian-blue h-16 text-left text-xs text-white uppercase tracking-wider border-none">
                                        Description
                                    </th>
                                    <th
                                        class="px-6 py-0 bg-persian-blue h-16 text-left text-xs text-white uppercase tracking-wider border-none">
                                        Qty. On Hand
                                    </th>
                                    <th
                                        class="px-6 py-0 bg-persian-blue h-16 text-left text-xs text-white uppercase tracking-wider border-none">
                                        Qty. To Sell
                                    </th>
                                    <th
                                        class="px-6 py-0 bg-persian-blue h-16 text-left text-xs text-white uppercase tracking-wider border-none hidden">
                                        SRP
                                    </th>
                                    <th
                                        class="px-6 py-0 bg-persian-blue h-16 text-left text-xs text-white uppercase tracking-wider border-none">
                                        Ext. Price
                                    </th>
                                </tr>
                            </thead>
                            <tbody class="bg-white"></tbody>
                        </table>
                        <div class="w-full pb-6 md:pb-0 border-t border-gray-200 md:border-none">
                            <div class="flex bg-white justify-between items-center">
                                <div class="pt-6 pb-0 px-6 whitespace-no-wrap">
                                    <p class="text-2xl text-gray-700 font-bold">Total</p>
                                </div>
                                <div class="pt-6 pb-0 px-6 whitespace-no-wrap">
                                    <p class="text-4xl text-gray-700 font-extrabold font-mono text-right">
                                        <span id="total">₱ 0.00</span>
                                        <input type="hidden" name="total" readonly/>
                                    </p>
                                </div>
                            </div>
                            <div id="cash-container" style="display: none;">
                                <div class="flex justify-between items-center">
                                    <div class="px-6 whitespace-no-wrap">
                                        <p class="text-lg text-gray-700 font-bold">Cash</p>
                                    </div>
                                    <div class="px-6 whitespace-no-wrap">
                                        <p class="text-lg text-gray-700 font-extrabold font-mono text-right">
                                            <span id="cash">0.00</span>
                                        </p>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="mt-4 w-full md:border-t md:border-b md:border-gray-200">
                            <div id="amount-due-container" class="flex bg-persian-blue md:bg-white justify-between items-center">
                                <div class="p-6 whitespace-no-wrap">
                                    <p id="lbl-amount-due" class="text-2xl text-gray-50 md:text-gray-700 font-bold">Amount Due</p>
                                </div>
                                <div class="p-6 whitespace-no-wrap">
                                    <p id="txt-amount-due" class="text-3xl text-gray-50 md:text-gray-700 font-extrabold font-mono text-right">
                                        <span id="amount_due"></span>
                                    </p>
                                </div>
                            </div>
                        </div>
                        <div id="btn-footer-group-mas" class="m-6 justify-between">
                            <button type="button" class="px-8 py-4 text-md font-medium text-gray-50 transition-colors duration-300 transform bg-red-400 hover:bg-red-500 rounded hover:text-white focus:outline-none focus:ring cstm-size-m-mas cstm-size-w-full-mas btn-clear" name="clear" value="clear" tabindex="2">Clear
                            </button>
                            <div id="btn-footer-right-group-mas">
                                <button type="button" id="btn-cash" class="px-8 py-4 text-md font-medium text-white transition-colors duration-300 transform rounded bg-green-400 hover:bg-green-300 focus:outline-none focus:ring cstm-size-m-mas cstm-size-w-full-mas" data-hystmodal="#pay-in-cash-modal" tabindex="3">Cash
                                </button>
                                <button type="submit" id="btn-credit" class="px-8 py-4 text-md font-medium text-white transition-colors duration-300 transform rounded bg-yellow-400 hover:bg-yellow-300 focus:outline-none focus:ring cstm-size-m-mas cstm-size-w-full-mas credited" name="action_create" value="credit" tabindex="4">Credit
                                </button>
                                <button type="submit" id="btn-save-and-print" class="px-8 py-4 text-md font-medium text-indigo-400 transition-colors duration-300 transform border-2 border-indigo-400 rounded bg-indigo-100 hover:bg-indigo-200 focus:outline-none focus:ring disabled:opacity-40 cursor-not-allowed cstm-size-m-mas  cstm-size-w-full-mas" name="action_create" value="save_and_print_receipt" tabindex="5">Save and Print Receipt
                                </button>
                                <button type="submit" id="btn-save" class="px-8 py-4 text-md font-medium text-white transition-colors duration-300 transform rounded bg-indigo-600 rounded hover:bg-indigo-500 focus:outline-none focus:ring cstm-last-el-size-m-mas cstm-size-w-full-mas" name="action_create" value="save" tabindex="6">Save
                                </button>
                            </div>
                        </div>
                    </form>

非常感谢任何帮助。

【问题讨论】:

嘿,我不明白你的问题。但首先检查 ajax 发送是否调用您的控制器方法?只需从控制器返回任何字符串,然后在 ajax 成功函数部分在控制台中打印响应字符串或警告该控制器字符串 &第二件事你不需要在 ajax 请求中编写硬编码的 URL 【参考方案1】:

在控制器端,您可以将 JSON 重定向到前端的 Ajax,而不是重定向到路由。 例如: 而不是:

return redirect()->route('make-a-sale.index');

你可以:

return response()->json(["status"->true]);

【讨论】:

谢谢,知道了。但是,它仍然没有将数据保存到数据库中。 使用 trycatch(\Exception $e) 并检查代码是否抛出任何异常。 对不起,它没有返回任何错误。 我的表单操作应该是这样吗?那是对的吗? &lt;form id="form-make-a-sale" action=" route('make-a-sale.store') " method="post"&gt;&lt;/form&gt;【参考方案2】:

您的问题我不明白,但首先检查提交您的 Ajax 发送请求到您的控制器功能不是...

第二件事,你不需要在 ajax 请求中写硬编码的 url...

$.ajax(
    type: "GET",
    url: " route('home') ?page="+ page,
    headers: 
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    ,
    // data:  id: deal_id, 
).done(function( data ) 
     //on success do your operation
)
.fail(function(jqXHR, ajaxOptions, thrownError)
    alert('No response from server');
);

如果您想在 URL 中传递参数,例如 domainname.com/user/edit/id 然后您可以使用路由传递给 ajax,如上相同的 URL...

只需像下面这样操作

user_id = 3; //on click get user_id 
url = " route('admin.users.edit',':id') ";
url = url.replace(':id', user_id);

然后那个url变量传递给ajax

$.ajax(
    type: "POST",
    url: url,
    headers: 
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    ,
    // data:  id: deal_id, 
).done(function( data ) 
     //on success do your operation
)
.fail(function(jqXHR, ajaxOptions, thrownError)
    alert('No response from server');
);

【讨论】:

【参考方案3】:

抱歉@Harsh Patel,如果我不能很好地解释我的问题。

我设法通过以下方式解决了它:

return response()->json([$data]);

并在我的 switch 语句中为每个案例添加重定向:

return redirect()->route('make-a-sale.index');

切换语句:

public function store(Request $request)
 
    switch($request->get('action_create')) 
        case 'credit':
            $this->saveCredit($request);
            return redirect()->route('make-a-sale.index');
            break;
        case 'save_and_print':
            $this->savePurchaseAndPrint($request); 
            break;
        case 'save':
            $this->savePurchase($request); 
            return redirect()->route('make-a-sale.index');
            break;
        default:
            return redirect()->route('make-a-sale.index');
    

谢谢@Shree Sthapit

【讨论】:

以上是关于如何使用 ajax 提交带有 3 个提交按钮的表单而不重定向到 Laravel 中的表单操作 url?的主要内容,如果未能解决你的问题,请参考以下文章

grails远程表单,多次提交,使用javascript

使用 ajax 和 mvc 提交带有照片数据的表单

有没有办法用 1 个提交按钮 mvc 提交 3 个表单

Rails 5 ajax 表单:单击 Ajax 中的 2 个单选按钮之一提交表单

如何通过包含表单数据但不单击提交按钮的 ajax 将视图模型发送到控制器

如何使用ajax提交带有输入文件的表单