Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mprythero's avatar

AJAX - Post Table Rows and Individual Inputs

I have a project in Laravel that I am working on and one portion requires me to work with submitting a form through a modal, the problem is I'm not as familiar with AJAX as I'd like to be and I've run into an issue.

Here are the modal contents:

    <table>
            <tr>
            <td>
                {{ csrf_field() }}
                <select name="payer_id" class="js-basic-single payer_id" style="width:100%;" id="payer_id">
                     <option></option>
                     @foreach($customers as $customer)
                     <option value="{{ $customer->id }}">{{ $customer->customer_name }}</option>
                     @endforeach
                </select>
                <div id="existing_biller_details" class="hidden" name="existing_biller_details" style="margin-top:10px;">
                    </div>
                <select class="form-control deposit_type" name="deposit_type" id="deposit_type">
                <option disabled selected>Please Select</option>
                <option value="Check">Check</option>
                <option value="Cash">Cash</option>
                    <option value="ECheck">ECheck</option>
                </select>
                <div name="check_number" id="check_number" class="hidden">
                      <input type="text" placeholder="Check Number" class="form-control" id="check_number" name="check_number">
                  </div>
                <input type="text" class="form-control" placeholder="Payment Amount" name="payment_amount" id="payment_amount">
                <input type="date" class="form-control" placeholder="Date of Deposit" name="date_deposit" id="date_deposit">
                <textarea placeholder="Notes" style="width:100%;" class="form-control" id="notes" name="notes"></textarea>
            </td><td style="width:50%;">
                <table style="width:100%;" id="freight_bill_items">
                    <thead>
                    
                        <td style="width:30%;font-weight:bold;text-align:center;">Bill No.</td><td style="width:30%; font-weight:bold; text-align:center;">Amount</td>
                        
                    </thead>
                    <tbody>
                        <tr style="height:40px">
                    <td style="width:30%;text-align:center;"><input type="text" name="payment_details[shipment_id][]" required class="form-control name_list" id="shipment_id" placeholder="Bill No." required></td><td style="width:30%;text-align:center;"><input type="text" name="payment_details[amount][]" required class="form-control name_list" id="amount" placeholder="Amount" required>
                            </td><td><button type="button" name="add" id="add" class="btn btn-success">Add More</button></td>
                    </tr>
                </tbody>
                </table>
                    <div id="freight_bill_items_subtotal;" style="font-weight:bold; padding-top:10px; padding-bottom:10px; text-align:left; background-color: #f0f8ff;">
                    SUBTOTAL:
                        <input type="text" readonly name="freightBillSubtotal" id="freightBillSubtotal" class="form-control total_field" style="display:inline;" value="0.00">
                    </div>
                
                
                
                
                </td>    
            </tr>
            </table>

As you can see a little bit lower, there is a div called "freight_bill_items", with a table and in the only tbody row, the two text inputs and a button to add another table row with the same exact inputs.

Now here at the moment is my ajax script:

    <script type="text/javascript">
            $(document).on('click', '.createPayment', function() {
                $('.modal-title').text('Record New Payment');
                $('#payment').modal('show');
            });
        $('.modal-footer').on('click', '.add_payment', function() {
            //ERROR COULD BE BELOW HERE//
            var payment_details = [];
            $("input[name='payment_details[shipment_id][]']").each(function(){
                    payment_details.push(this.value);
                });
            $("input[name='payment_details[amount][]']").each(function(){
                    payment_details.push(this.value);
                });
            
            //OR ERROR COULD BE UP ABOVE HERE//
            $.ajax({
                type:'POST',
                url: '/payments/createNew',
                data: {
                    payer_id: $('input[name=payer_id]').val(),
                    notes: $('input[name=notes]').val(),
                    payment_amount: $('input[name=payment_amount]').val(),
                    date_deposit: $('input[name=date_deposit]').val(),
                    check_number: $('input[name=check_number]').val(),
                    deposit_type: $('input[name=deposit_type]').val(),
                    payment_details:payment_details, //LOOKING FOR ASSISTANCE HERE//
                    _token: $('input[name=_token]').val(),
                },
                    success: function(data) {
                        $('.errorTitle').addClass('hidden');
                        $('.errorContent').addClass('hidden');
    
                        if ((data.errors)) {
                            setTimeout(function () {
                                $('#payment').modal('show');
                                toastr.error('Validation error - Check your inputs!', 'Error Alert', {timeOut: 5000});
                            }, 500);
    
                            if (data.errors.title) {
                                $('.errorTitle').removeClass('hidden');
                                $('.errorTitle').text(data.errors.title);
                            }
                            if (data.errors.content) {
                                $('.errorContent').removeClass('hidden');
                                $('.errorContent').text(data.errors.content);
                            }
                        } else {
                            toastr.success('Successfully recorded Payment!', 'Success Alert', {timeOut: 5000});
    
                        }
                    },
                });
            });
    </script>

