Search code examples
laravellaravel-8laravel-livewire

Laravel Livewire: Input select, default option selected


I am trying to fetch country codes from my database and trying to get the default value via IP address. It works just as I want for a second but then I don't know what happens but it refreshes itself and scrolls to the first option instead of the selected option.

Livewire Controller Component

use App\Models\CountryCodes;
use Livewire\Component;
use Location;

class TestCountry extends Component
{
    public $iso;
    public $country_codes;
    public $country_code;

    public function mount()
    {
        $iso=Location::get('ip');
        $this->iso=$iso->countryCode;
    }

    public function render()
    {
        return view('livewire.test-country',[
            $this->country_codes = CountryCodes::select('nicename','iso','phonecode')->get()->toArray()
        ]);
    }
}

Livewire Blade Component

<select wire:model.lazy="country_code" name="country_code" id="country_code" class="form-control" required>
    @foreach($country_codes as $country_code)
        <option value="{!! $country_code['iso'] !!}"
                wire:key="{{$country_code['iso']}}"
                {{ $country_code['iso'] == $iso ? 'selected' : ''}}>
            {!! $country_code['iso'] !!} +{!! $country_code['phonecode'] !!}
        </option>
    @endforeach
</select>

This code does select my default option but it changes and moves to the first option automatically. Am I doing something wrong here?


Solution

  • I believe what is happening is, $iso is set correctly, but the select is bound to the $country_code property, not $iso, so briefly, the check you have works, but because $country_code doesn't have a value, the selected option is lost when the state is updated by Livewire.

    TLDR: Livewire is checking whatever is in the wire:model attribute, so the class property must be set for it to work.

    I would try something like this:

    public function mount()
    {
        $iso = Location::get('ip');
        $this->iso = $iso->countryCode;
    
        // set $country_code to $iso
        $this->country_code = $this->iso;
    }
    

    I believe Livewire will intelligently select the state, so I think the selected check can be removed:

    <select wire:model.lazy="country_code" name="country_code" id="country_code" class="form-control" required>
        @foreach($country_codes as $country_code)
            <option
                value="{!! $country_code['iso'] !!}"
                wire:key="{{$country_code['iso']}}"
            >
                {!! $country_code['iso'] !!} +{!! $country_code['phonecode'] !!}
            </option>
        @endforeach
    </select>
    

    Also, any reason for using {!! !!} tags in the view rather than just {{ }}?