skip to Main Content

I’m working on the project which I have to make my users to be able to add and remove items; in this case is the reward information. I’m developing this on Laravel 10 and I’ve tried so many attempts to get the old values from the controller when the validation is failed by the rules I declared.

In my JavaScript, I have addMoreItem() function and removeItem() function. In addMoreItem() function, I can used value="{{ old(‘reward_name’) }}". After the failure, I have to check for the old value(s) by using @json(‘reward’) which contains the array of reward data like this :

{"1":
    {
        "reward_award_status":"1",
        "reward_type_id":"1",
        "reward_owner_name":"International Kid Scientist Programme",
        "reward_owner_description":"Example of Description",
        "reward_date":"2024-10-04",
        "reward_name":"International Kid Scientist",
        "reward_education_level_id":"1",
        "reward_academic_year":"2024",
        "reward_academic_semester":"1",
        "reward_prize_amount":null
    },
"2":
    {
        "reward_award_status":"1",
        "reward_type_id":"3",
        "reward_owner_name":"National Kid Scientist Programme",
        "reward_owner_description":"Example of Description",
        "reward_date":"2024-10-04",
        "reward_name":"National Kid Scientist",
        "reward_education_level_id":"1",
        "reward_academic_year":"2024",
        "reward_academic_semester":"1",
        "reward_prize_amount":null
    },
}

After I got the old values as above, I will work in JavaScript like this :

