DEV Community

Yossi Abramov
Yossi Abramov

Posted on • Originally published at yossiabramov.com

Laravel 7 Class Based Components – Part II

In my previous post about Laravel 7 Class Based Components I went over creating class based components as well as passing data to components and displaying them. In this post I will go over component class methods. And once again, class based components allow us to create robust components and harness the power of classes, so do more exploring on your own – you will not regrate it! ☝

Component Class Methods

Let’s say we have a news site with a news grid container and some news items in it. We would probably create 2 components: a news grid container component and a news grid item component.

Let’s create our components:

php artisan make:component NewsGridContainer
php artisan make:component NewsGridItem
Enter fullscreen mode Exit fullscreen mode

Then, we could pass a news items array with news items to our news grid container, inside the grid container.

In our welcome.blade.php:

@php
  $newsItems = [
   [
     'id' => 1,
     'title' => 'this is my title',
     'body' => '......',
     'featured_image' => '/images/featured.jpeg',
  ],
];
@endphp
<x-news-grid-container :news-items="$newsItems"/>
Enter fullscreen mode Exit fullscreen mode

In order to pass our $newsItems array to news-grid-container.blade.php we first need to declare it as public property in the app/Views/Components/NewsGridContainer.php class and assign it in the __construct() method:

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class NewsGridContainer extends Component
{
    public $newsItems;
    /**
     * Create a new component instance.
     *
     * @return void
     */
    public function __construct($newsItems)
    {
        $this->newsItems = $newsItems;
    }
    ...
}
Enter fullscreen mode Exit fullscreen mode

And in resources/views/components/news-grid-container.blade.php:

<div class="grid-container">
    @foreach ($newsItems as $item)
        <x-news-grid-item :news-item="$item" />
    @endforeach
</div>
Enter fullscreen mode Exit fullscreen mode

Here are our news grid item class properties declarations and __construct():

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class NewsGridItem extends Component
{

    public $title;
    public $body;
    public $featured_image;

    /**
     * Create a new component instance.
     *
     * @return void
     */
    public function __construct($newsItem)
    {
        $this->title = $newsItem['title'];
        $this->body = $newsItem['body'];
        $this->featured_image = $newsItem['featured_image'];
    }
    ...
}
Enter fullscreen mode Exit fullscreen mode

And our resources/views/components/news-grid-item.blade.php:

<div class="news-grid-item">
    <img class="featured-image" src="{{ $featured_image }}" alt="featured image">     
    <div class="content-body">
        <h3 class="title">{{ $title }}</h3>
        <p class="excerpt">{{ $body }}</p>
        <button class="read-more">READ MORE</button> 
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Now that we have some components to work with, let’s go over some basic ways of using component class methods.

First, let’s create a simple public function saySomething() that will simply return ‘Hello World’.

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class NewsGridItem extends Component
{
    ...
    public function saySomething(){
        return 'Hello World';
    }
}
Enter fullscreen mode Exit fullscreen mode

This is how you would call it in you blade component:

<div class="news-grid-item">
    {{ $saySomething }}
    ...
</div>
Enter fullscreen mode Exit fullscreen mode

If we want to pass some data to this function, we first need to change it a bit:

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class NewsGridItem extends Component
{
    ...
    public function saySomething($msg){
        return $msg;
    }
}
Enter fullscreen mode Exit fullscreen mode

And in the component:

<div class="news-grid-item">
    {{ $saySomething('Hello World') }}
    ...
</div>
Enter fullscreen mode Exit fullscreen mode

Now, let’s say our news item’s title is all in lower case letters and we want to “Title Case” it. We have a lot of ways of doing it: Modify the title already in our __construct method, or maybe inside our blade component itself. we can also create a public function called titleCase($title) in our class and pass the title to it:

<?php

namespace App\View\Components;

use Illuminate\Support\Str;
use Illuminate\View\Component;

class NewsGridItem extends Component
{
    ...
    public function titleCase($title){
        return Str::title($title);
    }
}
Enter fullscreen mode Exit fullscreen mode

Then, we would need to call it like this in our blade component (or do something even uglier in our __construct method):

<div class="news-grid-item">
    {{ $titleCase($title) }}
    ...
</div>
Enter fullscreen mode Exit fullscreen mode

However, there is a much nicer way of modifying properties. We can create a public function that shares the name of a declared property like this:

<?php

namespace App\View\Components;

use Illuminate\Support\Str;
use Illuminate\View\Component;

class NewsGridItem extends Component
{
    ...
    public function title(){
        return Str::title($this->title);
    }
}
Enter fullscreen mode Exit fullscreen mode

And our blade component can remain nice and clean:

<div class="news-grid-item">
    {{ $title }}
    ...
</div>
Enter fullscreen mode Exit fullscreen mode

I’ve added 2 more methods to this class just to show a bit more of what is possible – but this does not even scratch the surface. Here is the full result:

<?php

namespace App\View\Components;

use Illuminate\Support\Str;
use Illuminate\View\Component;

class NewsGridItem extends Component
{

    public $title;
    public $body;
    public $featured_image;

    /**
     * Create a new component instance.
     *
     * @return void
     */

    public function __construct($newsItem)
    {
        $this->title = $newsItem['title'];
        $this->body = $newsItem['body'];
        $this->featured_image = $newsItem['featured_image'];
    }

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\View\View|string
     */

    public function render()
    {
        return view('components.news-grid-item');
    }

    public function title()
    {
        return Str::title($this->title);
    }

    public function body()
    {
        return Str::limit($this->body, 40);
    }

    public function image(){
        // Check if image exists in public assets folder
        if(file_exists(public_path($this->featured_image))){
            return asset($this->featured_image);
        } 
        // Fallback
        return asset('/images/fallback.png');
    }
}
Enter fullscreen mode Exit fullscreen mode

And our blade component:

<div class="news-grid-item">
    <img class="featured-image" src="{{ $image }}" alt="featured image">     
    <div class="content-body">
        <h3 class="title">{{ $title }}</h3>
        <p class="excerpt">{{ $body }}</p>
        <button class="read-more">READ MORE</button> 
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Read more about class-based components in the Laravel official docs:

👉 https://laravel.com/docs/7.x/blade#components

✍ For more posts about Laravel:
https://yossiabramov.com/

Top comments (0)