Roots Discourse

How do I pass different data to multiple instances of the same partial on the same page with View Composers?

I’ve been struggling to get to grips with Sage 10 this week, having only minimal PHP knowledge beforehand which I assume is part of what’s tripping me up.

I’m stumped on how I get a partial (for example, a button) to be used in multiple parts of my page and still be able to define the data for each individual instance. Here is my problem:

// page_home.blade.php

@extends('layouts.app')
@section('content')
  @while(have_posts()) @php(the_post())
    @include('partials.common.page_header')
  @endwhile
@endsection

// partials/common/page_header.blade.php

<section class="container-fluid p-0 page-header">
  <div class="container">
    <h1 class="head-title">{{ $page_header_heading }}</h1>
    <p>{{ $page_header_subtext }}</p>
    @include('partials.common.button')
  </div>
</section>

// partials/common/button.blade.php

@if ($button_content)
    <a role="button" class="btn btn-primary" id="{{ $button_id }}" href="{{ $button_href }}">{{ $button_content }}</a>
@endif

// Page_home.php (View Composer)

<?php
namespace App\View\Composers;
use Roots\Acorn\View\Composer;
class Page_home extends Composer
{
    protected static $views = ['page_home'];
    public function with()
    {
        return [
            'page_header_heading' => 'My heading',
            'page_header_subtext' => "Text here",

            'button_content' => 'Get In Touch',
            'button_href' => 'mailto:email@email.com',
            'button_id' => 'headButtonCta',
        ];
    }
}

Now let’s say I wanted to add a second instance of the button partial either in the page header or even elsewhere on the main page template. They will all get the same values as eachother. How do I give them all unique values?

Look into components, for reusable elements that you need to pass parameters. You can use something like: wp acorn make:component CtaButton , then you’ll have a component class much like a composer, but you just need to add your parameters to the constructor, i.e.

/// app/View/Components/CtaButton.php
<?php

namespace App\View\Components;

use Roots\Acorn\View\Component;

class CtaButton extends Component
{


    public $buttonContent;

    public $buttonHref;

    /**
     * Create a new component instance.
     *
     * @return void
     */
    public function __construct($buttonContent, $buttonHref = null)
    {

        $this->buttonContent = $buttonContent;
        $this->buttonHref = $buttonHref;
    }

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\View\View|string
     */
    public function render()
    {
        return $this->view('components.cta-button');
    }

}

Then on the tamplate for the component, something like:
// components/cta-button.blade.php


@if ($buttonContent)
    <a href="{{ $buttonHref }}"  >{{ $buttonContent }}</a>
@endif

on the template, you can then pass the parameters you have from the composer into the component:

<x-cta-button button-content="some static text" :button-href="$someVarFromViewComposer" >

Note that the attribute names will become camelCase within the class. To pass a variable to the attribute prepend : as in :button-href.
Worth looking into the blade docs on how to use slots in components as well.

3 Likes

Components as mentioned by @foltra are an excellent solution! You can also pass arguments to partials when you include them, like so:

@include('partials.button', [
   'content' => "Get in touch", 
   'href' => 'mailto:email@email.com'
])

The second parameter is parsed as PHP, so it will accept variables, which means you can also do something like this:

// Composer
public function with()
{
  return [
    'button1' => [
      'content' => "Get in Touch",
      'href' => 'mailto:email@email.com',
    ],
    'button2' => [
      'content' => "Read Blog",
      'href' => 'https://site.com/blog',
    ],
  ];
}
@include('partials.button', $button1)
@include('partials.button', $button2)
1 Like

Thanks for the help guys. That’s cleared things up for me.

@include('partials.button', $button1)
@include('partials.button', $button2)

Is there a way i can increment the $button1 part of this in a for loop?

I currently have the following:

@for ($i = 0; $i < 10; $i++)--}} 

    @if ($i == 1)

      @include('partials.accordion.accordion-card', ['card_id' => $i, 'card_expanded' => 'true', 'card_show' => 'show',])

    @else

      @include('partials.accordion.accordion-card', ['card_id' => $i, 'card_expanded' => 'false',])

    @endif 

  @endfor 

This should output 10 instances of my partial, which it does. In order to give the correct values to the correct partials in my view composer, I’d need to assign a key to each (like $card1). The problem is, i don’t know how to increment the number at the end in a way that works. I’ve tried

@include('partials.accordion.accordion-card', ['card_id' => $i, 'card_expanded' => 'false',], $card.$i)

but this just returns blank.