Adding client dropdown to the top of issues list table and filtering the list with that dropdown

This tutorial is part of this mini project on Laravel vue spa. To see all the sections of this project click here

Step 01: first we need to create Api/ClientController and ClientResource with artisan command

php artisan make:controller Api/ClientController
php artisan make:resource ClientResource

Step 02: Changing ClientResource like below

class ClientResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
        ];
    }
}

Step 03: Changing Api/ClientController like below

// at the top 
use App\Http\Resources\ClientResource;
use App\Models\Client;

class ClientController extends Controller
{
    public function index() {
        return ClientResource::collection(Client::all());
    }
}

Step 04: Changing routes/api.php like below

Route::get('clients', [App\Http\Controllers\Api\ClientController::class, 'index']);

Step 05: After completing above steps for api end points lets head back to creating clients composable under resources/js/composables

import { ref } from 'vue'
 
export default function useClients() {
    const clients = ref({})
 
    const getClients = async () => {
        axios.get('/api/clients')
            .then(response => {
                clients.value = response.data.data;
            })
    }
 
    return { clients, getClients }
}

Step 06: After creating composable we need to import this inside components/Issues/Index.vue to populate clients dropdown above issues list table.

// first inside script tag adding following codes 
import { ref } from 'vue';

import useClients from "../../composables/clients";

const search_client = ref('')
const { clients, getClients } = useClients()

onMounted(() => {
    ...
    getClients()
})

// then in component template adding following code like below 
<table>
    <tr>
        <th class="px-6 py-3 bg-gray-50 text-left">
        </th>
        <th class="px-6 py-3 bg-gray-50 text-left">
            <select v-model="search_client" :options="clients" placeholder="Filter By Client" :settings="{ 'width' : '100%' }">
                <option value="" selected>-- Filter by client --</option>
                <option v-for="client in clients" :value="client.id" :key="client.id">
                    {{ client.name }}
                </option>
            </select>
        </th>
        <th>
        <th class="px-6 py-2 bg-gray-50 text-left">
        </th>            
        </th>                
        <th>
        <th class="px-6 py-2 bg-gray-50 text-left">
        </th>             
        </th>                
        <th></th>                
        <th></th>                
  </tr>          
</table>
<table class="table">
    <thead class="thead-dark">
    .......
Step 07: Now we can go on adding the feature of filtering list with client dropdown value.
// first need to add watch ( importing from vue ) for variable search_client 
import { ref, onMounted, watch } from 'vue';

.......
watch(search_client, (current, previous) => { 
    getIssues(1, current)
})     
</script>

// next we need to tweak issues.js like below to take client_id to pass it to api end point
const getIssues = async (page = 1, client = '') => { 
    axios.get('/api/issues?page=' + page + '&client=' + client)
        .then(response => {
            issues.value = response.data;
        })
}

Step 08: After making changes in composables and component we need to sync this change to Api/IssuesController like below for client_id filtering using conditional claue when

// at the top 
use Illuminate\Database\Eloquent\Builder;

public function index() {
    $issues = Issue::with('client')
    ->when(request('client'), function (Builder $query) { 
        $query->where('client_id', request('client'));
    }) 
    ->paginate(3);
    return IssueResource::collection($issues);
}

Step 09: Unfortunately, now client filtering would work with dropdown change but will break the pagination setup in such that if there are multiple pages for a particular client then paginate wont carry the client_id in the next pagination. We can add the following change to fix this inside Bootstrap4Pagination component inside Index.vue template

// this change will pass necessary parameters in composable which will then be passed to api endpoints for fetching correct rows for particular filtered paramters
<Bootstrap4Pagination :data="issues" @pagination-change-page="page => getIssues(page, search_client)" />

Related Posts


Seeding users and role_user data

Seeding clients and issues data

Adding client column in table

Storing issue in db table

Update issue

Showing user data and logout

Permission securing backend

Permission securing frontend