Mrxqwe's avatar

Dynamic Cascading Dropdown with Livewire

Hi,

issue is that the second select box in never shown. I tried both tutorials talltips.novate.co.uk/livewire/dynamic-cascading-dropdown-with-livewire and this one canbayat.com.tr/post/laravel-dynamic-dependent-dropdown-livewire but none of them showed me the second select box.

$projects always stays NULL. I cannot find my error. Maybe you can help. Here is my code with some debug info.

showbookingprice.blade.php

<div>
    <div class="form-group">
        <label for="sponsor">Sponsor</label>
        <select name="sponsor" id="sponsor" wire:model="sponsor" class="form-control" >
        <option value=''>Choose A Sponsor</option>
        @foreach($sponsors as $sponsor)
            <option value={{ $sponsor->id }}>{{ $sponsor->name }}</option>
        @endforeach
        </select>
    </div>

    @if(count($projects) > 0)
        <div class="form-group">
            <label for="project">Project</label>
            <select name="project" id="project" wire:model="project" class="form-control {{ count($this->projects)==0 ? 'hidden' : '' }}" >
            <option value=''>Choose A Project</option>
            @foreach($this->projects as $project)
                <option value={{ $project->id }}>{{ $project->name }}</option>
            @endforeach
            </select>
        </div>
    @endif
    <br>
    DEBUG:<br>
    sponsors: {{$sponsors}}<br>
    sponsor: {{$sponsor}}<br>
    projects: {{count($projects)}}<br>
    project: {{$project}}<br>
    <br>
</div>

Showbookingprice.php

<?php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\Price;
use App\Models\Sponsor;


class Showbookingprice extends Component
{

    public $sponsors;
    public $projects = [];
    public $sponsor;
    public $project;

    public function mount()
    {
        $this->refreshData();
    }

    private function refreshData()
    {
        $this->sponsors = Sponsor::orderBy('name')->get();
        if (!empty($this->sponsor)) {
            $this->projects = Price::orderBy('name')->get();
        }
    }

    public function render()
    {
        $this->refreshData();
        return view('livewire.showbookingprice');
    }
}

Any help is welcome. Thanks !

0 likes
26 replies
Sinnbeck's avatar

Why is projects Price?

$this->projects = Price::orderBy('name')->get(); 
Mrxqwe's avatar

Hi Sinnbeck,

I just used existing Models to speed up .-)

Mrxqwe's avatar

My debug output looks always like this

DEBUG:
sponsors: [{"id":4,"[content removed]"}]
sponsor: {"id":7," [content removed] "}
projects: 0
project:
Sinnbeck's avatar

Try adding a dd inside the refreshData. Is it hit?

if (!empty($this->sponsor)) {
dd($this->sponsor);
            $this->projects = Price::orderBy('name')->get();
        }
1 like
Mrxqwe's avatar

@Sinnbeck Wow, so quick answers ! Great ! No, unfortunately sponsor wasn't hit. Can't find the root cause.

This should work and assign it to sponsor, right?

<div>
    <div class="form-group">
        <label for="sponsor">Sponsor</label>
        <select name="sponsor" id="sponsor" wire:model="sponsor" class="form-control" >
        <option value=''>Choose A Sponsor</option>
Mrxqwe's avatar
private function refreshData()
    {
        dd($this->sponsor);
        $this->sponsors = Organisation::orderBy('name')->get();
        if (!empty($this->sponsor)) {
                  $this->projects = Organisation::orderBy('name')->get();
        }
    }

$this->sponsor stays at null

Sinnbeck's avatar

Are you sure you have data in Price?

public function mount()
    {
        dd(Price::all());
        $this->refreshData();
    }
1 like
Sinnbeck's avatar

Is this a component inside another or is this a full page component? If it just a regular component, is there then any chance that projects are defined further up?

Mrxqwe's avatar

@Sinnbeck It's part of an other blade file. But nothing fancy.

@extends('layouts.admin')
@section('content')

    <div class="card">
        <div class="card-header">
            <h4>New booking {{ $asset->name }}</h4>
        </div>

        <div class="card-body">
            <form method="POST" action="{{ route('object.store') }}" enctype="multipart/form-data">
                @csrf
                {{ method_field('POST') }}
                
                <livewire:showbookingprice > 
[...]
Mrxqwe's avatar

