Assume you have a list of items with checkboxes:


<ul class="project-ul">
@foreach ($projects as $project)
<li>  <label><input type="checkbox" value="1" class="checking"  data-id="{{$project->id}}" {{($project->featured) ? 'checked' : ''}}> {{$project->title}}</label></li>
@endforeach
</ul>

This may return a list like this:

Now we create a jQuery ajax call that should send the `id` and the checkbox `status` (note the value of the checkbox is not used here) to a PHP script:

Ajax Call

 
$(document).ready(function(){
      $('.checking').change(function() {
          var $status = $(this).is(":checked");
          var $id     = $(this).data('id');
          $.ajax({
            url: '/admin/resources/edit',
            type: 'POST',
            data: {status: $status, id :$id, _token: {{csrf_token()}}},
            dataType: 'json',
          })
          .done(function($data) {
            alert('All good!');
          })
          .fail(function($data){
            alert('Error, see log data');
            console.log($data);
          })

        });
    });

PHP Script


  public function toogleFeatured(Request $request)
    {
      $id     = $request->input('id');
      $status = $request->input('status');
    
      $project = \App\Resources\Project::find($id);      
      $project->featured = $status;
      $x->save();

      return json_encode("Updated");
    }

This script won’t work like that. Did you spot the problems?

Problem 1: CSRF Protection

In Laravel there is a build in CSRF Protection. You probably use csrf_field() for any normal post form that you created. You also need to that for ajax posts.

      1. Solution You could just ignore the csrf token for that specific url in app/Http/Middleware/VerifyCsrfToken:

       
          protected $except = [
             '/admin/resources/edit'
          ];
      

      While this is sometimes necessary for webhooks, its a bad practice for your own routes, because the csrf token is there for a reason – to protect against request from other domains. Therefore lets look for an alternative.

      2. Solution How about simply passing a CSRF token to your ajax call?

       
       data: {status: $status, id :$id, _token: {{csrf_token()}}},
      

      This seems fair for a quick fix, however, it comes with two major downsites. Firstly, one has to modify every ajax call in the application. Secondly, one can’t put his javascript code in a seperate .js file (because one needs to call the php function csrf_token()). This leads us to our recommended 3. Solution

      3. Solution Add a meta tag with a csrf_token in your master.blade

      
      <meta name="csrf-token" content="{{ csrf_token() }}" />
      

      and in your app.js (or whatever js file that you have included in your master.blade) add this:

      
        $.ajaxSetup({
              headers: {
                  'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
              }
          });
      

      Now you never need to care about csrf_token in any ajax call. It will just work out of the box.

Problem 2: Boolean’s

Now after we have taken care of the csrf_token, the code will run without any error. However, if one checks the database the column featured in the project table remains unchanged.

The problem is that var $status = $(this).is(“:checked”); will return either true or false. Because HTTP is a text protocol with no concept of booleans or integers everything must be stringified. In other words


  public function toogleFeatured(Request $request)
    {
      $id     = $request->input('id');
      $status = $request->input('status'); // this returns a string "true" or "false" instead of a boolean
    
      $project = \App\Resources\Project::find($id);      
      $project->featured = $status; // you can't set a boolean to a string "true" or "false"
      $x->save();

      return json_encode("Updated");
    }

There are again multiple solutions to this:

      1. Solution Instead of sending true or false, send an integer value 1 or 0:

       
          $.ajax({
            url: '/admin/resources/edit',
            type: 'POST',
            data: {status: $status ? 1 : 0, id :$id}, 
            dataType: 'json',
          })        
      

      This will work now

      
           $project->featured = $status; // if you set this to "0" or "1" this will be correctly converted
      
      2. Solution Another possible way of solving this is using the filter_var function with filter FILTER_VALIDATE_BOOLEAN in you php script. According to the docs:

      Returns TRUE for “1”, “true”, “on” and “yes”. Returns FALSE otherwise. If FILTER_NULL_ON_FAILURE is set, FALSE is returned only for “0”, “false”, “off”, “no”, and “”, and NULL is returned for all non-boolean values.

      SO this would also do it:

      
            $status =  filter_var ($request->input('status'), FILTER_VALIDATE_BOOLEAN); // converts string "true"/"false" to boolean true/false
          
      
adam