Skip to content
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

Add support for the ?= operator #3697

Open
alinnert opened this issue May 2, 2022 · 2 comments
Open

Add support for the ?= operator #3697

alinnert opened this issue May 2, 2022 · 2 comments

Comments

@alinnert
Copy link

alinnert commented May 2, 2022

I have a lot of templates that are intended to be used with {% include ... with { } %} or {% embed ... with { } %}. Conceptually, I like this a lot. It feels a lot like components in frontend frameworks or function calls.

But there are two things that bother me with how this currently works:

  1. It's quite difficult to find out which variables are expected by a template. Currently I'd need to look through the entire template to find, which variables are required, which are optional, and which aren't used at all.

  2. It's a little too complex to set a default value for an argument. Since the default filter isn't suited for this use-case I need to set default values like this:

{% set someParam = someParam is defined ? someParam : 'default value' %}

I had the idea to write my own param filter or function but that doesn't work either because the template crashes if a not defined variable is used with a custom function or filter (I guess this is caused by the strict_variables option, right?). I looked into how default deals with this. But its implementation looks quite advanced.

I think both points mentioned above could be solved at one go. But there are a lot of ways to tackle this. First of all: Is there any interest in solving these issues? I think they are tightly coupled to how both include and embed work, so I think this could help a lot of people.

One idea I have is the following:

{% params num = 1, str = 'hello', flag = false %}

In this case num should default to 1 only if it's missing from (or basically if it's not defined):

{% include ... with { ...no num here... } %}

My params* tag would basically be a shortcut for multiple set tags like the one above. This means it not only works in included or embedded templates but basically everywhere.

Now for point one (i.e. for documentation purposes) I'd also like the following to be valid:

{% params foo %}

On one hand this sends a signal to the user that there's a (potentially non-optional) variable foo required to render this template. But this tag like shown above would actually be a noop. Unless this defaults a not defined variable to null.

*) Maybe {% define ... %} is an even better name since it might work everywhere and it could set undefined variables to null.

After reading through other issues I think you wouldn't want to implement the possibility to mark a variable as required and throw if it's not defined, right? Otherwise, this is also something that could be covered by this tag.

Here's a more advanced and simplified real-live example (using define instead of params):

{# menu-item.html #}

{% define label = '', icon, link, variant = 'default' %}

{% set labelHtml %}
  <div class="variant-{{ variant }}">
    {% if icon is not null %}
      <img src="{{ icon }}">
    {% endif %}
    <span>{{ label }}</span>
  </div>
{% endset %}

{% if link is not null %}
  <a href="{{ link }}">
    {{ labelHtml }}
  </a>
{% else %}
  {{ labelHtml }}
{% endif %}

The define tag above would be equivalent to:

{% set label = label is defined ? label : '' %}
{% set icon = icon is defined ? icon : null %}
{% set link = link is defined ? link : null %}
{% set variant = variant is defined ? variant : 'default' %}

But more realistically icon and link would be missing and the template would check {% if icon is defined %}. Imo that's bad because of point 1 above. And it's not as easy to read what the actual default values are.

@stof
Copy link
Member

stof commented May 2, 2022

to set default values, you can probably use the ?? operator (unless you want to accept null as a non-default value)

@alinnert
Copy link
Author

alinnert commented May 2, 2022

Okay, that's a bit better (Although, ?= would be even better). Being not able to accept null might be an issue if "not defined" and null makes a difference. But I'm having trouble finding a use-case.

If we follow that approach, the following would be a good alternative:

{% set label ?= '' %}
{% set icon ?= null %}
{% set link ?= null %}
{% set variant ?= 'default' %}

I see you can combine multiple set into one, but I don't like this at all:

{% set label, icon, link, variant ?= '', null, null, 'default' %}

The more variables you define the harder it gets to read. If the following was possible it would be a good alternative to the entire proposed define/params tag:

{% set label ?= '', icon ?= null, link ?= null, variant ?= 'default' %}

The only downside is that you have to assign null as a default value explicitly. But I'd be ok with that.

@fabpot fabpot changed the title New tag to define "(sub)template arguments" or multiple undefined variables in general Add support for the ?= operator Oct 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

3 participants