@Sinnbeck sure normal template

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ trans('panel.site_title') }}</title>
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet" />
    <link href="https://unpkg.com/@coreui/[email protected]/dist/css/coreui.min.css" rel="stylesheet" />
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" rel="stylesheet" />
    <link href="https://use.fontawesome.com/releases/v5.2.0/css/all.css" rel="stylesheet" />
    <link href="https://cdn.datatables.net/1.10.19/css/dataTables.bootstrap4.min.css" rel="stylesheet" />
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" rel="stylesheet" />
    <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/css/select2.min.css" rel="stylesheet" />
    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/css/bootstrap-datetimepicker.min.css" rel="stylesheet" />
    <link href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/min/dropzone.min.css" rel="stylesheet" />
    <link href="{{ asset('css/custom.css') }}" rel="stylesheet" />
    @yield('styles')
    @livewireStyles
</head>

<body class="header-fixed sidebar-fixed aside-menu-fixed aside-menu-hidden login-page">
    <div class="c-app flex-row align-items-center">
        <div class="container">
            @yield("content")
        </div>
    </div>
    @yield('scripts')
    @livewireScripts
</body>

</html>
Mrxqwe's avatar

@Sinnbeck comes here

<?php

namespace App\Http\Controllers\Object;

use Acaronlex\LaravelCalendar\Calendar;

use App\Http\Controllers\Controller;

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Http\Request;

use App\Models\Asset;
use App\Models\Price;
use App\Models\Booking;
use App\Models\BookingStatus;
use App\Models\Organisation;
use App\Models\User;

use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Gate;
use Illuminate\View\ViewName;
use Symfony\Component\HttpFoundation\Response;
use Yajra\DataTables\Facades\DataTables;


class ObjectController extends Controller
{	 

[...]
 /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create(Request $request)
    {
        $id = $request->id;

        $asset = Asset::with('media', 'category', 'step')->findOrFail($id);

        $prices = Price::where('asset_id', $id)
            //->wherein('orga_category_id', $orga_category_id)
            ->where('orga_category_id', $orga_category_id)
            ->firstOrFail();

        $users = User::with('orgas')->get();

        $orgas = Organisation::with('orgaUsers')->get();

        //dd($asset);
        return view('object.create', compact('asset', 'users', 'prices', 'orgas'));
    }
}
Snapey's avatar

You are reusing the variable $sponsor

        <select name="sponsor" id="sponsor" wire:model="sponsor" class="form-control" >  <<< HERE
        <option value=''>Choose A Sponsor</option>
        @foreach($sponsors as $sponsor)  <<< HERE
            <option value={{ $sponsor->id }}>{{ $sponsor->name }}</option>
        @endforeach
        </select>

You overwrite $sponsor in your component with an instance of $sponsor object.

Don't use the same variables names!

1 like
Mrxqwe's avatar

@Snapey thanks for the hint ! I changed sponsor to sponsor_id in the blade, but still null as value. Something wrong with the naming of the select field that it stays at null?

<div>
    <div class="form-group">
        <label for="sponsor">Sponsor</label>
        <select name="sponsor" id="sponsor" wire:model="sponsor" class="form-control" >
        <option value=''>Choose A Sponsor</option>
        @foreach($sponsors as $sponsor_id)
            <option value={{ $sponsor_id->id }}>{{ $sponsor_id->name }}</option>
        @endforeach
        </select>
    </div>

    @if(count($projects) > 0)
        <div class="form-group">
            <label for="project">Project</label>
            <select name="project" id="project" wire:model="project" class="form-control {{ count($this->projects)==0 ? 'hidden' : '' }}" >
            <option value=''>Choose A Project</option>
            @foreach($this->projects as $project)
                <option value={{ $project->id }}>{{ $project->name }}</option>
            @endforeach
            </select>
        </div>
    @endif
    <br>
    DEBUG:<br>
    sponsors: {{$sponsors}}<br>
    sponsor: {{$sponsor}}<br>
    projects: {{count($projects)}}<br>
    project: {{$project}}<br>
    <br>
</div>
Mrxqwe's avatar

my debug output shows nothing is assigned to $sponsor

DEBUG:
sponsor:
projects: 0
project:
Mrxqwe's avatar

@Sinnbeck Yes, I linked both examples in my first posting. Both are not working for me. Couldn't find out why.

Snapey's avatar

@Mrxqwe Open your browser developer tools, Network tab. When you change the dropdown you should see a network request going to the server

1 like
Mrxqwe's avatar

@Snapey BINGO ! livewirescript was not loaded ! Many thanks for that hint.

Mrxqwe's avatar

Sorry, I can't do it. No button available to close the thread.

Please or to participate in this conversation.