Laravel 7 Class Based Components – Part II
Tags: laravel, php
Published: 2020-08-21 15:05:29

In my previous post about  [Laravel 7 Class Based Components](https://yossiabramov.com/blog/laravel-7-class-based-components-part-i)  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:

```plaintext
php artisan make:component NewsGridContainer
php artisan make:component NewsGridItem
```

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`:

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

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
<?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;
    }
    ...
}
```

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

```diff
<div class="grid-container">
    @foreach ($newsItems as $item)
        <x-news-grid-item :news-item="$item" />
    @endforeach
</div>
```

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

```php
<?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'];
    }
    ...
}
```

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

```diff
<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>
```

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
<?php

namespace App\View\Components;

use Illuminate\View\Component;

class NewsGridItem extends Component
{
    ...
    public function saySomething(){
        return 'Hello World';
    }
}
```

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

```diff
<div class="news-grid-item">
    {{ $saySomething }}
    ...
</div>
```

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

```php
<?php

namespace App\View\Components;

use Illuminate\View\Component;

class NewsGridItem extends Component
{
    ...
    public function saySomething($msg){
        return $msg;
    }
}
```

And in the component:

```diff
<div class="news-grid-item">
    {{ $saySomething('Hello World') }}
    ...
</div>
```

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
<?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);
    }
}
```

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

```diff
<div class="news-grid-item">
    {{ $titleCase($title) }}
    ...
</div>
```

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
<?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);
    }
}
```

And our  `blade`  component can remain nice and clean:

```diff
<div class="news-grid-item">
    {{ $title }}
    ...
</div>
```

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
<?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');
    }
}
```

And our  `blade`  component:

```diff
<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>
```

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

👉  [https://laravel.com/docs/7.x/blade#components](https://laravel.com/docs/7.x/blade#components)

✍ For more posts about Laravel:
[https://yossiabramov.com/](https://yossiabramov.com/)