var reward_items = @json(old('reward_total_items', 0));
if(reward_items > 0){
    const reward_details = @json(old('reward'));
    Object.entries(reward_details).forEach(([key, value]) => {
        $('#reward_details').append(
            '<div id="reward-' + key + '" class="card border-dark mt-3 mb-3' + '">' +
                        '<div class="card-header bg-warning">' +
                            '<div class="row align-items-center">' +
                                '<div class="col d-flex justify-content-start">' +
                                    '<strong>Reward Information</strong>' +
                                '</div>' +
                                '<div class="col d-flex justify-content-end">' +
                                    '<a class="btn btn-clear text-center" onclick="removeReward('reward-' + key + '');">' +
                                        '<i class="fa-solid fa-trash"></i>' +
                                        '<strong>Remove This Item</strong>' +
                                    '</a>' +
                                '</div>' +
                            '</div>' +
                        '</div>' +

                        '<input type="text" id="reward_' + key + '_reward_award_status" name="reward[' + key + '][reward_award_status]" class="form-control" value="{{ old("reward.' + key + '.reward_award_status", ' + value.reward_award_status + ') }}" style="display: none;"/>' + 

                        '<div class="card-body">' +
                            '<div class="row row-cols-1">' +
                                '<div class="col mt-1 mb-1">' +
                                    '<label for="reward_' + key + '_reward_type_id" class="form-label">' +
                                        '<strong>Reward Type <span style="color: red;">*</span> : </strong>' +
                                    '</label>' +
                                    '<select id="reward_' + key + '_reward_type_id" name="reward[' + key + '][reward_type_id]" class="form-select form-control search-on-selection ' +
                                        '@error("reward.' + key + '.reward_type_id") is-invalid @enderror" style="width: 100%;">' +
                                        '<option value="" selected disabled>Please Type</option>' +
                                        reward_type_list.map(reward_type => {
                                            return '<option value="' + reward_type.id + '" ' +
                                                (value.reward_type_id == reward_type.id ? 'selected' : '') + 
                                                ' data-is-get-reward="' + reward_type.is_get_reward + '">' +
                                                reward_type.name + '</option>';
                                        }).join('') + 
                                    '</select>' +
                                    '@error("reward.' + key + '.reward_type_id")' +
                                        '<span class="invalid-feedback" role="alert">' +
                                            '<strong>{{ $message }}</strong>' +
                                        '</span>' +
                                    '@enderror' +
                                '</div>' +
                            '</div>' +

                            '<div id="reward_' + key + '_reward_details" name="reward_' + key + '_reward_details" class="@if(' + value.reward_award_status + ' == "1")' + ' d-block @endif">' +
                                '<div class="row row-cols-1 row-cols-sm-1 row-cols-md-2 row-cols-lg-2">' +
                                    '<div class="col mt-1 mb-1">' +
                                        '<label for="reward_' + key + '_reward_owner_name" class="form-label">' +
                                            '<strong>Reward Owner Name <span style="color: red;">*</span> : </strong>' +
                                        '</label>' +
                                        '<input type="text" id="reward_' + key + '_reward_owner_name" name="reward[' + key + '][reward_owner_name]" class="form-control ' +
                                            '@error("reward.' + key + '.reward_owner_name") is-invalid @enderror" ' +
                                            'placeholder="Please Type Reward Owner Name" ' +
                                            'value="{{ old('reward.' + key + '.reward_owner_name', ) }}"' +
                                            'onkeyup="typeOnlyEN('reward_' + key + '_reward_owner_name');" ' +
                                            'onkeydown="typeOnlyEN('reward_' + key + '_reward_owner_name');"/>' +
                                        '<span class="invalid-feedback type_alert_reward_reward_owner_name" role="alert" style="display: none;">' +
                                            '<strong>Please specify in English</strong>' +
                                        '</span>' +
                                        '@error("reward.' + key + 'reward.reward_owner_name")' +
                                            '<span class="invalid-feedback" role="alert">' +
                                                '<strong>{{ $message }}</strong>' +
                                            '</span>' +
                                        '@enderror' +
                                    '</div>' + ...

I want to use old function like the code above but I can’t use it. I don’t know why it is not working but I assume that it is because of the different of how Blade and JavaScript read the code in different side. However, I need to use the old function.

The key is that I know I need to change this line of code : ‘value="{{ old(‘reward.’ + key + ‘reward.owner_name’, ) }}"’ to add the default value to it using value.reward_owner_name but I don’t really know the syntax to do it properly.

2

Answers


  1. Chosen as BEST ANSWER

    I'm not the expert on using AJAX but I have tried AJAX to send the data from the form in Blade file with this code :

            let form = $('#form');
            
            form.submit(function (e){
                e.preventDefault();
    
                // Send Data using AJAX
                $.ajax({
                    url: form.attr('action'),
                    type: form.attr('method'),
                    data: form.serialize(),
                    error: function(data){
    
                        let status = data.status;
                        console.log("Status : " + status);
    
                        // Get Message
                        let message = data.message;
    
                        // alert("Message : " + message);
    
                        // Show Alert Message
                        Swal.fire({
                            position: 'center',
                            icon: 'error',
                            title: message,
                            showCloseButton: false,
                            showConfirmButton: false,
                            timer: 2000
                        })
    
                        // Get All Error(s)
                        let errors = data.all_errors;
    
                        // Show Each Error
                        // For Achievement + Reward Information
                        $.each(errors, function(key, message){
    
                            // Replace '.' from Reward Information Field(s)
                            let elementID = key.replace(/./g, '_');
                            let element = $('#' + elementID);
    
                            // Add 'is-invalid' Class
                            element.addClass('is-invalid');
    
                            // Append Error Message After Element
                            element.after('<span class="invalid-feedback" role="alert"><strong>' + message[0] + '</strong></span>');
                        });
    
                        // Get All Old Value(s)
                        let old_values = data.old_values;
                        
                        // Re-populate Form Fields with Old Value(s)
                        // For Achievement
                        $('#achievement_name_th').val(old_values.achievement_name_th);
                        $('#achievement_name_en').val(old_values.achievement_name_en);
                        $('#start_achievement_date').val(old_values.start_achievement_date);
                        $('#finish_achievement_date').val(old_values.finish_achievement_date);
                        $('#start_achievement_education_level_id').val(old_values.start_achievement_education_level_id).change();
                        $('#start_achievement_academic_year').val(old_values.start_achievement_academic_year);
                        $('#start_achievement_academic_semester').val(old_values.start_achievement_academic_semester);
                        $('#finish_achievement_education_level_id').val(old_values.finish_achievement_education_level_id).change();
                        $('#finish_achievement_academic_year').val(old_values.finish_achievement_academic_year);
                        $('#finish_achievement_academic_semester').val(old_values.finish_achievement_academic_semester);
                        
                        // For Reward Total Items 
                        $('#reward_total_items').val(old_values.reward_total_items);
    
                        // Re-populate Form Fields with Old Value(s)
                        // For Reward Information
                        $.each(old_values.reward, function(key, value){
                            $('#' + 'reward' + '_' + key + '_' + 'reward_award_status').val(value.reward_award_status);
                            $('#' + 'reward' + '_' + key + '_' + 'reward_type_id').val(value.reward_type_id).change();
                            $('#' + 'reward' + '_' + key + '_' + 'reward_owner_name_th').val(value.reward_owner_name_th);
                            $('#' + 'reward' + '_' + key + '_' + 'reward_owner_name_en').val(value.reward_owner_name_en);
                            $('#' + 'reward' + '_' + key + '_' + 'reward_owner_description_th').val(value.reward_owner_description_th);
                            $('#' + 'reward' + '_' + key + '_' + 'reward_owner_description_en').val(value.reward_owner_description_en);
                            $('#' + 'reward' + '_' + key + '_' + 'reward_date').val(value.reward_date);
                            $('#' + 'reward' + '_' + key + '_' + 'reward_name_th').val(value.reward_name_th);
                            $('#' + 'reward' + '_' + key + '_' + 'reward_name_en').val(value.reward_name_en);
                            $('#' + 'reward' + '_' + key + '_' + 'reward_education_level_id').val(old_values.reward_education_level_id).change();
                            $('#' + 'reward' + '_' + key + '_' + 'reward_academic_year').val(old_values.reward_academic_year);
                            $('#' + 'reward' + '_' + key + '_' + 'reward_academic_semester').val(old_values.reward_academic_semester);
                            $('#' + 'reward' + '_' + key + '_' + 'reward_prize_amount').val(old_values.reward_prize_amount);
                            $('#' + 'reward' + '_' + key + '_' + 'reward_currency_id').val(old_values.reward_currency_id).change();
                        });
                    },
                    success: function(response){
                    
                        // Go to Student Profile Page
                        window.location.replace(response.route);
                    }
                });
            });
    

    After the validation failed, I used this code to send the old data I want to display with their error messages and the message for SweetAlert Pop-up. However, what is returned is in json and I cannot get back to the form which I don't really know why. This way get me the data I want but cannot take to where I want the data should be displayed which is very weird for me.

    This is not the best solution, but I think sending data with AJAX is working better than the code I used earlier. Thank you to @kris gjika for this idea. For now, I have to figure out why I can't get back to the form.

    If anyone has any ideas, please post yours in the comment below.

    For more information, this is the code I used after the validation failed in the Controller :

    if ($validator->fails()) {
    
            $data = array();
    
            $old_values = $request->all();
            $all_errors = $validator->errors();
            $message = 'ขออภัย!nกรุณากรอกข้อมูลให้ถูกต้องและครบถ้วน!';
    
            $data = compact(
                'message',
                'old_values',
                'all_errors',
            );
    
            return $data; 
        }
    

    This is the form tag I used and the route I set :

    <form id="form" name="form" method="POST" action="{{ route('achievement_info.store_achievement_info', ['profile_id' => $student->id]) }}" enctype="multipart/form-data">
    
    Route::post('/menu_student/{profile_id}/store_achievement_info', [AchievementInfoController::class, 'store'])->middleware('auth')->name('achievement_info.store_achievement_info');
    

  2. First of all I think you are over complicating this, by not submitting the form via ajax (since you re-render rewards on error). By using a regular form submit, your page reloads on validation errors and you lose the current state of the form, for example: how many items have been created via addMoreItem.

    So what if you didn’t have to reload on validation errors?

    $(document).ready(function () { // assuming you are using Jquery
      let form = $(`form#form-id`);
      form.submit(function (e) {
        e.preventDefault();
        form.find(`.text-danger.error-msg`).remove(); // remove any previous messages
        form.find(`button[type="submit"]`).css({"cursor": 'not-allowed'}).prop('disabled', true); // disable submit until done
    
        $.ajax({
          type: form.attr('method'),
          url: form.attr('action'),
          data: form.serialize(),
          success: function(response) {
            location.reload();
            // or window.location.replace(`{{ route('route-to-redirect-on-success') }}`)
          },
          error: function(xhr, status, error) {
            if (xhr.status == 422) { // validation error
              Object.keys(xhr.responseJSON.errors).forEach((f) => {
                let error = xhr.responseJSON.errors[f][0]; // get first error message of field
                let input = form.find(`[name="${f}"]`); // find input matching name
                
                if (input.length == 0 && f.includes('.')) { // match fields such as parent.child => parent[child]
                  let name = f.split('.').map((p, i) => {return i == 0 ? p : `[${p}]`}).join('');
                  input = form.find(`[name="${name}"]`);
                }
    
                if (input.length) {
                  input.parent().append(`<span class="text-danger error-msg">${error}</span>`); // append error to input container, assuming each input is contained in some other element like div, or change the selector for your need
                }
            }  else {
              alert(`Something went wrong!`);
            }
    
            form.find(`button[type="submit"]`).css({"cursor": ''}).prop('disabled', false); // re enable submit
          });
          
          return false;
      });
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search