-
Notifications
You must be signed in to change notification settings - Fork 641
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Passing data to includes #539
Comments
Reopening to track this feature request. Some discussion in #522. I'm not opposed to this feature, but since it's not in Jinja2 I'm also uninterested in implementing it or reviewing or merging the implementation. Anyone interested in the feature is welcome to submit a pull request, it may be that one of the other maintainers is interested in reviewing and merging it. |
it would be great to be able to pass blocks into includes to make it easier to create one-off versions |
I don't know what "pass blocks into includes" means, concretely speaking. |
Here's the use case I'm concerned about: I have an include for a site banner. On a page I would like to define a block with the links to be used, then be able to pass that block to the banner include to replace the default markup for that section. |
The "nunjucks way" to approach that use case is to make the banner-display a macro, which takes arguments (perhaps with default values) for the various links that may need to change. I still don't understand how your proposed solution would work. If there are multiple links that need to be changed, wouldn't you need multiple blocks? Why are blocks better here than simple variables or macro arguments? |
In that particular case all the links are side by side. The nunjucks way is good. |
+1 |
Following up on this: I was able to do much of what I needed to do when I realized that variables are globally scoped (but you don't have to worry about leaking to sibling pages). For more complicated situations, it's good to know that includes have their own inheritance tree. If that's not enough, macros come to the rescue. In my opinion it's not a matter of being able to do something with nunjucks, it's a matter of how intuitive it will be to do. @keelii I'd be interested in hearing your use case to test this hypothesis. |
To be clear, the original feature request here is to pass simple extra context data to The ticket has since been clouded with discussion of some not-entirely-clear-to-me additional hypothetical feature involving "passing blocks into includes." If that's still something you want to pursue or discuss, please open a new separate issue for it, as IMO it's quite a different thing from the feature proposed in this issue, and I don't think anything will be gained by confusing them in a single issue. Thanks! |
@carljm right, that is not what I'm trying to do. That's why I posted my follow up. I should have been more clear. |
@sbussard
and i convert this
|
@keelii Why not just write |
@keelii You might be able to use a macro: {% macro component(bar, orz) %}
// template here. this can also be included and then called. args can also be objects
{% endmacro %}
{% for i in range(0, 1) %}
{{ component(1, '2') }}
{% endfor %} |
@carljm The component tag contains a sub-template, but i want pass some variable to this sub-template. these variable works for component private scope, and share some parent's variables. just like The JavaScript closure. I've tried to use nunjucks extension, but it is hard to understand for me. checkout this: https://github.com/keelii/wo/blob/master/boilerplate/app/views/index.html#L26 @devoidfury macro content can not be maintained in a separate file. |
@keelii here's an example // nunjucks-component.js
// I'm using gulp-nunjucks-render, so I have to grab the nunjucks object:
import {nunjucks as nunjucks} from 'gulp-nunjucks-render';
/**
* {% component 'name', {title: 'Example', subtitle: 'An example component'} %}
*/
var ComponentTag = function() {
this.tags = ['component'];
this.parse = function(parser, nodes, lexer) {
var token = parser.nextToken();
var args = parser.parseSignature(null, true);
parser.advanceAfterBlockEnd(token.value);
return new nodes.CallExtension(this, 'run', args);
};
this.run = function(context, name, data) {
// My components are organized in this manner: components/componentName/componentName.html, but this is easily changed.
// Note that the component is only given the data object, and the context is not exposed.
return nunjucks.render('components/' + name + '/' + name + '.html', data);
};
};
module.exports = new ComponentTag(); // Enabling the component tag extension
import nunjucksComponent from 'nunjucks-component';
nunjucks.addExtension('component', nunjucksComponent); I hope that helps! |
@elcontraption Awesome! it looks sexy, I will try. |
Not the best solution, but works for me. Input:
_partials/section-header.html
Output:
|
Any news on this one? Handlebars already allows passing custom data to the included template and it's incredibly useful. |
As the new maintainer I'm slowly making my way through old tickets. This seems like something worth adding. |
Thank you @fdintino! Right now we can use macros but jinja2 gives parent context to partials, which would be wonderful. You're the best! |
@dreki You can import macros with context too. |
In theory not a bad add, but I feel like this feature can be accomplished with macros and/or custom components. |
@misscs In some cases that is true, but there have been arguments put forward elsewhere about the utility of this feature and how it would differ from a macro implementation. There is actually a two-year-old pull request for this feature on jinja2, pallets/jinja#512. That PR hasn't been closed, but it has this bizarre response from the repo maintainer:
It is the rare case where the django templating engine is actually more featured than jinja2. |
Hm, that seems to be strange argument. We're using solely macros, and they all stored as Components, each macro in standalone file: example. Doesn't seem to be much different from storing standalone templates which later will be included with specific context.
Well, I actually share his opinion. We've used includes in the beginning too, but after it always started to rise debates "should this component be include or macro", we've ended up using only macros. And after that usefulness of includes became completely unclear for me. Just my two cents. |
Yeah, that is a strange point. It would be nice if there was something like an ES6 "default export" for macros, though I suppose a naming convention can address that. I can definitely see the advantage to having the context variables all listed explicitly in a file. Maybe I'm just biased due to familiarity—we're in the middle of transitioning our templates from django to jinja. |
Well, in Jinja all macros are like "exported by default", so you can import all ( So, in some sense, explicit exporting isn't necessary.
To be honest, didn't get that part :) Hard to gasp without example |
Oh, that was an argument in favor of macros over includes. |
Ah, now I get. Actually, it never occurred to me that includes with context also have this issue when you really don't know which context they can accept... Good point. |
I'm with @ArmorDarks (and creator of Jinja): macros cover most all use cases. I believe what folks are trying to accomplish can be done with what the language already provides. |
An alternative to @neysimoes solution with macros. I have used his solution a lot but over time found macros to be better. With macros, you avoid globals e.g. "sectionHeader.Title", and can easily implement default values. In this example we set a custom color in the first instance but easily revert to the default value in the second (which is not possible if you use include; you would need to re-set color before the second instance). Both of those benefits can be big time and error-savers if you have complex templates with a lot of variables. Input:
_partials/section-header.html
Output:
|
I've found a simple way to achieve this. Wrote a method to merge two JSONs. Then we pass this merged json to our templates.
then inside your template html files, use like:
Then access inside the partial access by: |
- remove `with variable` declarations. You cannot use them in nunjucks. We can replace by macros, but for the sake of this first refactor we’ll pass all context to includes - More: mozilla/nunjucks#539 (comment) - updated include paths - yup just this 🙌
- remove `with variable` declarations. You cannot use them in nunjucks. We can replace by macros, but for the sake of this first refactor we’ll pass all context to includes - More: mozilla/nunjucks#539 (comment) - updated include paths - yup just this 🙌
- remove `with variable` declarations. You cannot use them in nunjucks. We can replace by macros, but for the sake of this first refactor we’ll pass all context to includes - More: mozilla/nunjucks#539 (comment) - updated include paths - yup just this 🙌
- remove `with variable` declarations. You cannot use them in nunjucks. We can replace by macros, but for the sake of this first refactor we’ll pass all context to includes - More: mozilla/nunjucks#539 (comment) - updated include paths - yup just this 🙌
- remove `with variable` declarations. You cannot use them in nunjucks. We can replace by macros, but for the sake of this first refactor we’ll pass all context to includes - More: mozilla/nunjucks#539 (comment) - updated include paths - yup just this 🙌
I've picked nunjucks randomly to change from my usual template engine. It seems incredible to me that nunjucks doesn't allow this simple and intuitive behavior. I'll use the following syntax: {% set barChartData = ...%}
{% include 'reveal/barchart.njk' %}
{% set barChartData = ... %}
{% include 'reveal/barchart.njk' %} But that's a bit sad tbh. Edit: |
I'd like this feature to use WITH macros. Something like: {% macro HandleOn(on = {}) %}
{% for event in required %}
{{ throwError(event + " is required") if not in(event, on) }}
{% endfor %}
{% for key, value in on %}
on{{ key }}="{{ value }}"
{% endfor %}
{% endmacro %}
{% macro DocumentationPiece() %}
Handles `on` events. The following events are required: {{ requires | join(", ") }}
{% endmacro %} and on the other template I use it, I could say: {{ from "handles_on.njk" import HandleOn, DocumentationPiece with { requires: ["click", "hover"] } }} And I could use (that's a simplified version of a code I'm really using, |
It works for me. test.njk {{ tagName }} main.njk {% set tagName = someVariable %}
{% include 'test.njk' %} someVariable is just variable. it can be represented {{someVariable}} in njk. |
The solution proposed by @dbwodlf3 worked for me, but I would still like to have a way of passing arguments/having parameters in my includes. |
I've been using a similar approach to @dbwodlf3 for those cases where I have an include rather than a macro. It makes me a little wary as it relies on the current context / changing something on the current context - which presumably for safety you might set in the line proceeding the include. I like the 'neatness' / readability of directly passing the data to use, just like you can with a macro. Includes can actually be really powerful when used with macros - one nice thing with them (though I love macros) is that the included file doesn't have to have any Nunjucks syntax in it. It can be pure text, html, whatever. If it were a macro, that content would need to be wrapped in the macro block (unless I'm wrong). The UK Government uses this to good effect for their macros. The actual html is stored as html in a file, and then the macro includes that. This enables other things to make use of the html / compose with it (tests, rendering of examples for the deisgn system), without the macro block syntax getting in the way. I've also used this as a way of mass-importing macros as a workaround for no default export or easy macro file management. I can all the source code for them in separate files, and then have a single example: {% macro govukButton(params) %}
{% include "govuk/components/button/template.njk" %}
{% endmacro %}
{% macro govukCharacterCount(params) %}
{% include "govuk/components/character-count/template.njk" %}
{% endmacro %}
{% macro govukCheckboxes(params) %}
{% include "govuk/components/checkboxes/template.njk" %}
{% endmacro %}
{% macro govukDateInput(params) %}
{% include "govuk/components/date-input/template.njk" %}
{% endmacro %} |
Just as a heads up we did a POC for this a while back in https://github.com/Financial-Times/nunjucks-loader. |
Twig supports sending data to includes, like so:
This is really useful in many cases, like re-using a block in different contexts, with different behaviour / data. Have anyone looked into adding support for this?
The text was updated successfully, but these errors were encountered: