1

Recently I found myself having to create a page that users can freely fill out, but I am struggling to understand how to make the page capable of saving changes in real-time.

The idea is that every time the user selects an option from a dropdown or types characters in a textarea, the state (the change) should be saved without the need to click a button or anything else.

I have already tried the following code, but I get a 419 error from the console, and the data is not being saved to the database.

HTML:

<table class="table-bordered table-striped table">
    <tr>
        <th>@lang('quickadmin.inspections.fields.inspection-date')</th>
        <td field-key='inspection_date'>
            {!! Form::text('inspection_date', old('inspection_date'), [
                'class' => 'form-control date',
                'placeholder' => '',
                'id' => 'inspection_date',
            ]) !!}
        </td>

    <tr>
        <th>@lang('quickadmin.inspections.fields.execution-date')</th>
        <td field-key='execution_date'>
            {!! Form::text('execution_date', old('execution_date'), [
                'class' => 'form-control date',
                'id' => 'execution_date',
                'placeholder' => '',
            ]) !!}
        </td>

        <th>@lang('quickadmin.inspections.fields.execution-hour')</th>
        <td field-key='execution_time'>
            {!! Form::text('execution_time', old('execution_time'), [
                'class' => 'form-control timepicker',
                'id' => 'execution_time',
                'placeholder' => '',
            ]) !!}
        </td>
    </tr>

    <tr>
        <th>Veicolo</th>
        <td field-key='vehicles' colspan="3">
            {!! Form::select('vehicles[]', $vehicles, old('vehicles'), ['class' => 'form-control select2', 'multiple' => 'multiple', 'id' => 'selectall-methods' ]) !!}
            <p class="help-block"></p>
            @if($errors->has('vehicles'))
                <p class="help-block">
                    {{ $errors->first('vehicles') }}
                </p>
            @endif
        </td>
    </tr>
    
    <tr>
        <th>Trasferta [minuti]</th>
        <td field-key='trip_time' colspan="3">
            {!! Form::text('trip_time', old('trip_time'), [
                'class' => 'form-control',
                'id' => 'trip_time',
                'placeholder' => 'Esempio: 28 [min]',
            ]) !!}
        </td>
    </tr>

    <tr>
        <th>Descrizione dell'intervento</th>
        <td field-key='inspection_note' colspan="3">
            @if ($inspection->inspection_note != null)
                <textarea id="desc" class="form-control" style="width: 100%;resize: none;" rows="5" maxlength="80">{{ $inspection->inspection_note }}</textarea>
            @else
                <textarea id="desc" class="form-control" style="width: 100%;resize: none;" rows="5" placeholder="Descrizione intervento"
                 maxlength="80"></textarea>
            @endif
        </td>
    </tr>
</table>

Javascript:

<script>
    // This code will update the database when the user changes the value of a field
    $(function() {
        $('.form-control').on('change', function() {
            $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': "{{ \Illuminate\Support\Facades\Session::token() }}"
            }
        });

            $.ajax({
                url: '/admin/new_inspections/update/' + {{ $inspection->id }},
                type: 'post',
                data: {
                    inspection_date: $('#inspection_date').val(),
                    inspection_time: $('#inspection_time').val(),
                    inspection_state: $('#inspection_state').find("option:selected").attr('value'),
                    user_code: $('#user_code').find("option:selected").attr('value'),
                    inspection_note: $('textarea#desc').val(),
                    trip_time: $('#trip_time').val(),
                    execution_date: $('#execution_date').val(),
                    execution_hour: $('#execution_time').val(),
                },
                success: function(response) {
                    if (response.success) {
                        console.log('Product updated successfully!');
                    } else {
                        console.log('Error updating product!');
                    }
                }
            });
        });
    });
</script>

Controller update (The code can't even enter it):

public function update(UpdateNewInspectionRequest $request, $id)
{
    $inspection = NewInspection::findOrFail($id);
    $inspection->extra_vehicles()->sync(array_filter((array)$request->input('extra_vehicles')));
    $inspection->update($request->all());
    $inspection->save();

    return back();
}

I don't know if it could be important, but the feature I'm trying to implement was present in an old version of the website on a different host. About 6 months ago, we changed hosts and migrated the site. It's possible that the issue lies in the change of a reference?

Drakdy
  • 11
  • 3
  • 2
    HTTP status code 419 is what laravel uses when the CSRF token is not valid. – CBroe Jul 25 '23 at 09:07
  • 419 indicate that your X-CSRF-TOKEN isn't valid, try it with 'X-CSRF-TOKEN': "{{ csrf_token() }}" if you don't use csrf token in your form – Gireada Jul 25 '23 at 09:08
  • Under "saving changes in real-time", do you mean AJAX save without clicking the 'Save' button? – Tpojka Jul 25 '23 at 10:19
  • @Gireada: Thank you for the suggestion, but I have already tried it and the result is always the same (419). – Drakdy Jul 25 '23 at 12:42
  • @Tpojka: Yes, that's exactly what I meant. – Drakdy Jul 25 '23 at 12:42
  • Then you should implement it in JS code. Check how to invoke events. Do you use some JS framework or library like Vue, React, jQuery? – Tpojka Jul 25 '23 at 13:14
  • @Tpojka: I'm using jQuery – Drakdy Jul 26 '23 at 10:09
  • @Drakdy change the authorization value in UpdateNewInspectionRequest – Gireada Jul 26 '23 at 16:42
  • @Gireada: More open than this is impossible: public function authorize() { return true; } – Drakdy Jul 27 '23 at 06:52
  • You should set event listener on exact elements, not on wrapping div. Find [here](https://stackoverflow.com/questions/6153047/detect-changed-input-text-box) some ideas. – Tpojka Jul 27 '23 at 11:50
  • @Tpojka: Actually, that's the only part of the code that works without issues, as I can retrieve the form's value and display it in the console. The real problem is that I'm unable to send the data to the controller (NewInspectionController). With the PUT and PATCH methods, I get error 405, while with the POST method, I get error 419. – Drakdy Jul 27 '23 at 12:18
  • Have you tried to use CSRF token like [this](https://laravel.com/docs/10.x/csrf#csrf-x-csrf-token)? Also, can you show how is defined that route in route file (edit question with it)? [PUT within AJAX](https://stackoverflow.com/questions/8032938/jquery-ajax-put-with-parameters) tested? – Tpojka Jul 27 '23 at 13:22
  • @Tpojka: Yes I tried that code as well with no result. web.php: Route::PUT('new_inspections/update/{id}', ['uses' => 'Admin\NewInspectionsController@update', 'as' => 'new_inspections.update']); – Drakdy Jul 27 '23 at 14:17

1 Answers1

0

If you would like to do real-time updates, then this surely sounds like you need an asynchronous JavaScript solution. Specifically for that, there is the Laravel Package Inertia which allows to build asynchronous JavaScript forms. Specifically see this page of the documentation.

Alternatively, there is also Livewire which allows you do to the same thing using PHP.

Bob Aiden Scott
  • 175
  • 1
  • 9
  • I have tested both options (that's why it took me so long to reply, sorry), but I am unable to download Inertia due to an error, while Livewire would require a code rewrite that could potentially cause more issues than before, and I haven't been able to test the feature yet, but I'm still experimenting. – Drakdy Jul 27 '23 at 12:24