Now what I'm stuck on is how do I pass these rows and their input contents into arrays to POST along with the other values?

At the moment, with the above code, I get the following as the parameters:

payment_amount  143.00
date_deposit    2017-12-28
check_number    41504
payment_details[]   […]
0   214267
1   214276
2   71.50
3   71.50
_token  E669......

My issue is that I need it to be like this for the payment_details[]:

0 -> shipment_id => 214267
-> amount => 71.50

1 ->shipment_id => 214276
->amount => 71.50

I'd appreciate any help anyone can provide, and much thanks in advance -

Best - Matt

0 likes
6 replies
lostdreamer_nl's avatar

The problem is exactly where you thought it was, you are getting all the shipment_ids and amounts and putting them all in 1 big array, instead of a big array of objects.

var shipments = [];
var amounts = [];
var payment_details = [];
// first get all shipment_ids in a list
$("input[name='payment_details[shipment_id][]']").each(function(){
    shipments.push(this.value);
});
// now get all of the amounts
$("input[name='payment_details[amount][]']").each(function(){
    amounts.push(this.value);
});
// now loop through the shipments and foreach shipment, add the id and the corresponding amount into a new array....

for (i = 0; i < shipments.length; i++) { 
    payment_details[] = {
        shipment_id: shipments[i],
        amount: amounts[i],
    };
}

Then send the payment_details variable with the AJAX request like you are doing now.

btw. For completeness: Check out the jQuery method for serializing forms. It will save you a lot of code:

https://api.jquery.com/serialize/

$.post( '/payments/createNew', $('#my-form').serialize(), function(response) {
   // success code in here
});
    
mprythero's avatar

@lostdreamer_nl - I'll look into the serialization. Out of curiosity, should my script now look like this?


        $(document).on('click', '.createPayment', function() {
            $('.modal-title').text('Record New Payment');
            $('#payment').modal('show');
        });
        $('.modal-footer').on('click', '.add_payment', function() {
            //ERROR COULD BE BELOW HERE//
            var shipments = [];
            var amounts = [];
            var payment_details = [];
            $("input[name='payment_details[shipment_id][]']").each(function(){
                    shipments.push(this.value);
                });
            $("input[name='payment_details[amount][]']").each(function(){
                    amounts.push(this.value);
                });
            for (i = 0; i < shipment_ids.length; i++) { 
                    payment_details[] = {
                        shipment_id: shipments[i],
                        amount: amounts[i],
                    };
                }
            //OR ERROR COULD BE UP ABOVE HERE//
            $.ajax({
            type:'POST',
            url: '/payments/createNew',
            data: {
                payer_id: $('select[name=payer_id]').val(),
                notes: $('input[name=notes]').val(),
                payment_amount: $('input[name=payment_amount]').val(),
                date_deposit: $('input[name=date_deposit]').val(),
                check_number: $('input[name=check_number]').val(),
                deposit_type: $('select[name=deposit_type]').val(),
                _token: $('input[name=_token]').val(),
            },
                success: function(data) {
                    $('.errorTitle').addClass('hidden');
                    $('.errorContent').addClass('hidden');

                    if ((data.errors)) {
                        setTimeout(function () {
                            $('#payment').modal('show');
                            toastr.error('Validation error - Check your inputs!', 'Error Alert', {timeOut: 5000});
                        }, 500);

                        if (data.errors.title) {
                            $('.errorTitle').removeClass('hidden');
                            $('.errorTitle').text(data.errors.title);
                        }
                        if (data.errors.content) {
                            $('.errorContent').removeClass('hidden');
                            $('.errorContent').text(data.errors.content);
                        }
                    } else {
                        toastr.success('Successfully recorded Payment!', 'Success Alert', {timeOut: 5000});

                    }
                },
            });
        });

It's not working but while I try and skirt through the code using JSHint and other forums, I was hoping you might see something if it's as obvious as I think it is. And thank you for all of your help!

robrogers3's avatar

This is TRIVIAL with Vue. Trivial. Watch Vuecasts. but this will get you MORE than started:

