0

I'm fairly new to Laravel (and I love it!) I'm trying to do something a bit complicated: Creating a drop-down menu that upon selection of an option -will display a second drop-down menu that will give further options dynamically based on the previous selection.

My controller looks like this:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Manufacturer;
use App\GearCategory;
use App\SubCategory;
use App\GearItem;

class GearItemController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth'); 
    }

    public function create(Manufacturer $manufacturers, GearItem $gearItem, GearCategory $gearCategory, SubCategory $subCategory)
    {
        // dd($gearCategory->all());
        $catNum = 6; // <-- needs to be equal to the dispaly div name. Hard coded as 6 for test purposes. 
        $gearCategory = $gearCategory->all();
        $subCategory = $subCategory::where('gear_categories_id', $catNum)->get();
        $manufacturers = $manufacturers->all();


        return view('gearitem.create', compact('gearCategory'), compact('subCategory'), compact('manufacturers'),  compact('gearItem'));
    }
}

My blade looks like this:

  <div class="card-header">
                    <h3>Add a new gear Item</h3>

                </div>
                <div class="container">
                    <select name="gear_categories_id" id="gear_categories_id" class="custom-select mb-3 mt-3"
                        onchange="selector('display_div', this)">
                        <option value="" selected>Choose category</option>
                        @foreach ($gearCategory as $category)
                        <option id="cat_selector" value="{{ $category->id  }}"
                            {{ (old("gear_categories_id") == $category->id ? "selected" : "") }}>{{ $category->name }}
                        </option>

                        @endforeach
                    </select>
                </div>


                <script>
                    "use strict"
                    function selector(divId, element) {

                        console.log(element.value);

                        document.getElementById(divId).setAttribute("name", element.value)

                    }
                </script>



                    <div class="display_div container" id="display_div" name="">

                    <select name="sub_categories_id" id="sub_categories_id" class="custom-select mb-3 mt-3"
                    onchange="selector('display_div', this)">
                    <option value="" selected>Choose item's type</option>
                    @foreach ($subCategory as $scategory)
                    <option id="cat_selector" value="{{ $scategory->id }}"
                        {{ (old("sub_categories_id") == $scategory->id ? "selected" : "") }}>{{ $scategory->name }}
                    </option>
                    @endforeach
                </select>

                </div>

(Sorry for using vanilla JS i haven't gotten into Vue yet...) I'm trying to pass the name of the "display_div" onto the $catNum variable in the controller (set to "6" just to test if it works but should be set to whatever the user is choosing on the first dropdown) The values of the 'gear_categories_id' appear as a foreign key in the SubCategory model and if i'll manage to feed these values to the second dropdown it would work. I've been struggling for hours with it and I can't figure it out... Please help and sorry for being such a n00b.

1 Answer 1

1

You can use an AJAX request on change of the parent category drop-down to populate the subcategories. See the code below. I have added a second route to get subCategories for a specific categoryID.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Manufacturer;
use App\GearCategory;
use App\SubCategory;
use App\GearItem;

class GearItemController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth'); 
    }

    public function create(Manufacturer $manufacturers, GearItem $gearItem, GearCategory $gearCategory, SubCategory $subCategory)
    {
        // dd($gearCategory->all());
        $catNum = 6; // <-- needs to be equal to the dispaly div name. Hard coded as 6 for test purposes. 
        $gearCategory = $gearCategory->all();
        $subCategory = $subCategory::where('gear_categories_id', $catNum)->get();
        $manufacturers = $manufacturers->all();


        return view('gearitem.create', compact('gearCategory'), compact('subCategory'), compact('manufacturers'),  compact('gearItem'));
    }

    public function getSubCategories($categoryID) {
        return  SubCategory::where('gear_categories_id', $categoryID)->get();
    }
}

Route::get('/sub-categories/{categoryID}', 'GearItemController@getSubCategories');

<div class="card-header">
    <h3>Add a new gear Item</h3>
</div>
<div class="container">
    <select name="gear_categories_id" id="gear_categories_id" class="custom-select mb-3 mt-3"
        onchange="selector('display_div', this)">
        <option value="" selected>Choose category</option>
        @foreach ($gearCategory as $category)
        <option id="cat_selector" value="{{ $category->id  }}"
            {{ (old("gear_categories_id") == $category->id ? "selected" : "") }}>{{ $category->name }}
        </option>

        @endforeach
    </select>
</div>


    <script>
        "use strict"
        function selector(divId, element) {

            console.log(element.value);

            document.getElementById(divId).setAttribute("name", element.value);


            fetch('/sub-categories/')
            .then(res => res.json())
            .then(subCategories => {
                var options = subCategories.reduce( (opts, cat) => 
                    `${opts}<option value="${cat.id}">${cat.name}</option>`, "");
                document.getElementById("sub_categories_id").innerHTML = `<option value="" selected>Choose item's type</option>${options}`;
            });

        }
    </script>



<div class="display_div container" id="display_div" name="">

    <select name="sub_categories_id" id="sub_categories_id" class="custom-select mb-3 mt-3"
        onchange="selector('display_div', this)">
        <option value="" selected>Choose item's type</option>
    </select>

</div>
Sign up to request clarification or add additional context in comments.

11 Comments

Not really, I mean if you don't want to refresh the page, you are going to have to make an AJAX request
Or If there is not too much categories and Subcategories, you can just fetch all the subcategories and then filter on the client side. How many Subcategories are there?
Yes. Basically whenever you need a Separate set of data from the server, in the background, you will have to make a separate request for that. Thus, you will need another route
Although even 100 is not that large a number. You could fetch all and store them on the client side and then Filter that array based on the array stored in client side. If you really want to avoid creating the extra route
If you want, I can edit the answer to use the fetch library
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.