DEV Community

Cover image for Creation, Listing and Reactivity 📜
Northon Iserhardt
Northon Iserhardt

Posted on

Creation, Listing and Reactivity 📜

Posts

To proceed with notifications, we need events that trigger them. We will notify a user whenever they are tagged in a post. So let's move on to creating the posts.

New posts

Let's add an option to register posts to our navbar:
Image description

In resources/views/livewire/layout/navigation.blade.php:
Image description

<x-nav-link :href="route('posts.index')" :active="request()->routeIs('posts.index')" wire:navigate>
    {{ __('Posts') }}
</x-nav-link>
Enter fullscreen mode Exit fullscreen mode

Image description

<x-responsive-nav-link :href="route('posts.index')" :active="request()->routeIs('posts.index')" wire:navigate>
    {{ __('Posts') }}
</x-responsive-nav-link>
Enter fullscreen mode Exit fullscreen mode

Using Laravel commands we can create several resources at the same time.
For more details: https://laravel.com/docs/10.x/eloquent#generating-model-classes

In our case we will create the Model, migration and controller with resources:
php artisan make:model -mrc Post

In database/migrations/{date}_create_posts_table.php:
Image description

    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            $table->foreignId('tagged_user_id')->nullable()->constrained('users')->cascadeOnDelete();
            $table->string('message', 280);
            $table->timestamps();
        });
    }
Enter fullscreen mode Exit fullscreen mode

tagged_user_id can be null, since a post can be created without having to tag someone.

Let's run the migrations:
php artisan migrate

In routes/web.php:
Image description

Route::view('posts','posts.index')->middleware('auth')->name('posts.index');
Enter fullscreen mode Exit fullscreen mode

In app/Models/Post.php:
Image description

    protected $fillable = [
      'user_id',
      'tagged_user_id',
      'message',
    ];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function taggedUser(): BelongsTo
    {
        return $this->belongsTo(User::class, 'tagged_user_id');
    }
Enter fullscreen mode Exit fullscreen mode

In app/Models/User.php:
Image description

    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }

    public function taggedPosts(): HasMany
    {
        return $this->hasMany(Post::class, 'tagged_user_id');
    }
Enter fullscreen mode Exit fullscreen mode

Let’s create the post registration and listing components:
php artisan make:livewire posts.post-create
php artisan make:livewire posts.post-list

Let's create the index.blade.php file in resources/views/posts, and import the default layout with our components:
Image description

<x-app-layout>
    @livewire('posts.post-create')
    @livewire('posts.post-list')
</x-app-layout>
Enter fullscreen mode Exit fullscreen mode

One point of attention: To make the project simpler, we will not work with validation and repository layers.

In resources/views/livewire/posts/post-create.blade.php:
Image description

<div>
    <form class="grid grid-cols-2 max-w-xl mx-auto m-6" wire:submit.prevent="save">
        <textarea
            wire:model="state.message"
            placeholder="{{ __('Post Message') }}"
            class="col-span-2 w-full shadow rounded-lg border-gray-200"
        ></textarea>
        @error('state.message') <span class="error">{{ $message }}</span> @enderror

        <select wire:model="state.tagged_user_id" class="mt-4 border-gray-200 rounded-lg">
            <option value=""></option>
            @foreach($users as $user)
                <option value="{{$user->id}}">{{$user->name}}</option>
            @endforeach
        </select>
        @error('state.tagged_user_id') <span class="error">{{ $message }}</span> @enderror

        <div class="flex justify-end">
            <button class="w-16 rounded-lg mt-4 bg-blue-500 shadow text-white">{{ __('Save') }}</button>
        </div>
    </form>
</div>

Enter fullscreen mode Exit fullscreen mode

Let's add it to app/Livewire/Posts/PostCreate.php:
Image description

    public $state = [
        'tagged_user_id' => null,
        'message' => ''
    ];

    public $users = null;

    public function mount()
    {
        $this->users = User::query()->get();
    }

    public function save(Request $request)
    {
        $this->validate([
            'state.message' => 'required|max:280',
            'state.tagged_user_id' => 'sometimes'
        ]);

        $request->user()->posts()->create($this->state);
        $this->reset('state');
    }
Enter fullscreen mode Exit fullscreen mode

List of posts

Now, we will proceed with the list of posts, where we will include both the posts we created and those in which we were tagged.

In resources/views/livewire/post/post-list.blade.php:
Image description

<div>
    <div class="max-w-xl mx-auto mt-16">
        @foreach($posts as $post)
            <div class="bg-white p-6 rounded-md shadow-md text-center break-words mt-4">
                <p class="text-gray-700">
                    "{{$post->message}}"
                </p>
                <p class="text-blue-500 text-sm">{{ optional($post->taggedUser)->name ? '@'.$post->taggedUser->name : '' }}</p>
                <p class="text-end text-sm text-gray-500 mt-2">{{$post->user->name}}</p>
            </div>
        @endforeach
    </div>
</div>

Enter fullscreen mode Exit fullscreen mode

In app/Livewire/Posts/PostList.php:
Image description

<?php

namespace App\Livewire\Posts;

use Livewire\Component;

class PostList extends Component
{
    public $posts;

    public function render()
    {
        $this->posts = auth()->user()->posts()
            ->orWhere('tagged_user_id', auth()->user()->id)
            ->orderBy('id', 'desc')
            ->get();

        return view('livewire.posts.post-list');
    }
}
Enter fullscreen mode Exit fullscreen mode

Reactivity

When a post is created, you need to reload the screen to view it. However, with Livewire, we were able to make the listing reactive. This means that when we create a post the list will be updated automatically.

But how?
Let's dispatch the creation component to the listing component, indicating that it is necessary to update the list.

In app/Livewire/Posts/PostCreate.php let's add dispatch:
Image description

        $this->dispatch('refreshPostList');
Enter fullscreen mode Exit fullscreen mode

In app/Livewire/Posts/PostList.php let's add our listener with the refresh event:
Image description

    protected $listeners = [
        'refreshPostList' => '$refresh'
    ];
Enter fullscreen mode Exit fullscreen mode

Ready! Our features are now reactive.

Top comments (0)