Building a Real-Time Weather Dashboard with Laravel Reverb and Vue.js

Building a Real-Time Weather Dashboard with Laravel Reverb and Vue.js

In today’s fast-paced digital world, real-time data is crucial for providing users with up-to-date information. In this tutorial, we’ll create a dynamic weather dashboard using Laravel Reverb and Vue.js, showcasing how to implement real-time updates in a practical application.

Table of Contents
    Add a header to begin generating the table of contents

    What We’ll Build

    We’ll create a weather dashboard that displays current weather conditions and forecasts for multiple cities. The dashboard will update in real-time as new data becomes available, providing users with the latest weather information without requiring page refreshes.

    Prerequisites

    • Basic knowledge of Laravel and Vue.js
    • Familiarity with API integrations
    • Laravel 11.x installed on your system
    • Composer and Node.js installed

    Step 1: Setting Up the Laravel Project

    First, let’s create a new Laravel project:

    composer create-project laravel/laravel weather-dashboard
    cd weather-dashboard

    Step 2: Installing and Configuring Laravel Reverb

    Install Laravel Reverb by running:

    php artisan install:broadcasting

    Update your .env file with the following configurations:

    BROADCAST_DRIVER=reverb
    REVERB_APP_ID=weather-dashboard
    REVERB_APP_KEY=your-app-key
    REVERB_APP_SECRET=your-app-secret
    

    Step 3: Setting Up the Database

    For this project, we’ll use SQLite for simplicity. Update your .env file:

    DB_CONNECTION=sqlite
    DB_DATABASE=/absolute/path/to/database.sqlite
    

    Create the SQLite database:

    touch database/database.sqlite

    Step 4: Creating the Weather Model and Migration

    Generate the Weather model and migration:

    See also
    Mastering SEO with Laravel: Building Dynamic Sitemaps for Enhanced Visibility
    php artisan make:model Weather --migration

    Update the migration file in database/migrations:

    public function up()
    {
    Schema::create('weather', function (Blueprint $table) {
    $table->id();
    $table->string('city');
    $table->float('temperature');
    $table->string('condition');
    $table->float('humidity');
    $table->float('wind_speed');
    $table->timestamps();
    });
    }

    Run the migration:

    php artisan migrate

    Step 5: Creating the WeatherUpdated Event

    Generate a new event:

    php artisan make:event WeatherUpdated

    Update the app/Events/WeatherUpdated.php file:

    <?php

    namespace AppEvents;

    use AppModelsWeather;
    use IlluminateBroadcastingChannel;
    use IlluminateBroadcastingInteractsWithSockets;
    use IlluminateContractsBroadcastingShouldBroadcastNow;
    use IlluminateFoundationEventsDispatchable;
    use IlluminateQueueSerializesModels;

    class WeatherUpdated implements ShouldBroadcastNow
    {
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $weather;

    public function __construct(Weather $weather)
    {
    $this->weather = $weather;
    }

    public function broadcastOn()
    {
    return new Channel('weather-updates');
    }
    }

    Step 6: Creating the WeatherController

    Generate a new controller:

    php artisan make:controller WeatherController

    Update the app/Http/Controllers/WeatherController.php file:

    <?php

    namespace AppHttpControllers;

    use AppModelsWeather;
    use AppEventsWeatherUpdated;
    use IlluminateHttpRequest;
    use IlluminateSupportFacadesHttp;

    class WeatherController extends Controller
    {
    public function index()
    {
    return Weather::all();
    }

    public function update()
    {
    $cities = ['London', 'New York', 'Tokyo', 'Sydney', 'Paris'];

    foreach ($cities as $city) {
    $response = Http::get("https://api.openweathermap.org/data/2.5/weather", [
    'q' => $city,
    'appid' => env('OPENWEATHERMAP_API_KEY'),
    'units' => 'metric'
    ]);

    if ($response->successful()) {
    $data = $response->json();
    $weather = Weather::updateOrCreate(
    ['city' => $city],
    [
    'temperature' => $data['main']['temp'],
    'condition' => $data['weather'][0]['main'],
    'humidity' => $data['main']['humidity'],
    'wind_speed' => $data['wind']['speed']
    ]
    );

    event(new WeatherUpdated($weather));
    }
    }

    return response()->json(['message' => 'Weather data updated successfully']);
    }
    }

    Step 7: Setting Up Routes

    Update your routes/web.php file:

    use AppHttpControllersWeatherController;

    Route::get('/', function () {
    return view('dashboard');
    });

    Route::get('/api/weather', [WeatherController::class, 'index']);
    Route::post('/api/weather/update', [WeatherController::class, 'update']);

    Step 8: Creating the Vue Component

    Create a new file resources/js/components/WeatherDashboard.vue:

    <template>
    <div class="weather-dashboard">
    <h1>Real-Time Weather Dashboard</h1>
    <div class="city-grid">
    <div v-for="city in cities" :key="city.id" class="city-card">
    <h2>{{ city.city }}</h2>
    <p>Temperature: {{ city.temperature }}°C</p>
    <p>Condition: {{ city.condition }}</p>
    <p>Humidity: {{ city.humidity }}%</p>
    <p>Wind Speed: {{ city.wind_speed }} m/s</p>
    </div>
    </div>
    </div>
    </template>

    <script>
    import axios from 'axios';

    export default {
    data() {
    return {
    cities: []
    }
    },
    mounted() {
    this.fetchWeatherData();
    this.listenForUpdates();
    },
    methods: {
    fetchWeatherData() {
    axios.get('/api/weather')
    .then(response => {
    this.cities = response.data;
    });
    },
    listenForUpdates() {
    Echo.channel('weather-updates')
    .listen('WeatherUpdated', (event) => {
    const index = this.cities.findIndex(city => city.id === event.weather.id);
    if (index !== -1) {
    this.cities[index] = event.weather;
    } else {
    this.cities.push(event.weather);
    }
    });
    }
    }
    }
    </script>

    <style scoped>
    .weather-dashboard {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
    }

    .city-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 20px;
    }

    .city-card {
    background-color: #f0f0f0;
    border-radius: 8px;
    padding: 20px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    }
    </style>
    See also
    Building an AI-Powered Text Summarizer with Laravel and Livewire

    Step 9: Setting Up the Blade View

    Create a new file resources/views/dashboard.blade.php:

    <!DOCTYPE html>
    <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Weather Dashboard</title>
    @vite(['resources/css/app.css', 'resources/js/app.js'])
    </head>
    <body>
    <div id="app">
    <weather-dashboard></weather-dashboard>
    </div>
    </body>
    </html>

    Step 10: Updating app.js

    Update your resources/js/app.js file:

    import './bootstrap';
    import { createApp } from 'vue';
    import WeatherDashboard from './components/WeatherDashboard.vue';

    const app = createApp({});
    app.component('weather-dashboard', WeatherDashboard);
    app.mount('#app');

    Step 11: Running the Application

    Start your Laravel application:

    php artisan serve

    In a separate terminal, start Reverb:

    php artisan reverb:start

    And in another terminal, compile your assets:

    npm run dev

    Visit http://localhost:8000 to see your real-time weather dashboard in action!

    How It Works

    • The WeatherController fetches data from the OpenWeatherMap API and stores it in the database.
    • When weather data is updated, it broadcasts a WeatherUpdated event.
    • The Vue.js component listens for these events and updates the UI in real-time.
     

    Conclusion

    See also
    Streamlining API Exception Handling in Laravel 11: The JSON Way

    By leveraging Laravel Reverb and Vue.js, we’ve created a dynamic weather dashboard that updates in real-time. This approach can be applied to various applications requiring live data updates, providing a seamless and engaging user experience.

    FAQ

    Vue.js complements Laravel well for real-time applications because of its reactive data binding and component-based architecture. It allows for efficient updates to the UI when new data is received through WebSockets, creating a smooth, dynamic user experience.

    Yes, the concept demonstrated in this weather dashboard can be applied to various types of real-time data applications. Examples include live stock tickers, sports score updates, social media feeds, or any scenario where data needs to be updated in real-time without page refreshes.

    Leave a Reply

    Your email address will not be published. Required fields are marked *