Laravel 12 DataTables with Relationships & Column Filtering: Complete Guide

Author

Kritim Yantra

Apr 07, 2025

Laravel 12 DataTables with Relationships & Column Filtering: Complete Guide

Introduction

When working with relational data in Laravel DataTables, you often need to:

  1. Display related model data (e.g., show user's department name)
  2. Implement column-specific filtering
  3. Maintain server-side processing performance

This guide covers everything from basic relationship handling to advanced filtering techniques.


1. Setting Up Relationships in DataTables

1.1 Database Structure Example

users
  id - integer
  name - string
  email - string
  department_id - integer

departments
  id - integer
  name - string

1.2 Basic Relationship Setup

// User.php
public function department()
{
    return $this->belongsTo(Department::class);
}

1.3 Controller with Eager Loading

public function getUsers()
{
    $model = User::with('department');
    
    return DataTables::eloquent($model)
        ->addColumn('department_name', function(User $user) {
            return $user->department->name;
        })
        ->toJson();
}

2. Column Filtering Techniques

2.1 Individual Column Filters (Dropdowns)

<!-- Add above your table -->
<div class="row mb-3">
    <div class="col-md-3">
        <select class="form-control filter-select" data-column="3">
            <option value="">All Departments</option>
            @foreach($departments as $department)
                <option value="{{ $department->name }}">{{ $department->name }}</option>
            @endforeach
        </select>
    </div>
</div>

2.2 JavaScript Filter Implementation

let table = $('#users-table').DataTable({
    // ... standard config
});

$('.filter-select').on('change', function() {
    let column = $(this).data('column');
    table.column(column).search(this.value).draw();
});

3. Advanced Relationship Filtering

3.1 Server-Side Relationship Filtering

return DataTables::eloquent($model)
    ->filter(function ($query) {
        if (request()->has('department_filter')) {
            $query->whereHas('department', function($q) {
                $q->where('name', request('department_filter'));
            });
        }
    });

3.2 Dynamic Filter Form

// In controller index method
$departments = Department::pluck('name', 'id');
return view('users.index', compact('departments'));
<form id="filter-form">
    <select name="department_id" class="form-control">
        <option value="">All Departments</option>
        @foreach($departments as $id => $name)
            <option value="{{ $id }}">{{ $name }}</option>
        @endforeach
    </select>
    <button type="submit" class="btn btn-primary">Filter</button>
</form>
$('#filter-form').on('submit', function(e) {
    e.preventDefault();
    table.ajax.url("{{ route('users.data') }}?" + $(this).serialize()).load();
});

4. Handling Complex Relationships

4.1 Many-to-Many Relationships

// Filter users by their roles
->filter(function ($query) {
    if (request()->has('role')) {
        $query->whereHas('roles', function($q) {
            $q->where('name', request('role'));
        });
    }
})

4.2 Polymorphic Relationships

// Filter comments by commentable type
->filter(function ($query) {
    if (request()->has('commentable_type')) {
        $query->where('commentable_type', request('commentable_type'));
    }
})

5. Performance Optimization

5.1 Select Only Required Columns

return DataTables::eloquent($model)
    ->select(['users.id', 'users.name', 'departments.name as department_name'])
    ->join('departments', 'users.department_id', '=', 'departments.id')

5.2 Disable Searching on Unfilterable Columns

columns: [
    { data: 'id', searchable: false },
    { data: 'name' },
    { data: 'department_name', searchable: true }
]

5.3 Cache Frequent Queries

$departments = Cache::remember('departments.filter', 3600, function() {
    return Department::all();
});

6. Complete Example: User Management System

6.1 Final Controller

public function getUsers()
{
    $model = User::with('department', 'roles')
        ->select(['users.*']);
    
    return DataTables::eloquent($model)
        ->addColumn('department_name', function(User $user) {
            return $user->department->name;
        })
        ->addColumn('roles', function(User $user) {
            return $user->roles->pluck('name')->implode(', ');
        })
        ->filter(function ($query) {
            // Department filter
            if (request()->has('department_id')) {
                $query->where('department_id', request('department_id'));
            }
            
            // Role filter
            if (request()->has('role')) {
                $query->whereHas('roles', function($q) {
                    $q->where('name', request('role'));
                });
            }
            
            // Date range filter
            if (request()->has('date_from')) {
                $query->whereDate('created_at', '>=', request('date_from'));
            }
        })
        ->toJson();
}

6.2 Blade View

<table id="users-table" class="table">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Email</th>
            <th>Department</th>
            <th>Roles</th>
            <th>Joined At</th>
        </tr>
    </thead>
</table>

<script>
$(document).ready(function() {
    $('#users-table').DataTable({
        processing: true,
        serverSide: true,
        ajax: {
            url: "{{ route('users.data') }}",
            data: function(d) {
                d.department_id = $('#department-filter').val();
                d.role = $('#role-filter').val();
            }
        },
        columns: [
            { data: 'id' },
            { data: 'name' },
            { data: 'email' },
            { data: 'department_name' },
            { data: 'roles' },
            { 
                data: 'created_at',
                render: function(data) {
                    return new Date(data).toLocaleDateString();
                }
            }
        ]
    });
    
    // Refresh table when filters change
    $('.filter').on('change', function() {
        $('#users-table').DataTable().ajax.reload();
    });
});
</script>

Conclusion

You've now learned how to:
✅ Display relational data in DataTables
✅ Implement column-specific filtering
✅ Handle complex relationship queries
✅ Optimize server-side performance

📌 Need help? Drop your questions below! 👇

LIVE MENTORSHIP ONLY 5 SPOTS

Laravel Mastery
Coaching Class Program

KritiMyantra

Transform from beginner to Laravel expert with our personalized Coaching Class starting June 21, 2025. Limited enrollment ensures focused attention.

Daily Sessions

1-hour personalized coaching

Real Projects

Build portfolio applications

Best Practices

Industry-standard techniques

Career Support

Interview prep & job guidance

Total Investment
$200
Duration
30 hours
1h/day

Enrollment Closes In

Days
Hours
Minutes
Seconds
Spots Available 5 of 10 remaining
Next cohort starts:
June 21, 2025

Join the Program

Complete your application to secure your spot

Application Submitted!

Thank you for your interest in our Laravel mentorship program. We'll contact you within 24 hours with next steps.

What happens next?

  • Confirmation email with program details
  • WhatsApp message from our team
  • Onboarding call to discuss your goals

Tags

Comments

No comments yet. Be the first to comment!

Please log in to post a comment:

Sign in with Google

Related Posts