Search code examples
jqueryajaxlaraveldatatablesjquery-ajax

Having to refresh a page after form submission using jquery ajax


So I have a page to display courses a student is enrolled in and also in that page is a form in a modal all which is built as a Laravel web project, and the purpose of that form is that a user selects courses(all data is pulled from a database) that they want to enroll in and click 'enroll' to add it to courses they are enrolled in. So the form was built with some elements of jQuery ajax and now when there is a successful enrollment it runs and displays a message on the modal, the problem now is with a successful enrollment I still have to refresh the page before I see the course listed, I'm looking for a way to fix it so that I don't have to refresh the page after exiting the modal

this is my form in my course.blade.php

 <div id="enroll-form">
                    <div class="modal-body">
                       
                        <form method="post" action="{{ route('enroll') }}">
                            @csrf
                    
                            <label for="courses">Select Courses:</label>
                            <select class="form-select"name="courses[]"  id="courses"   aria-label="Default select example">
                                <option selected>Select Course</option>
                                @foreach ($availableCourses as $course)
                                    <option value="{{ $course->courseId }}">{{ $course->courseTitle }}</option>
                                @endforeach
                            </select>
                    </div>
                    <div class="modal-footer">
                        <button class="btn btn-secondary text-black" type="button" data-dismiss="modal">Cancel</button>
                        <button class="btn btn-primary text-black" type="submit">Enroll</button>
                        
                    </div>
                </form>
                    
                    <div class="card-footer">
                        <div id="enroll-messages"></div>
                    </div>
                </div>

This is my script code

<script src="{{asset('vendor/jquery/jquery.min.js')}}"></script>
 <script>
        $(document).ready(function() {
            $('#enroll-form form').submit(function(e) {
                e.preventDefault();
    
                $.ajax({
                    type: 'POST',
                    url: $(this).attr('action'),
                    data: $(this).serialize(),
                    success: function(response) {
                        $('#enroll-messages').html('<div class="alert alert-success">' + response.success + '</div>');
                    },
                    error: function(response) {
                        $('#enroll-messages').html('<div class="alert alert-danger">' + response.responseJSON.error + '</div>');
                    }
                });
            });
        });
    </script>

This is my courseController

 public function index()
    {
        $studentId = Auth::user()->studentId; //Retrieve the currently logged-in student's ID using the Auth facade.
        $availableCourses = Course::all();
     
        $user = User::with('courses')->find($studentId);
       
        return view('course', 
    [
        
        'user' => $user,
        'availableCourses' => $availableCourses
    ]);
    }

    public function enroll(Request $request)
    {
        $studentId = Auth::user()->studentId;
        $coursesToEnroll = $request->input('courses', []);
        $user = User::with('courses')->find($studentId);
        $alreadyEnrolled = $user->courses->pluck('courseId')->intersect($coursesToEnroll);
        
        if ($alreadyEnrolled->count() > 0) {
            $courseTitles = Course::whereIn('courseId', $alreadyEnrolled)->pluck('courseTitle')->implode(', ');
            return response()->json(['error' => "You are already enrolled in the following course(s): $courseTitles."], 422);
        }
    
        $user->courses()->syncWithoutDetaching($coursesToEnroll);
    
        return response()->json(['success' => 'Enrollment successful.']);
    }
    
    

With the coursecontroller this is how I loop through the database with this code block in my couse.blade.php to display the courses(PS: Its a jquery datatable)

 <table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
                                  
                                    <thead>
                                        <tr>
                                            <th>Name <i> fa fa-angle-up</i></th>
                                            <th>Course Code</th>
                                            <th>Schedule</th>
                                            <th>Progress</th>
                                        </tr>
                                    </thead>
                                  
                                   
                                    <tbody>
                                        @foreach ($user->courses as $item)
                                        <tr>
                                            <td>{{$item->courseTitle}}</td>
                                            <td>{{$item->courseCode}}</td>
                                            <td>{{$item->courseSchedule}}</td>
                                            <td>{{$item->courseProg}}%</td>
                                            
                                        </tr>
                                        @endforeach
                                        
                                    </tbody>
                                  
                                </table>

And finally my route

Route::get('/course', [CourseController::class, 'index'])
    ->middleware(['auth', 'verified'])
    ->name('course');

Route::post('/enroll', [CourseController::class, 'enroll'])
    ->middleware(['auth', 'verified'])
    ->name('enroll');

With this current code, whenever I try selecting a new course it runs successfully, the success message shows as it should but I still have to reload the page to see it displayed in the section allocated for it. (PS: Also when a user enrolls in a course already registered in the error message also runs as it should saying cant add course cause already registered'


Solution

  • you can achieve that, you can add load new course content to the table after submitting the form, add a new (route, view, controller method):

    web.php

    Add a route for loading courses dynamically:

    Route::get('/course-api', [CourseController::class, 'loadOnlyCourses'])
    ->middleware(['auth', 'verified'])
    ->name('course-api');
    

    courseController.php:

    ...
    
    public function loadOnlyCourses()
    {
        //same code as index()
            $studentId = Auth::user()->studentId;
            $availableCourses = Course::all();
         
            $user = User::with('courses')->find($studentId);
       
        return view('course-only', 
        [
            'availableCourses' => $availableCourses
        ]);
    }
    
    ...
    

    resources/views/course-only.blade.php

    add this view to load the courses html only without the full page :

    @foreach ($user->courses as $item)
        <tr>
            <td>{{$item->courseTitle}}</td>
            <td>{{$item->courseCode}}</td>
            <td>{{$item->courseSchedule}}</td>
            <td>{{$item->courseProg}}%</td>
            
        </tr>
    @endforeach
    

    js script

    now add the fetch code to your script :

    <script>
        $(document).ready(function() {
            $('#enroll-form form').submit(function(e) {
                e.preventDefault();
    
                $.ajax({
                    type: 'POST',
                    url: $(this).attr('action'),
                    data: $(this).serialize(),
                    success: function(response) {
                        $('#enroll-messages').html('<div class="alert alert-success">' + response.success + '</div>');
                        refreshTable();
                    },
                    error: function(response) {
                        $('#enroll-messages').html('<div class="alert alert-danger">' + response.responseJSON.error + '</div>');
                    }
                });
            });
        });
    
        function refreshTable() {
            $("#dataTable tbody").load("{{route('course-api')}}");
        }
    </script>