0

I have a livewire component class and a livewire blade component. In the livewire blade component I have a submit button that when is clicked should call the updatedCity method to update the city.

However when the submit button is clicked on the livewire component its not working. For example the user types "Munich" in the input and then clicks on the submit button and it doesnt work, on the console shows : "Uncaught ReferenceError: Dortmund is not defined", Dortmund is the city of the authenticated user.

Thanks

Blade livewire component:

<div>

@guest

    <h1>Please login/register</h1>

@else

    <h1>Weather in
        <b>{{ $city }}</b></h1>

    <main>

        <div>
            <div class="flex items-center justify-between rounded-md">
                <form wire:submit.prevent="getWeatherByCity({{$city}})">
                    <input
                        type="text" name="city">
                    <div>
                        <x-form.button>Submit</x-form.button>
                    </div>
                </form>
            </div>
        </div>

        <div x-data="{ openedIndex: -1  }">
            <div
                @click="openedIndex == 0 ? openedIndex = -1 : openedIndex = 0">

                <div>
                    <img
                        src="http://openweathermap.org/img/wn/{{ $forecastWeatherResp['current']['condition']['icon'] }}.png"
                        alt="weather icon">
                    <span>
                {{ round($forecastWeatherResp['current']['temp_c']) }}º
            </span>
                </div>

                <div>
            <span>
                Today
            </span>
                    <span>
                {{ ucwords($forecastWeatherResp['current']['condition']['text']) }}
            </span>
                </div>

                <svg style="display: none;"
                     x-show.transition.duration.500ms="openedIndex != 0"
                     xmlns="http://www.w3.org/2000/svg"
                     class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                    <path fill-rule="evenodd"
                          d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
                          clip-rule="evenodd"/>
                </svg>
                <svg
                    x-show.transition.duration.500ms="openedIndex == 0"
                    xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                    <path fill-rule="evenodd"
                          d="M14.707 12.707a1 1 0 01-1.414 0L10 9.414l-3.293 3.293a1 1 0 01-1.414-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 010 1.414z"
                          clip-rule="evenodd"/>
                </svg>
            </div>
            <div
                x-show="openedIndex == 0"
                class="w-full border " style="display: none;">
                <div class="border-t border-gray-200">
                    <dl>

                        <div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
                            <dt class="text-sm font-medium text-gray-500">
                                Feels Like
                            </dt>
                            <dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
                                {{ round($forecastWeatherResp['current']['temp_c']) }}º
                            </dd>
                        </div>
                        ....
                    </dl>
                </div>

            </div>

            @foreach($forecastWeatherResp['forecast']['forecastday'] as $weather)
                <ul>
                    <li
                        @click="openedIndex == {{ $loop->iteration }} ? openedIndex = -1 : openedIndex = {{$loop->iteration}}"
                        class="w-full">
                        <div>
                            <div>
                                <img src="http://openweathermap.org/img/wn/{{ $weather['day']['condition']['icon'] }}"
                                     alt="weather icon">
                            </div>
                            ....

                        </div>

                        <div
                            x-show="openedIndex == {{ $loop->iteration }}">
                            <div>
                                <dl>

                                    <div>
                                        <dt>
                                            Feels Like
                                        </dt>
                                        <dd>
                                            {{ round($weather['day']['avgtemp_c']) }}º
                                        </dd>
                                    </div>
                                    .....
                                </dl>
                            </div>

                        </div>

                    </li>

                </ul>

            @endforeach
        </div>
    </main>

@endguest
</div> 

Livewire component class:

class WeatherInfo extends Component 

{ 

public $city; 
private $currentWeatherRes; 
private $forecastWeatherRes;

public function mount()
{
    $this->city = auth()->user()->city ?? $this->city;
    $this->getWeatherByCity($this->city);
}


protected function getWeatherByCity($city)
{

    $apiKey = config('services.openweather.key');

    $this->currentWeatherResp = Http::get(
        "http://api.weatherapi.com/v1/current.json?&q={$this->city}&key={$apiKey}")->json();

    $this->forecastWeatherResp = Http::get(
        "http://api.weatherapi.com/v1/forecast.json?key={$apiKey}&q={$this->city}&days=7")->json();


}

public function render()
{
    return view('livewire.weather-info', [
        'currentWeatherResp' => $this->currentWeatherResp,
        'forecastWeatherResp' => $this->forecastWeatherResp,
    ]);
}
}
2
  • 1
    Reason you pass something you are not using? protected function getWeatherByCity()<-- and getWeatherByCity({{$city}}) Commented Oct 27, 2021 at 15:11
  • Thanks, it was a typo I already corrected the question. Commented Oct 27, 2021 at 15:13

1 Answer 1

1

You don't need to send in the city-argument to your method, because you use wire:model="city" to bind it to $this->city. That's it.

class WeatherInfo extends Component
{
    public $city;
    private $currentWeatherRes;
    private $forecastWeatherRes;

    public function mount()
    {
        $this->city = auth()->user()->city ?? $this->city;
        $this->getWeatherByCity();
    }

    public function getWeatherByCity()
    {
        $apiKey = config('services.openweather.key');

        $this->currentWeatherResp = Http::get(
            "http://api.weatherapi.com/v1/current.json?&q={$this->city}&key={$apiKey}"
        )->json();

        $this->forecastWeatherResp = Http::get(
            "http://api.weatherapi.com/v1/forecast.json?key={$apiKey}&q={$this->city}&days=7"
        )->json();
    }

    public function render()
    {
        return view('livewire.weather-info', [
            'currentWeatherResp' => $this->currentWeatherResp,
            'forecastWeatherResp' => $this->forecastWeatherResp,
        ]);
    }
}
<form wire:submit.prevent="getWeatherByCity()">
    <input type="text" name="city" wire:model="city">
    <div>
        <x-form.button>Submit</x-form.button>
    </div>
</form>
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! Do you know how to show a custom validation rule with livewire? For example if the api response array contains 404, if(in_array('404', $this->currentWeatherResp)){, how to show a validation error? Because the user can enter an invalid location, and I checked that with if(in_array('404', $this->currentWeatherResp)){. But Im not understanding how to show the message to the user since in the render() the currentWeatherResp and forecastWeatherResp variables are being passed to the view.
You can just do $this->addError('invalidCity', 'An invalid city "'.$this->city.'" was entered'); in your getWeatherByCity() method, then do @error('myError') {{ $message}} @enderror in your view.
Thanks, however like that the render method is executed anyway and then it shows errors like undefined index errors because in the render method it returns these 'currentWeatherResp' => $this->currentWeatherResp, 'forecastWeatherResp' => $this->forecastWeatherResp,. Do you know how to solve that? When exist errors how to show the validation message and not run again the render method?

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.