How to build conditional list of dropdown options in Laravel Voyager

Boris Tetřev picture Boris Tetřev · Aug 16, 2019 · Viewed 7k times · Source

I have a problem with Laravel Voyager v1.2. I need to filter list of related list of options in select dropdown easily by where condition. So let's say I have Post with relation to Category, but I don't want to list all Categories in select dropdown, but just that active ones.

  1. I tried to force Voyager to take my own method to build an relationship in Post model:
public function category_id() {
  return $this->belongsTo('Post::class')->where('active',1);
}
  1. Also tried to define scope in BREAD JSON options for the category field:
{
    "relationship": {
        "key": "id",
        "label": "name",
        "scopes": [
            "active"
        ]
    }
}

Post Model part:

public function scopeActive($query) {
  return $query->where('active', 1);
}

This is how my Post class look like (I don't actualy need to filter active categories, but food categories by it's IDs):

public function soup1() {
  return $this->belongsTo('App\Meal')->where('meal_category_id',1);
}


public function soup2() {
  return $this->belongsTo('App\Meal')->where('meal_category_id',1);
}

public function mealy() {
  return $this->belongsTo('App\Meal')->where('meal_category_id',7);
}

public function scopeSoups($query)
{
  return $query->where('meal_category_id', 1);
}

public function scopeMealy($query)
{
  return $query->where('meal_category_id', 7);
}

I want to receive filtered list of options instead of all model rows.

Answer

Ali Jouadi picture Ali Jouadi · Aug 16, 2019

You can do this easily by overriding the blades in voyager:

Step 1 :

Copy relationship.blade.php

from: /"YourProject"/vendor/tcg/voyager/resources/views/formfields/relationship.blade.php

To: /"YourProject"/resources/views/vendor/voyager/formfields/relationship.blade.php

This way voyager will use this file in your your project views instead of the package file in the vendor.

Read More: Voyager Documentations

Step 2 :

In the line 25 of relationship.blade.php you'll see this block of code:

            <select
                class="form-control select2-ajax" name="{{ $options->column }}"
                data-get-items-route="{{route('voyager.' . $dataType->slug.'.relation')}}"
                data-get-items-field="{{$row->field}}"
            >
                @php
                    $model = app($options->model);
                    $query = $model::where($options->key, $dataTypeContent->{$options->column})->get();
                @endphp

                @if(!$row->required)
                    <option value="">{{__('voyager::generic.none')}}</option>
                @endif

                @foreach($query as $relationshipData)
                    <option value="{{ $relationshipData->{$options->key} }}" @if($dataTypeContent->{$options->column} == $relationshipData->{$options->key}){{ 'selected="selected"' }}@endif>{{ $relationshipData->{$options->label} }}</option>
                @endforeach
            </select>

Which you should override it with this:

            @if($options->table == 'categories')

                <div class="ap-form-input">
                    @php
                        $model = app($options->model);
                        $query = $model::where('active', true)->get();
                    @endphp

                    <select class="form-control select2" id="language-select" name="{{ $options->column }}">


                        @if(!$row->required)
                            <option value="">{{__('voyager::generic.none')}}</option>
                        @endif

                            @foreach($query as $relationshipData)
                                <option value={{ $relationshipData->{$options->key} }} @if($dataTypeContent->{$options->column} == $relationshipData->{$options->key}){{ 'selected="selected"' }}@endif>{{ $relationshipData->{$options->label} }}</option>
                            @endforeach
                    </select>
                </div>

            @else
                <div class="ap-form-input">
                    <select class="form-control select2" name="{{ $options->column }}">
                        @php
                            $model = app($options->model);
                            $query = $model::all();
                        @endphp

                        @if(!$row->required)
                            <option value="">{{__('voyager::generic.none')}}</option>
                        @endif

                        @foreach($query as $relationshipData)
                            <option value={{ $relationshipData->{$options->key} }} @if($dataTypeContent->{$options->column} == $relationshipData->{$options->key}){{ 'selected="selected"' }}@endif>{{ $relationshipData->{$options->label} }}</option>
                        @endforeach
                    </select>
                </div>
            @endif

This way when you're using categories relationship you will only get the active categories.