you blade file:

@extends('layouts.app')
@section('content')
<shipments template="inline">
    <div id="model">
<table>
        <tr>
        <td>
            {{ csrf_field() }}
            <select v-model="payer_id" name="payer_id" class="js-basic-single payer_id" style="width:100%;" id="payer_id">
                 <option></option>
                 @foreach($customers as $customer)
                 <option value="{{ $customer->id }}">{{ $customer->customer_name }}</option>
                 @endforeach
            </select>
            <div id="existing_biller_details" class="hidden" name="existing_biller_details" style="margin-top:10px;">
                </div>
            <select v-model="deposit_type" class="form-control deposit_type" name="deposit_type" id="deposit_type">
            <option disabled selected>Please Select</option>
            <option value="Check">Check</option>
            <option value="Cash">Cash</option>
                <option value="ECheck">ECheck</option>
            </select>
            <div name="check_number" id="check_number" class="hidden">
                  <input v-model="check_number" type="text" placeholder="Check Number" class="form-control" id="check_number" name="check_number">
              </div>
            <input v-model="payment_amount" type="text" class="form-control" placeholder="Payment Amount" name="payment_amount" id="payment_amount">
            <input v-model="date" type="date" class="form-control" placeholder="Date of Deposit" name="date_deposit" id="date_deposit">
            <textarea v-model="notes" placeholder="Notes" style="width:100%;" class="form-control" id="notes" name="notes"></textarea>
        </td>
        <td style="width:50%;">
            <table style="width:100%;" id="freight_bill_items">
                <thead>
                
                    <td style="width:30%;font-weight:bold;text-align:center;">Bill No.</td>
                    <td style="width:30%; font-weight:bold; text-align:center;">Amount</td>
                    
                </thead>
                <tbody v-for="paymentDetail in paymentDetails"><!-- as you add this grows automatically -->
                    <tr style="height:40px" class="use a component best"> <!-- use a component best, but also why inputs?? -->
                        <td>
                            <input v-model="paymentDetail.shipment_id" type="text" name="shipmentid" required class="form-control name_list" id="shipment_id" placeholder="Bill No." required>
                        </td>
                        <td style="width:30%;text-align:center;">
                            <input v-model="paymentDetail.amount" type="text" name="amount" required class="form-control name_list" id="amount" placeholder="Amount" required>
                        </td>
                        <!-- you may want a remove button here -->
                    </tr>
            </tbody>
            <tbody>
                <tr class="use a component way better">>
                        <td style="width:30%;text-align:center;">
                                <input v-model="shipment_id" type="text" name="shipmentid" required class="form-control name_list" id="shipment_id" placeholder="Bill No." required></td>
                                <td style="width:30%;text-align:center;">
                                <input type="text" name="amount" required class="form-control name_list" id="amount" placeholder="Amount" required>
                        </td>
                    <td>
                        <button @click="addPaymentDetail" type="button" name="add" id="add" class="btn btn-success clicking add should ">Add</button>
                    </td>
                </tr>
            </tbody>
            </table>
                <div id="freight_bill_items_subtotal;" style="font-weight:bold; padding-top:10px; padding-bottom:10px; text-align:left; background-color: #f0f8ff;">
                SUBTOTAL:
                    Your SubTotal is <span v-text="calculatedSubTotal"></span>
                </div>
            </td>    
        </tr>
        </table>
        <footer>
                <button @click="submitDetails">Submit Details</button>
            </footer>
       
        </div>
    </shipments>

@endsection

your Vue file: (note Vue just works out of the box with Laravel. npm run install. npm run build. DONE!!!!!)

your new vue js file: create this file called Shipments.vue in the js directory

<script>
export default {
    data() {
        return {
            payer_id: '',
            paymentDetails: [], // <-- here is the main difference it's an array of objects
            check_number: '',
            deposit_type: '',
            chock_number: '',
            paymount_amount: '',
            date: '',
            notes: '',
            shipment_id: '',
            amount: ''
        }
    },
    computed: {
        calculatedSubTotal() {
            return 'your math';
        }
    },
    methods: {
        addPamentDetails() {
            let paymentDetail = {
                shipment: this.shipment,
                amount: this.amount
            };
            
            this.paymentDetails.push(paymentDetail); //just add to the array
            this.shipment_id = '';
            this.amount = '';
        },
        submitDetails() {
            let formData = new FormData;
            formData.append('payer_id', this.payer_id);
            //Repeat for all the easy ones.
            //now for payment details:
            this.paymentDetails.each((detail) => {
                formData.append('payment_details[]["amount"]', detail.amount);
                formData.append('payment_details[]["shipment_id"]', detail.shipment_id);
            });
            //https://www.mattlunn.me.uk/blog/2012/05/sending-formdata-with-jquery-ajax/
            axios.post('/payments/createNew', formData) //jus jquery too. just pass it in as data: formData.
            .then(() => alert('success'))
            .catch(error => {
                alert('something is wrong!!')
            });
        }
    }

}

