Rendering a component inside another in Nunjucks & Fractal - components

I'm working on a design system and just getting my head around the component way of thinking.
We're using Nunjucks and Fractal.
We have an existing component, an accordion which gets it's data from a JSON object. The props being title and content.
I've built a component, like a table of contents, which displays a list of styled links, using a simple loop, pulling in from a ToC.config.js file.
I need to include that new component within the accordion component, the ToC has a title and an array containing urls and text for each link.
At present I've just copied the HTML from the accordion's view in Fractal, but that's probably not the way to go, but visually it's as the designer requires.
I can also render the accordion correctly if I put all the links, HTML and all in the config, as a string, but that's not the way it should work either.
What I want to do, which is probably the proper way, is pull that accordion in and populate it with my ToC component.
{% render '#my-accordion', 'accordion: items' %} doesn't do what I want and I can't seem to figure out how to achieve what I need to do.
Something like so:
{% render '#my-accordion' %}
// Pass in data from ToC, somehow
{{ title: title }}
{% for item in items %}
{{ item.text etc }}
{% endfor %}
Then I would have my accordion component, where its title, links and HTML etc are those from my ToC component. Sorry for the rough pseudo above, it's more an example of what I want to do. I can't copy code to an external resource.
using render doesn't appear to be the way to go, unless I'm missing something? I can't pass the list through as a string as it has classes and aria for the current page etc and content authors will be building pages with these.
A little nudge in the right direction would be great.

You can add a render-filter that similar to include and macro.
import 'nunjucks.min.js';
var env = new nunjucks.Environment({autoescape: true});
env.addFilter('render', function (template, ctx) {
const html = env.render(template, ctx); // try-catch
return env.filters.safe(html);
});
Usage
// table.njk
<table>
{% for e in rows %}
{% 'row.njk' | render({row: e}) %}
{% endfor %}
</table>
// row.njk
<tr>
{% for c in row.cols %}
<td> {{ c.name }} </td>
{% endfor %}
</tr>

Related

How to get article url in a given category?

I'm trying to make a scroll on products in a given category for articles in shopware 6. I've managed to extend the product-detail html.twig file to add the next and previous on the page. The problem I'm facing is how to generate the URL links in a given category.
{% sw_extends '#storefront/page/product-detail/index.html.twig' %}
{% block base_content %}
« Previous
Next »
{{parent()}}
{% endblock %}
With the twig function seoUrl, you can generate links to other pages.
After the URL you can add query strings for the right pagination, see the example:
{{ seoUrl('frontend.navigation.page', { navigationId: 'ID' }) }}

OctoberCMS Partials sharing variables life cycle

I'm new in October CMS and I try to develop some components and these components have more than one page. I include every page as a partial in the default.htm file with an if condition depends on the type property of the page.
{% set type = __SELF__.property('type') %}
{% if type == 'y' %}
{% partial 'x::yy' %}
{% elseif type == 'x' %}
{% partial 'x::xx' %}
the problem is when I have a collection of items in one page and send id of one of the items to another ajax handler and want to retrieve full info of the item, I can't pass it to next page because of the page cycle in October CMS.for example :
// firstpage
{% set posts = __SELF__.posts %}
{%for post in posts%}
<button data-request="handlerX" data-request-data="id: {{post.id}}">
{%endfor%}
//hanlerX
public function onHanldlerX(){
$post = $this->post = POST::where('id',post("id"))->first();
return redirect()->to('/my-posts/'.$post->slug);
}
//nextpage -> my-posts/$post->slug
// post informations is unavailible
what's the best way for these type of components?
Is It the right way for this?
how can I send variables to view after the OnRun method in components?

Using an ACF gallery with Timber/Twig

