Blade Component Aliasing

Hey all - been diving into Sage 9 and ran into some trouble implementing a Blade feature that would really help streamline my process.

I’ve been building out a modular system with a rigid HTML structure of sections > rows > columns > elements. To keep the markup consistent, I’ve been using @component to pull in some HTML to wrap whatever’s inside it.

For example, a 2-column section might look like:

@component('components.row', ['row_data' => 'something'])
    @component('components.column', ['col1_data' => 'col1_something'])
        {-- Column 1 stuff --}
    @endcomponent
    @component('components.column', ['col2_data' => 'col2_something'])
        {-- Column 2 stuff --}
    @endcomponent
@endcomponent

which generates something like:

<div class="row something">
  <div class="column col1_something">
        {-- Column 1 stuff --}
  </div>
  <div class="column col2_something">
        {-- Column 2 stuff --}
  </div>
</div>

That’s real annoying to keep typing over and over, and starts to get difficult to organize.

As of v5.6, Blade supports aliasing components (https://laravel.com/docs/5.6/blade#components-and-slots), but Blade’s documentation refers to putting code in a file that doesn’t exist in a standard Sage install. I’ve tried a handful of seemingly related techniques from other threads here but haven’t found a method of setting up this feature that works.

According to Blade documentation, I should be able to replace the above code with something like:

@row( ['rowdata' => 'something'] )
    @column( ['col1_data' => 'col1_something'] )
        {-- Column 1 stuff --}
    @endcolumn
    @column( ['col2_data' => 'col1_something'] )
        {-- Column 2 stuff --}
    @endcolumn
@endrow

…which is much easier to read/understand. Unfortunately, I haven’t been able to figure out how to get Blade component aliasing to work in Sage’s structure.

Has anyone been able to get this kind of aliasing to work?

I know with the current Blade implementation in Sage you can create your own directives (will provide example below), but I remember components not working. (There is a way! See my next reply.)

For a custom blade directive:

// app/setup

sage('blade')->compiler()->directive('row', function ($data) {
    return "<?= " . __NAMESPACE__ . "\\template('components.row', $data); ?>";
});

That assumes you’ve created a components directory in your views folder. You could also use partials.

I guess you could make the corresponding @endrow directives. It’s pretty hacky, but, hey, it’ll work.

I stand corrected. There is a way: :tada:

sage('blade')->compiler()->component('components.row');

It doesn’t create custom directives for the slots though.

@row
  @slot('col1')
    Column 1 stuff
  @endslot
  @slot('col2')
    Column 2 stuff
  @endslot
@endrow

Alternatively you could just create another component:

@row(['class' => 'bg-primary text-white'])

  @col
    Hello, column two!
  @endcol

  @col(['class' => 'col-9'])
    What’s up one?
  @endcol

@endrow 

It doesn’t seem to let you use @slot('some_slot') and another embedded component side-by-side though (unless the component is embedded in the slot). If you need to pass anything to another slot, it’d be best to do that through the embedded component.

:tophat: https://github.com/tightenco/jigsaw/pull/204

2 Likes

So the first method (directive) partially works, but it’s not putting the content within the slot. For example:

@row 
   <p>Some content</p>

Prints

<div class=row>
</div>
<p>Some content</p>

It’s probably worth noting that there doesn’t seem to be a way to provide the end to the component we’re aliasing. Putting in:

@row 
   <p>Some content</p>
@endrow

prints

<div class=row>
</div>
<p>Some content</p>
@endrow

and

@row 
   <p>Some content</p>
@endcomponent

breaks the page completely. It also doesn’t seem to understand how the slot connects:

@row
    @slot
        <p>Some content</p>
    @endslot

doesn’t print anything at all, not even the row component.

The second method isn’t working for me at all. Blade docs suggest you might need the name of your alias, so I also tried:

sage('blade')->compiler()->component('components.row','row');

to no avail - back-end and front-end of the site go down completely.

Thoughts?

What is the sage-lib version in your composer.json? It needs to be ~9.0.1 to work. That’s when the Illuminate dependencies were bumped to 5.6.

Yeah that’s not going to work because the custom directive is just an @include. You would need to create an @endrow directive to mimic the component, which isn’t ideal so I crossed it out in my original reply.

You can set the second parameter, but it isn’t necessary. When I was playing around with it, I was able to confirm that both one and two parameters work. My solution in #3 is correct. I believe it must be an issue of not have the correct sage-lib dependency.

Also, when working with Blade templates, sometimes you need to trigger a compile. Most of the time you can do this by just saving the template again or you can use @alwaysblank’s handy blade-generate WP-CLI package.

Also, just want to clarify: the components.row in the Blade component alias registration corresponds to: resources/views/components/row.blade.php