jrdavidson's avatar

Livewire Subview Dependent Upon Dropdown

I have a form with 6 different inputs on it, 1 of which is a select dropdown. What I am wanting to do is once the dropdown is changed it will inject a partial into the form based on the user's selection. Currently my page initially loads fine however I"m trying to have it render the child view into this form based on the user's input. Something I need to also figure out is passing the value of the selected option from the select into the changeCustomView method so I can know which child view to render.

<x-form.inputs.select
    ...
    id="someId"
    wire:click="changeCustomView"
/>

@if ($viewToRender)
    {{ $viewToRender }}
@endif
<?php

namespace App\Http\Livewire\Foo;

use App\Http\Livewire\BaseComponent;
use Illuminate\Support\Facades\View;
use App\Models\MyClass;

class Form extends BaseComponent
{
    public $myVar;

    public $viewToRender = '';

    public function mount(MyClass $myVar)
    {
        $this->myVar = $myVar;
    }

    public function changeCustomView()
    {
        return $this->viewToRender = View::make('livewire.views.types.foobar')->render();
    }

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\View\View
     */
    public function render()
    {
        return view('livewire.foo.form', [
            'myVar' => $this->myVar,
        ]);
    }
}
0 likes
18 replies
webrobert's avatar

I would use a dynamic component and change the variable for which one is used

jrdavidson's avatar

@webrobert Thanks for your help. So with making the change with adding it as a dynamic component I just need to figure out which route I need to do to have it change the subview. Do I use the click event on the select or use the updated lifecycle hook. Either way I need to pass the selected option so I can figure out which view needs passes since it will be dynamic.

@if ($subViewToUse)
    <x-dynamic-component :component="$subViewToUse" class="mt-4" />
@endif

Livewire Component

public $subViewToUse;

public function changeCompetitorsView()
{
	return $this->subViewToUse = View::make('livewire.myviews.types.foo')->render();
}

public function updatedMySelectId()
{
    // 
}
webrobert's avatar

@jrdavidson

public function updatedMyVar()
{
 	$this->subViewToUse = “livewire.myviews.types.” . $this->myVar; // lookup, etc
}

...
<x-form.inputs.select
    ...
    id="someId"
    wire:model="myVar"
/>
@if ($subViewToUse)
    <x-dynamic-component :component="$subViewToUse" class="mt-4" />
@endif 

jrdavidson's avatar

@webrobert It got me further down the line to next problem but this deals right now with passing the blade attributes down into nested blade components. I'll show you what I'm meaning.

Lets say once the select option is changed it will load the corresponding dynamic component. Then when it tries to render the blade its looking for the $attributes but at this point there might not be any that I need to apply.

main.blade.php

@if ($subViewToUse)
    <x-dynamic-component :component="$subViewToUse" class="mt-4" :foo="$foo" />
@endif

Livewire Component

public $subViewToUse;

public function updatedSelectElementId()
{
        $myClassSlug = MyClass::find($this->selectElementId)->slug;

        return $this->subViewToUse = View::make('livewire.directory.to.slugs.'.$myClassSlug)->render();
}

livewire/directory/to/slugs/slug1.blade.php

<x-form.inputs.select
    name="selectElementName"
    label="My Slug"
    :options="$options"
    wire:model="myVar"
/>

views/components/inputs/select.blade.php

<select
    class="form-control @error($name) is-invalid @enderror"
    name="{{ $name }}"
    id="{{ $name }}-dropdown"
    {{ $attributes->whereStartsWith('wire:click') }}
    {{ $attributes->whereStartsWith('wire:model') }}
</select>
webrobert's avatar

@jrdavidson huh?

Why have you removed the wire:model from the select??

And for the dynamic component your meant to pass a string…


updatedSelectElementId()
{
    $myClassSlug = MyClass::find($this->selectElementId)->slug;

     $this->subViewToUse = “livewire.directory.to.slugs.”. $myClassSlug;

}

On mobile forgive my syntax 
webrobert's avatar

And if you load the slug and name into an array to foreach into the select you won’t have to look it up twice. You can just use the slug. As I originally posted. I updated the first code example to include the string.

jrdavidson's avatar

@webrobert I updated to include the wire-model because for some reaosn I removed it. My apologies. Its looking for the right view and it exists but for reason reason is saying Unable to locate a class or view for component [livewire.directory.to.slugs.foo]. I don't understand because foo does exist in views/livewire/directory/to/slugs/foo.blade.php

jrdavidson's avatar

@webrobert For some reason it doesn't show the contents of the component. It doesn't error either so I'm clueless on the problem.

jrdavidson's avatar

@webrobert What I'm happening it will do is depending on the option selected from the dropdown inject the HTML from the component into the page but looking at the inspector I don't see any additional html that wasn't there during page load.

jrdavidson's avatar

@webrobert It is. I can actually @dd('component found') inside of the blade file and have it show the dd but when I remove the dd It doesn't inject its HTML into the page.

webrobert's avatar
Level 51

@jrdavidson

working example, tested. blade files named test and test2 in the components directory...

<select wire:model="valuee">
    <option>test</option>
    <option>test2</option>
</select>

<x-dynamic-component :component="$componentName" class="mt-4" />
public $componentName = 'test';
public $valuee;

public function updatedValuee()
{
    $this->componentName = $this->valuee;
}
1 like
jrdavidson's avatar

@webrobert Wanted to report I saw in the console I didn't have 1 root element showing. This problem has been resolved. Thank you for your assistance.

1 like

Please or to participate in this conversation.