Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating ready-to-use shared elements using twig

I'm working on a project that has a lot of shared elements, e.g. footer, header, navigation, etc. I have few layouts which I extend in my views. For now, I'm loading the shared elements inside my view, but I need to provide all the assets (Dependencies) needed for each shared element inside the view I'm loading it into. I'd like to be able to skip that step and load the element which would be actually prepared for usage right away (so I wouldn't need to remember all the dependent javascript and css files, as some of them might have a few).

I was thinking about specifying all the assets needed for shared element inside the element's view, so when I include the element I need, it would load the assets "automatically", without me specifying all of them inside my view. So my question is if it's possible to do this or what's the right way to accomplish this?

Hope it will be explained even better using code:

Structure:

views/
- /layout/
    -> layout.twig
- /homepage/
    -> index.twig
- /shared/
    -> navigation.twig

Layout:

<!-- HTML headers, etc. -->
{% block assets %}
    <link rel="stylesheet" href="xxx" />
{% endblock %}

{% block content %}

{% endblock %}

View:

{% extends "layout/layout.twig" %}
{% block assets %}
    {{ parent() }}
    <!-- some assets for view -->    
{% endblock %}
{% block content %}
    {% include "shared/navigation.twig" %}
    <!-- content -->
{% endblock %}

Shared element navigation.twig:

// It's not working, of course - just for better explanation of what I'm trying to approach
{% block assets %}
    {{ parent() }}
    <!-- assets needed for shared element -->
{% endblock %}
<!-- rest of shared element -->

I guess, normally, you don't load all the assets in the views as some shared elements may have a lot of them, especially in bigger project. Also, I think it's nice to point out, that I don't really want to render the styles for them inside the <body>, so creating <links> inside the view is not a way to go for me. This is meant to work like a shared element from which you can control where your assets will be loaded and what assets will be loaded without even knowing what assets are required for each shared element. Thank you in advance.

like image 776
Dawid Zbiński Avatar asked Nov 07 '22 13:11

Dawid Zbiński


1 Answers

From the documentation on use:

Horizontal reuse ... is mainly used by projects that need to make template blocks reusable without using inheritance.

use incorporates an external file into the current file, with the option to rename blocks to locally unique values. These locally unique values may then be injected - using block - into the inheritance hierarchy.

Example. Start with the base "parent":

<head>
  {% block assets %}
  <link rel='stylesheet' href='layout.css' />
  {% endblock %}
</head>
<body>
  <div id='layout' class='content'>
    {% block content %}
    {% endblock %}
  </div>
</body>

Define the menu, the "component" we will "reuse" later:

{% block assets %}
  <link rel='stylesheet' href='menu.css' />
{% endblock %}
{% block content %}
  <div id='menu' class='content'></div>
{% endblock %}

Now, bring those two together. Notice how we are extends-ing the base, but then use-ing the component and reusing its blocks with block:

{% extends "layout.twig" %}

{% use "menu.twig" with assets as menu_assets, content as menu_content %}

{% block assets %}
  {{ parent() }}
  <link rel='stylesheet' href='view.css' />
  {{ block('menu_assets') }}
{% endblock %}

{% block content %}
  <div class='menu'>
    {{ block('menu_content') }}
  </div>
  <div id='view' class='content'></div>
{% endblock %}

Yields:

<head>
  <link rel='stylesheet' href='layout.css' />
  <link rel='stylesheet' href='view.css' />
  <link rel='stylesheet' href='menu.css' />
</head>
<body>
  <div id='layout' class='content'>
    <div class='menu'>
      <div id='menu' class='content'>
      </div>
    </div>
    <div id='view' class='content'></div>
  </div>
</body>

It's not quite the magic of "define blocks with the same name and they all get combined", but it's pretty close. Your layout doesn't know about menu, and menu doesn't know about layout: but they both agree on blocks named "assets" and "content". The view then stitches those together into the correct inheritance form.

like image 89
bishop Avatar answered Nov 15 '22 05:11

bishop