syse-i / django-component-tags

Create advanced HTML components using Django Tags.
MIT License
18 stars 1 forks source link

isolated context in slots? #11

Open nerdoc opened 2 years ago

nerdoc commented 2 years ago

I've got a problem with the context isolation.

    {% for block in block_list %}
      {% card with object=block %}
        {% slot "title" %}
          foo
          {{ object.verbose_name }}
        {% endslot %}
        ...
      {% endcard %}
    {% endfor %}

in the card title, "foo" is displayed, but object.verbose_name not. Could it be that slots themselves have their own isolated contexts?

I also have problems with {% url 'foo-bar' block.pk %} links, as block.pk is empty - same problem.

Any hints?

nerdoc commented 2 years ago

more info: when debugging, outside of the slot object has a value, within the slot, it is undefined. But I can't pass it down to the slot using `{% slot "title" with object=object %}: too many values to unpack (expected 5).

Wouldn't it be good to automatically pass all available context attrs down to all slots of the component?

nerdoc commented 2 years ago

in components.py, line 39 you write:

def __init__(self, *args, **kwargs):
    tag_name, nodelist, options, slots, name = args
    kwargs['isolated_context'] = True  # Make sure slot has the parent context
    super().__init__(tag_name, nodelist, options, slots, **kwargs)

If you set kwargs['isolated_context'] = False- the slot context of the surrounding component is inherited, so it would work (for me). Is that a solution? Did you maybe just accidentally mixed up False/True there?

nerdoc commented 2 years ago

In a quick test I did now this (False) should work:

david-sosa-valdes commented 2 years ago

Now i remember why, something weird was happening with a couple of tests.

Did you run the tests with this changes?

nerdoc commented 2 years ago

no... just a quick check with my own code... I didn't even download you repo yet...

david-sosa-valdes commented 2 years ago

Also i was looking inside README and i did not doc the Test Suite part....my bad.

If you clone the repo you could install deps and and run it with tox: https://pyscaffold.org/en/stable/usage.html

Or manually: python3 manage.py test component_tags

nerdoc commented 2 years ago

Can't run the tests.

django.template.library.InvalidTemplateLibrary: 
Invalid template library specified. ImportError raised when trying to load 'templatetags.test_tags': 
No module named 'templatetags.test_tags'

There is no test_tags string in the whole repo...

david-sosa-valdes commented 2 years ago

Can't run the tests.

django.template.library.InvalidTemplateLibrary: 
Invalid template library specified. ImportError raised when trying to load 'templatetags.test_tags': 
No module named 'templatetags.test_tags'

There is no test_tags string in the whole repo...

Ok, im on it

david-sosa-valdes commented 2 years ago

The tests passed correctly now, i update the README and fix the problem.

@nerdoc are you using the default tailwind Card component?...if the answer is no, could you please show us your definition of that component?

Reference:

nerdoc commented 2 years ago

No, it's my own one. "Card" is even not true, I just simplified it. Here is the current code (again a bit simplified):

{# block_list_htmx.html #}
{% for block in block_list %}
  {% sortablecard title=block.verbose_name with object=block %}

    {% slot "actions" %}

      <div class="btn-group">
        {% include 'homepage/block_toggle_htmx.html' %}
        <button ... >{% translate 'Edit' %}</button>
        <button ...>{% translate 'Delete' %}</button>
      </div>

    {% endslot %}

  {% endsortablecard %}
{% endfor %}

The component backend:

from component_tags import template

register = template.Library()

@register.tag
class SortableCard(template.Component):
    title = template.Attribute(required=True, as_context=True)

    class Meta:
        template_name = "homepage/tags/sortable_card.html"

sortable_card.html:

<div id="sortablecard-{{ object.pk }}" class="card mt-3">
  <input type='hidden' name='sortable-item' value='{{ object.pk }}'/>
  <div class="card-header d-flex justify-content-between align-items-center">
    <h5><i class="bi bi-arrows-move handle"></i> {{ title }}</h5>
    <div class="d-flex">
      {{ slot_actions }}
    </div>
  </div>
  {% if slot_body %}
    <div class="card-body">
      {{ slot_body }}
    </div>
  {% endif %}
</div>
david-sosa-valdes commented 2 years ago

It seems that adding extra context is not properly working, we will make sure to test it again to fix it...

In the meantime did you try to specify the attribute value as context, something like:

from component_tags import template

register = template.Library()

@register.tag
class SortableCard(template.Component):
    title = template.Attribute(required=True, as_context=True)
    obj = template.Attribute(as_context=True)

    class Meta:
        template_name = "homepage/tags/sortable_card.html"

And render it as follows:

{% sortablecard title=block.verbose_name obj=block %}
nerdoc commented 1 year ago

Yes, I tried. bu as context, you can't e.g. provide translated content. (You have to translate it in the view, this works)