user2519032
user2519032

Reputation: 829

Laravel drop down filter without search button

I have a page with doctors listing. All the doctors belongs to specific category: gynecology, surgery, urology etc.

How can I filter them with a select drop down without using submit button? I know this is possible to achieve with Ajax, but I need help.

Here's my code:

DoctorsController

public function doctorsList() {
    $doctors = Doctor::orderBy('id', 'desc')->paginate(20);
    $categories = Category::all();
    return view('doctors-list', compact('doctors', 'categories'));
}

doctors-list.blade.php

  <div class="filter text-center">
    <select name="category_id">
      <option value="all">All</option>
      @foreach($categories as $category)
        <option value="{{ $category->id }}">{{ $category->title }}</option>
      @endforeach
    </select>
  </div>
  @foreach($doctors as $doctor)
    <div class="article">
      <div class="row">
        <div class="col-sm-3">
          <div class="image"><a href="{{ route('doctor', $doctor->slug) }}"><img width="260" src="{{ Storage::url($doctor->image) }}" /></a></div>
        </div>
        <div class="col-sm-9 right">
          <div class="title"><h3>{{ $doctor->title }}</h3></div>
          <div class="body">{!! strip_tags(str_limit($doctor->body, 300)) !!}</div>
          <div class="more"><a href="{{ route('doctor', $doctor->slug) }}">More></a></div>
        </div>
      </div>
    </div>
  @endforeach

Route:

Route::get('/doctors', 'DoctorsController@doctorsList')->name('doctorsList');

Migrations (two separate files):

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateDoctorsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('doctors', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('doctors');
    }
}


<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateDoctorTranslationsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('doctor_translations', function (Blueprint $table) {
          $table->increments('id');
          $table->integer('doctor_id')->unsigned();
          $table->string('locale')->index();

          // The actual fields to store the content of your entity. You can add whatever you need.
          $table->string('title');
          $table->string('slug')->unique();
          $table->string('image');
          $table->text('body');
          $table->integer('category_id');
          $table->string('status');
          $table->integer('user_id');

          $table->unique(['doctor_id', 'locale']);
          $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('doctor_translations');
    }
}

Models: Doctor.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Dimsav\Translatable\Translatable;

class Doctor extends Model
{
  use Translatable;

  public $translatedAttributes = ['title', 'slug', 'image', 'body', 'category_id','status', 'user_id'];

  public function category() {
    return $this->belongsTo('App\Category');
  }
}

DoctorTranslation.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Cviebrock\EloquentSluggable\Sluggable;

class DoctorTranslation extends Model
{
  use Sluggable;

  public $timestamps = false;

  /**
   * Return the sluggable configuration array for this model.
   *
   * @return array
   */
  public function sluggable()
  {
      return [
          'slug' => [
              'source' => 'title',
              'onUpdate' => true
          ]
      ];
  }
}

Right now with this code I'm displaying all the doctors and I have created the Select box that gets the categories from the database.

How can I filter them when I choose a different category from the drop down?

I'm using Laravel 5.5

Upvotes: 0

Views: 1952

Answers (2)

Mihai Matei
Mihai Matei

Reputation: 24276

You can use a query parameter to filter the doctors by category. This would be the updated controller method:

public function doctorsList(Request $request)
{
    $query = (new Doctor)->newQuery();
    $selectedCategory = $request->get('category_id', 'all');

    if (is_numeric($selectedCategory )) {
        $query->whereTranslation('category_id', $selectedCategory);
    }

    $doctors = $query->orderBy('id', 'desc')->paginate(20);
    $categories = Category::all();

    return view('doctors-list', compact('doctors', 'categories', 'selectedCategory'));
}

And the blade template would be something like:

<form action="{{route('doctorsList')}}" method="get">
  <div class="filter text-center">
    <select name="category_id" onchange="this.form.submit()">
      <option value="all">All</option>
      @foreach($categories as $category)
        <option value="{{ $category->id }}" {{$category->id == $selectedCategory ? 'selected' : ''}}>{{ $category->title }}</option>
      @endforeach
    </select>
  </div>
</form>
  @foreach($doctors as $doctor)
    <div class="article">
      <div class="row">
        <div class="col-sm-3">
          <div class="image"><a href="{{ route('doctor', $doctor->slug) }}"><img width="260" src="{{ Storage::url($doctor->image) }}" /></a></div>
        </div>
        <div class="col-sm-9 right">
          <div class="title"><h3>{{ $doctor->title }}</h3></div>
          <div class="body">{!! strip_tags(str_limit($doctor->body, 300)) !!}</div>
          <div class="more"><a href="{{ route('doctor', $doctor->slug) }}">More></a></div>
        </div>
      </div>
    </div>
  @endforeach

Of course, you can put the onchange handler somewhere in your js files instead of doing it inline.

I considered you named the doctors listing route as doctors.list

Also, if you use this solution, you should be aware to add the category query parameter to the pagination links too.

Upvotes: 3

phpdroid
phpdroid

Reputation: 1663

Here is my solution in this solution you will not require any server call

just give id to the <div class="article">

give id as docs-categoryid-doctorid

now on your <select name="category_id" onchange="showhidedocs();">

function showhidedocs(){
      var cat=$('#category_id').val();
            if(cat!="all"){
             $('[id^=docs-]').hide();
             var temp="[id^=docs-"+cat+']';
             $(temp).show();
                          }else{
                              $('[id^=docs-]').show();
                              }
                       }

Upvotes: 2

Related Questions