I'm using Timber (the WordPress plugin implementation of Twig) and the Advanced Custom Fields plugin gallery field. I have a working gallery under a custom post type, so ACF and Timber are working elswhere in the site, but not for a standard page. When I try to add a gallery to a page, all I end up with is empty markup for the img src tag.
I have this in page.php in the template folder:
$context = Timber::get_context();
$page = new TimberPost();
$context['page'] = $page;
if ($photos = $page->get_field('photos')) {
$context['photos'] = $photos;
}
I have this in default.twig in the templates/page/ folder in the theme (html removed for simplicity):
{% if page.photos %}
{% for p in page.photos %}
<img src="{{ p.sizes.gallery|relative }}" alt="{{ p.alt }}" />
{{ p.caption }}
{% endfor %}
{% endif %}
This results in the page source <img src="" alt="">.
If I use {{ dump(photos) }} inside the for p in page.photos statement, it dumps the array of images I have entered in the Gallery field on the backend. So the image array exists and it being output. The relative extension runs for all post types; removing it makes no difference here.
So why is the p.sizes.gallery|relative function not outputting each image's url and caption?
You append the data to the $context['photos'] so I believe you should change your code to check for if photos and iterate as for p in photos

Twig : Access to variable from outer scope in a form widget customization

I'm trying to customize a specific widget, like in the documentation : http://symfony.com/doc/current/cookbook/form/form_customization.html#how-to-customize-an-individual-field
The problem is that in this custom block, I need to use a variable from my actual template. I thought "blocks have access to variables from outer scopes", but apparently not in this case :
{% extends "CDASvBundle::layout.html.twig" %}
{% block _contact_activity1_widget %}
<select name="contact[activity1]">
{% for key, child_contact_categories in contact_categories_tab %}
<option value="{{key}}">{{child_contact_categories}}</option>
{% endfor %}
</select>
It's saying that contact_categories_tab is undefined, but outside of this block (in the normal content block for example), it works !
I tried something like :
{% use 'form_div_layout.html.twig' with contact_categories_tab as contact_categories_tab %}
But that doesn't either.. Though I'm not sure I understand if I have to use use and how !
I see one other solution that I haven't tried yet : put this customization in another template. But I don't really want to do that (few lines in a new template), there should be a way to do that in only ONE template ?!
Finally found the answer in a previous post :
Each symfony form type extents AbstractType class.
AbstactType class has method:
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->set('img_src', '120x100.jpg');
$view->set('my_variable', $foo);
}
You can create this method on your form type and next in your twig:
{{ asset(img_src) }}
Source : How to get entity or pass variable to Symfony2 twig form widget?

Grav template -- Twig not listing child pages

I have made a few pages in grav with a taxonomy like this.
- Home (category type)
- programming (category type)
- stuff (category type)
- stuff1 (page type)
- stuff2 (page type)
- stuff3 (page type)
I've also made a template type called "category" which should hopefully grab all the links to stuff1/2/3 and place them on the "stuff" page as links. My code looks a bit like this:
{% block body %}
{% block content %}
<ul>
{% for p in self.children %}
<li>{{ p.title }}</li>
{% endfor %}
</ul>
{% endblock %}
{% endblock %}
The end goal is to just get a simple listing of links for children to the category something like:
<ul>
<li>stuff1</li>
<li>stuff2</li>
<li>stuff3</li>
</ul>
I've tried using page.children, self.children, and a few other things but nothing seems to be getting this to work the way that I want it to.
Any help would be appreciated.
I'm afraid I do not quite understand what you mean by 'category type' and 'page type...
The docs on Page Collections might be quite helpful.
Example:
If you want a page with template 'category.html.twig' which shows a list of urls to all pages containing a certain category (or tag), you can do the following:
create a page 'category.md' defining a collection of categories in frontmatter:
content:
items:
'#taxonomy.category': mycategory
Create a template 'category.html.twig' containing:
<ul>
{% for p in page.collection() %}
<li>{{p.title}}</li>
{% endfor %}
</ul>
The resulting page will look like:
<ul>
<li>Home</li>
<li>Body & Hero Classes</li>
</ul>

Resources