</script>

update app.js

Vue.component('shipments', require('./Shipments.vue'));
const app = new Vue({
    el: '#app'
});


make sure you include the app.js in your html.

then reload the page.

1 like
robrogers3's avatar

I may have missed a couple spots let me know if it's totally not working and I'll create a fiddle.

lostdreamer_nl's avatar

@mprythero

You removed this line :

                    payment_details:payment_details, //LOOKING FOR ASSISTANCE HERE//

It should be there otherwise you're not posting the payment_details anymore.

So either:


        $(document).on('click', '.createPayment', function() {
            $('.modal-title').text('Record New Payment');
            $('#payment').modal('show');
        });
        $('.modal-footer').on('click', '.add_payment', function() {
            var shipments = [];
            var amounts = [];
            var payment_details = [];
            $("input[name='payment_details[shipment_id][]']").each(function(){
                    shipments.push(this.value);
                });
            $("input[name='payment_details[amount][]']").each(function(){
                    amounts.push(this.value);
                });
            for (i = 0; i < shipment_ids.length; i++) { 
                    payment_details[] = {
                        shipment_id: shipments[i],
                        amount: amounts[i],
                    };
                }

            $.ajax({
            type:'POST',
            url: '/payments/createNew',
            data: {
                payer_id: $('select[name=payer_id]').val(),
                notes: $('input[name=notes]').val(),
                payment_amount: $('input[name=payment_amount]').val(),
                date_deposit: $('input[name=date_deposit]').val(),
                check_number: $('input[name=check_number]').val(),
                deposit_type: $('select[name=deposit_type]').val(),
                payment_details:payment_details, // I added this line again
                _token: $('input[name=_token]').val(),
            },
                success: function(data) {
                    $('.errorTitle').addClass('hidden');
                    $('.errorContent').addClass('hidden');

                    if ((data.errors)) {
                        setTimeout(function () {
                            $('#payment').modal('show');
                            toastr.error('Validation error - Check your inputs!', 'Error Alert', {timeOut: 5000});
                        }, 500);

                        if (data.errors.title) {
                            $('.errorTitle').removeClass('hidden');
                            $('.errorTitle').text(data.errors.title);
                        }
                        if (data.errors.content) {
                            $('.errorContent').removeClass('hidden');
                            $('.errorContent').text(data.errors.content);
                        }
                    } else {
                        toastr.success('Successfully recorded Payment!', 'Success Alert', {timeOut: 5000});

                    }
                },
            });
        });

Or


        $('.modal-footer').on('click', '.add_payment', function() {

            $.post( '/payments/createNew', $('#my-form').serialize(), function(data) {
                $('.errorTitle').addClass('hidden');
                    $('.errorContent').addClass('hidden');

                    if ((data.errors)) {
                        setTimeout(function () {
                            $('#payment').modal('show');
                            toastr.error('Validation error - Check your inputs!', 'Error Alert', {timeOut: 5000});
                        }, 500);

                        if (data.errors.title) {
                            $('.errorTitle').removeClass('hidden');
                            $('.errorTitle').text(data.errors.title);
                        }
                        if (data.errors.content) {
                            $('.errorContent').removeClass('hidden');
                            $('.errorContent').text(data.errors.content);
                        }
                    } else {
                        toastr.success('Successfully recorded Payment!', 'Success Alert', {timeOut: 5000});

                    }
            }
        });

If you go for the second version, you should give the form tag an ID of 'my-form' or change the line

$('#my-form').serialize()

To suit your needs

akaelfty38's avatar

This will wont work. for those who might use this to solve their own issues for (i = 0; i < shipment_ids.length; i++) { payment_details[] = { shipment_id: shipments[i], amount: amounts[i], }; }

use this for (i = 0; i < shipment_ids.length; i++) { payment_details.push({ shipment_id: shipments[i], amount: amounts[i], }); }

Please or to participate in this conversation.