emilstenstrom / django-components Goto Github PK
View Code? Open in Web Editor NEWCreate simple reusable template components in Django.
License: MIT License
Create simple reusable template components in Django.
License: MIT License
If you write a component tag like: {% component_block 'my_list' %}
, you currently get a NotRegistered
Error for the component 'my_list' (not my_list unquoted). I believe the correct (and intended) behavior is that the template tag should strip both single quotes and double quotes before doing the lookup.
The line in do_component
is
component_name = component_name.strip('"')
which I think should be:
component_name = component_name.strip('"\'')
There is a similar library for rails -> https://viewcomponent.org/ (https://github.com/github/view_component) Apparently that library is 10x faster in rendering than partials, which is the equivalent of django's include.
Do you have any idea what the performance characteristics are for this library?
I am thinking of using this with something like https://github.com/AccordBox/python-webpack-boilerplate
Hi, I am trying to configure the components.py and I have tried everything in the Media class, but I can't get the css and js to load.
My app path is like this: apps/app_name/components.py
I have tried many combinations but none have worked.
Hi, I was wondering whether a component's CSS and JavaScript are scoped just to that component's markup or if they get applied globally.
Thanks!
You need to add 'django_components.middleware.ComponentDependencyMiddleware' to your MIDDLEWARE section too, that's the thing that makes smarter choices of where to import CSS and JS.
Originally posted by @EmilStenstrom in #70 (comment)
Making two extra HTTP requests for each component on the page makes sense with few components. It will even be decently efficient when using HTTP/2 or later. But as the number of components grow it will stop to make sense. Therefor we should add some sort of bundling of all CSS-files used by components into one file, and all JS-files into another. Using any number of components should just require one CSS file and one JS file.
Upsides?
Downsides?
Things to consider:
Sorry for putting both of these in one issue, but they're both so minor it seemed excessive to open separate issues:
In slotted components, trying to include a variable that isn't available in the context raises an exception. The reason seems to be that the render path for slotted components uses nodelist.render()
, which automatically binds the template, rather than template.render()
, which does not. The problem goes away if the template is manually bound.
Using {% component_block variable="XYZ" %}, it is currently an error if the component's context
function inserts additional variables into the context (e.g., default parameters). The issue is that if there are any arguments specified in the tag, ComponentNode.render()
runs the entire context through the dictcomp that resolves FilterExpression
s to generate extra_context
. This can be fixed by passing anything that doesn't have a resolve
method through the dictcomp unchanged.
I put together a PR to demonstrate the issues and fix them--will send shortly.
Hi,
Thanks for the useful library! I've recently upgraded to 0.11 and have noticed a lot of print output in my console from the djagno server when viewing pages that have components on them, as shown below - reverting to 0.10 appears to fix the issue.
------------------------------------ Before ------------------------------------
<django.template.defaulttags.LoadNode object at 0x7f2af5438640>
<TextNode: '\n\n<div>\n <div class="rel'>
<Variable Node: columns>
<TextNode: '">\n '>
<ForNode: for object in object_list, tail_len: 3>
<TextNode: '\n </div>\n</div>\n '>
<IfNode>
<TextNode: '\n <div class="w-full m'>
<Component Node: <dp.apps.dp_core.components.components.Pagination object at 0x7f2af543fa60>. Contents: None>
<TextNode: '\n </div>\n\n '>
<TextNode: '\n</div>\n'>
------------------------------------ After -------------------------------------
<django.template.defaulttags.LoadNode object at 0x7f2af5438640>
<TextNode: '\n\n<div>\n <div class="rel'>
<Variable Node: columns>
<TextNode: '">\n '>
<ForNode: for object in object_list, tail_len: 3>
<TextNode: '\n </div>\n</div>\n '>
<IfNode>
<TextNode: '\n <div class="w-full m'>
<Component Node: <dp.apps.dp_core.components.components.Pagination object at 0x7f2af543fa60>. Contents: None>
<TextNode: '\n </div>\n\n '>
<TextNode: '\n</div>\n'>
Does django-components have a way to access context or do you have to pass in "request" manually?
Django template tag decorators have a "takes_context" argument that does this, so I was wondering if this is something that could be supported.
I would love to see these 3 working together!
I haven't looked too much here but I guess it's possible without much effort.
Thanks for this app.
It seems to me that {% block %}
tags should be executed first, and only after blocks are filled should components parse and fill their slots. This would enable use-cases as:
{% block content %}
{% component_block 'calendar' date="2021-01-01" %}
{% slot 'header' %}Calendar for January{% endslot %}
{% endcomponent %}
{% endblock %}
As well as:
{% component_block 'calendar' date="2021-01-01" %}
{% slot 'header' %}{% block content %}{% endblock %}{% endslot %}
{% endcomponent %}
Currently only the first example works, and not the second one, because slots gets executed before blocks.
I'm not sure if there's an easy way to solve this, but I think we should examine if there is. If it's not possible to solve, let's at least document the shortcoming to solve people some trouble.
Hi! In my template index.html, i tried to call my component named "login" and it's wrong with that error.
I want to get a tutorial containing configuration in a whole django folders. Thanks for your answer in advance!
In the README:
"We create a Component by inheriting from the Component class and specifying the context method. We also register the global component registry so that we easily can render it anywhere in our templates."
However there is no documentation on how the components are discovered: for example templatetags in Django are automatically loaded for all registered app, or explicitly added in the TEMPLATES config. There doesn't appear to be a similar process for component files: adding a component.py file under an app doesn't work, nor does there appear to be a way to add "global" components in settings. Django admin uses a similar pattern.
So for example I have this component.py file under an app:
class Button(component.Component):
... #
component.registry.register(name="button", component=Button)
This module is not autodiscovered (using for example autodiscover_modules) so it is not registered. Calling this:
{% component name="button" %}
Raises a NotRegistered error.
Problem
It seems that on django 3.2 (I haven't tested other versions) django development server is not reloaded when component's python file is modified.
On django 4.1 hot reloading works correctly.
Testid with django-components==0.22
Steps to reproduce:
sampleproject/requirements.txt
: freeze django to version 3.2 django==3.2
pip install -r requirements.txt
python3 manage.py migrate && python3 manage.py runserver
sampleproject/components/calendar/calendar.py
(eg. add raise Exception('hello')
inside method get_context_data
Suppose I have a component with a slot:
<div>
{% slot header %}some default content...{% endslot %}
</div>
There doesn't appear to be a way to do something like {{ block.super }} i.e.
{% component_block "my-component" %}
{% slot header %}
some new content
{{ slot.super }}
{% endslot %}
In the default example in the README this Media definition is used:
class Media:
css = '[your app]/components/calendar/calendar.css'
js = '[your app]/components/calendar/calendar.js'
I would like to simplify this to this:
class Media:
css = 'calendar/calendar.css'
js = 'calendar/calendar.js'
... so that it matches the name template_name paths. CSS and JS should still be loaded from the same directory.
Hey,
For now the signature of the "get_context_data" method is the following:
def get_context_data(self):
return {}
It could be nice to change signature of Component.get_context_data to add *args and **kwargs like this :
def get_context_data(self, *args, **kwargs):
return {}
What do you think about it ?
Aymeric,
I found https://torchbox.github.io/django-pattern-library/ which is a way to show the various components in a pattern library way.
Has anyone tried to use django-components
within the pattern-library?
In the example:
{% component_block %}
{% slot "body" %}Today's date is <span>{{ date }}</span>{% endslot %}
{% endcomponent_block %}
shouldn't this be component_block "calendar"
?
Adding an issue here to track this, as this is something I think is something we really need. Ping @rbeard0330.
So with Django admin I can do this:
@admin.register(MyModel):
class MyModelAdmin(admin.ModelAdmin):
....
It would be nice to have similar functionality for django-components:
@component.registry.register("button")
class Button(component.Component):
...
I'm trying to use a conditional component based on the parent parameters, I'm calling the component not by its name but with a variable containing its name, which is very helpful in many cases.
The problem is that your "component" tag is treating the component name parameter as a string, so when I use a variable name like this:
{% component_block variable_name %}
I get an error saying:
django.template.exceptions.TemplateSyntaxError: Component name 'variable_name' should be in quotes
I tried to make it work by adding some filter ""|add:variable_name
but it didn't work, this trick worked for me with the include tag of Django.
Thanks
The "Block" component of django doesn't throw error when the block is not called from the inheriting template, many times some slots might not be needed when component called, but if not mentioned will throw error, and that implies declaring it empty.
Is there a way to pass complex arguments to component?
Here's my component permission_button.html
{% if permission %}
<a class="btn btn-primary" href="{{ url }}">{{ caption }}</a>
{% endif %}
This one does not work:
{% component 'permission_button' perms.locations.delete_address url 'locations:delete_address' object.id trans 'Delete' %}
So I have to do something like this, which is not that great IMO:
{% url 'locations:delete_address' object.id as url %}
{% trans 'Delete' as title %}
{% component 'permission_button' perms.locations.delete_address url title %}
I used django-components in development, working just fine, using the django development server.
Currently I am deploying the web application to my apache2 server, the rest of the app is working fine but when i open a page that should have a component, it raises the following error:
NotRegistered The component "bgShowCard" is not registered /home/Youssef/env/lib/python3.10/site-packages/django_components/component_registry.py, line 28, in get shows.views.home_view /home/Youssef/env//bin/python 3.10.6 ['/home/Youssef/Desktop/SIMSY', '/usr/lib/python310.zip', '/usr/lib/python3.10', '/usr/lib/python3.10/lib-dynload', '/home/Youssef/env/lib/python3.10/site-packages'] Sat, 15 Oct 2022 13:18:14 +0200
It's kinda odd that no one asked about this before but can the plugin be used in a production server like apache2?
In an attempt to make this project less dependent on me I'd like to automate releases to PyPI. I think a good way to do this is to move the PyPI account from my personal to a new one, put the secrets for the new one as GitHub environment variables, and make a GitHub Action that uses them to push new releases to PyPI. That way, everyone with GitHub access to django-components will also be able to make releases.
Hi,
I am opening a new issue as this seems to be different:
I am still trying to make the calendar example work. templates are found, css works, and js file is loaded. But I get following error in the console:
script.js:2 Uncaught ReferenceError: $ is not defined
Search engine results suggest that this happens when jquery is not loaded yet but called.
My guess is the reason is I am using the defer attribute when referencing jquery (cookiecutterdjango does this for all included js files):
<script defer src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
but the
{% component_js_dependencies %}
tag does not add a defer attribute to the script tag it creates. I moved the jquery reference to the bottom of the page, and deleted the defer attribute. Than everything worked.
This might be something for a separate library, or it could be something we include here, but I'm leaving it here as I think it's an exciting way forward for django-components.
I would like to see a way to push component updates from the server to the client. Some idea how this could work:
More about the philosophy behind this approach: https://alistapart.com/article/the-future-of-web-software-is-html-over-websockets/
How Phoenix LiveView does this (interesting to compare to): https://www.youtube.com/watch?v=8xJzHq8ru0M
Hi,
I tried to use this package but i noticed that the folder templatetags is missing because i don't have component_tags.
I use python 3.8.3 and pip 20.1.1 with django 3.0.7
I have to manualy download the missing file to use components.
So I have this component:
class Svg(component.Component):
def context(self, name: str, css_class: str = "", title: str = "", **attrs) -> Dict:
return {"name": name, "css_class": css_class, "title": title, **attrs}
def template(self, context: Dict) -> str:
print(context)
return f"svg/_{context['name']}.svg"
The template name is assigned dynamically depending on the name of the SVG:
{% component "svg" name="download" %}
However the template() method raises a KeyError, as the key "name" is not in the context: it's empty.
What is the order of execution here? Is template() called before context() ? If so, how do I access variables to be able to set the template name dynamically?
Some components might have optional slots, e.g.:
<div class="frontmatter-component">
<div class="title">
{% slot "title" %}Title{% endslot %}
</div>
<div class="subtitle">
{% slot "subtitle" %}Optional subtitle{% endslot %}
</div>
</div>
If implemented as above, the the subtitle div would always be rendered. It could be useful to check whether a slot, here subtitle
is non empty and then modify the template like so:
<div class="frontmatter-component">
<div class="title">
{% slot "title" %}Title{% endslot %}
</div>
{% if slots.subtitle %}
<div class="subtitle">
{% slot "subtitle" %}Optional subtitle{% endslot %}
</div>
{% endif %}
</div>
When rendering, _DJANGO_COMPONENTS_ACTIVE_SLOTS
is available but it cannot be used inside the template (see https://docs.djangoproject.com/en/dev/ref/templates/api/#variables-and-lookups).
Take a look at this for example
{% component_block "calendar" date="2020-06-06" %}
I would like to put a variable instead of "2020-06-06" through my view function. Is that possible and if it is, how? I tried something like date={{var_name}}, but it failed.
I would like to not have to consider coding style at all, and this is the problem that black solves. This feature would mean that we add black as a dev dependency, and add a github action that checks that the code is formatted before passing.
Hi there,
We have a page that initially doesn't render any component, but is able to insert into its DOM some HTML fragments (through htmx or hotwired or stuff like that), which themselves may carry some components.
With current django-components
capabilities, we have two options when calling {% component_js_dependencies %}
:
ComponentDependencyMiddleware
is disabled, JS from all components will be loaded, which is suboptimal{% component mycomponent %}
; that forces us to load JS with the classic <script src="{% static 'path/to/component.js' %}">
My first thought would be to add optional arguments to component_js_dependencies
/component_css_dependencies
, listing components that have a chance to appear on this page. Do you think it's the way to go? If so, I can work on a PR ๐
Firstly thanks for creating this useful library.
I've noticed that {% csrf_token %}
isn't rendered when used inside component template HTML. Other default Django template tags seem to work, so I'm guessing this is because the component HTML doesn't have access to Django's RequestContext
.
A work-around is to just pass down the {% csrf_token %}
inside a slot
from the parent component, however this becomes repetitive. I'm wondering if it's currently possible to give the component access to the necessary context. Cheers!
Example:
{% slot form_footer %}
<div class="flex items-center justify-end">
{% slot form_buttons %}{% endslot %}
</div>
{% endslot %}
I use the component thus:
{% component_block "form" %}
{% slot form_buttons %}
<button>Submit</button>
{% endslot %}
{% endcomponent_block %}
The content of the form_buttons is not overridden, i.e. it's empty. Only the outer content of form_footer is rendered:
<div class="flex items-center justify-end">
</div>
since all the components JS are loaded via {% component_js_dependencies %}
we need to make sure that the element selected in the js scripts actually exist in the page, esp if conditional loading is not used.
so instead of
/* In a file called [your app]/components/calendar/script.js */
(function(){
document.querySelector(".calendar-component").onclick = function(){ alert("Clicked calendar!"); };
})()
it should be
/* In a file called [your app]/components/calendar/script.js */
(function(){
if (document.querySelector(".calendar-component")) {
document.querySelector(".calendar-component").onclick = function(){ alert("Clicked calendar!"); };
}
})()
Hi,
Hitting some issues running 0.13 - our CI tests generate the following error - which recurses into a long set of deepcopy
operations, failing eventually within the pickle failure
at the bottom. I haven't dug into the code but think there may perhaps be a bug in the duplicate_node
that is copying additional python objects that it shouldn't be.
File "/home/runner/work/datapane-hosted/datapane-hosted/dp-server/.venv/lib/python3.9/site-packages/django_components/component.py", line 146, in duplicate_node
setattr(clone, nodelist_name, type(nodelist)(nodelist_contents))
AttributeError: can't set attribute
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/runner/work/datapane-hosted/datapane-hosted/dp-server/.venv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/home/runner/work/datapane-hosted/datapane-hosted/dp-server/.venv/lib/python3.9/site-packages/django/core/handlers/base.py", line 204, in _get_response
response = response.render()
...
File "/home/runner/work/datapane-hosted/datapane-hosted/dp-server/.venv/lib/python3.9/site-packages/django_components/component.py", line 151, in duplicate_node
return deepcopy(source_node)
File "/opt/hostedtoolcache/Python/3.9.5/x64/lib/python3.9/copy.py", line 172, in deepcopy
y = _reconstruct(x, memo, *rv)
File "/opt/hostedtoolcache/Python/3.9.5/x64/lib/python3.9/copy.py", line 270, in _reconstruct
state = deepcopy(state, memo)
File "/opt/hostedtoolcache/Python/3.9.5/x64/lib/python3.9/copy.py", line 146, in deepcopy
y = copier(x, memo)
File "/opt/hostedtoolcache/Python/3.9.5/x64/lib/python3.9/copy.py", line 230, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
...
File "/opt/hostedtoolcache/Python/3.9.5/x64/lib/python3.9/copy.py", line 230, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/opt/hostedtoolcache/Python/3.9.5/x64/lib/python3.9/copy.py", line 161, in deepcopy
rv = reductor(4)
TypeError: cannot pickle '_thread.lock' object
From @mands in a separate thread, breaking out to a new one since that bug was solved:
I believe I have a reproducible example, the issue seems to be when a component has nested another component that has a slot with the same name.
So for instance, in our code we have a component as follows, which has an (unused in this case) slot called body
.
<li {% if border_top %}class="border-t border-gray-200"{% endif %}>
<div class="block focus:outline-none focus:bg-gray-50 transition duration-150 ease-in-out">
<div class="py-4">
<div class="text-lg leading-7 font-medium text-indigo-600 truncate">
{{ header }}
</div>
{% slot body %}{% endslot %}
</div>
</div>
{% slot extra_content %}{% endslot %}
</li>
When called from the following fragment, it includes a sub-component in the body
slot
{% component_block "instruction_li" border_top=True header="header" %}
{% slot "body" %}
{% component "copy_field" field_selector2="line-3-field" content="content" %}
{% endslot %}
{% endcomponent_block %}
The copy_field
component eventually calls a few other components until it ends up at the following,
...
<div class="ml-3 w-0 flex-1 pt-0.5">
<p class="text-sm leading-5 font-medium text-gray-900">
{{ head }}
</p>
<p class="mt-1 text-sm leading-5 text-gray-500">
{% slot body %}
{% endslot %}
</p>
</div>
...
It seems to be this nested body
slot that causes the infinite recursion - renaming it to something else, like body1
, fixes the issue. I've also attached the test log output - it's quite long and unsure if that helpful :)
Originally posted by @mands in #64 (comment)
I have this component template:
<div>
...
{% if show_extra %}
{% slot extra_text %}{% endslot %}
{% endif %}
</div>
And in another template:
{% component_block "mycomponent" show_extra=True %}
{% slot extra_text %}show me!{% endslot %}
{% endcomponent_block %}
The text "show me!" is not rendered, just the slot default content. Overriden {% block %} content on the other hand is rendered inside a conditional.
Many components imply many CSS & JS files which affect the loading speed of the page, it would be better if all CSS & JS files get packed into one single file (CSS FILE & JS FILE) which will make improve the loading speed;
Have you ever thought to implement a single file component, similar to vuejs ?
Eg.:
@component.register("calendar")
class Calendar(component.Component):
# This component takes one parameter, a date string to show in the template
def get_context_data(self, date):
return {
"date": date,
}
template = """
<div class="calendar-component">Today's date is <span>{{ date }}</span></div>
"""
css = """
.calendar-component { width: 200px; background: pink; }
.calendar-component span { font-weight: bold; }
"""
js = """
(function(){
if (document.querySelector(".calendar-component")) {
document.querySelector(".calendar-component").onclick = function(){ alert("Clicked calendar!"); };
}
})()
"""
Nested components does not work today, and I think this might be a common case for people using components in bigger projects.
When nesting components, you quickly run into the problem with not knowing if a slot
tag refers to you defining a new slot, or if you're filling in an existing slot. This could be solved by introducing attributes that toggle if a slot should behave one way or the other, but I think the problem is fundamental enough that we should update the syntax.
Let's use {% slot %} for defining new slots, and {% fill %} for well... filling a slot with content. This does break backwards compatibility, and requires that people change their code when upgrading, but I think it's worth it to get this right.
Here are the two examples using this syntax. See if you can understand what it's doing before reading the explanation below.
<div id="dashboard">
{% component_block "calendar" date="2020-06-06" %}
{% fill header %}
{% slot calendar_header %}{% endslot %}
{% endfill %}
{% fill body %}Here are your to-do items for today:{% endfill %}
{% endcomponent_block %}
<ol>
{% for item in items %}
<li>{{ item }} </li>
{% endfor %}
</ol>
</div>
Explanation: There's an existing component named calendar that contains two slots, header and body. This template code redefines header as new slot called calendar_header, and fills the body slot with some content. Below the component it defines some other content that needs an items parameter. So this is likely the definition of a new component with just has one new slot and takes one parameter items.
Another example, now defining new default content for a slot; it works exactly as non-nested slots.
<div id="dashboard">
{% component_block "calendar" date="2020-06-06" %}
{% fill header %}
{% slot calendar_header %}Welcome to your dashboard!{% endslot %}
{% endfill %}
{% fill body %}Here are your to-do items for today:{% endfill %}
{% endcomponent_block %}
...
This syntax just makes sense to me. I can fully understand what's happening without any other explanation. It also doesn't require learning any new concept when going from the normal slot
and fill
concepts to the nested form. Things just work.
First, thank you for creating this library. It looks very promising for providing some structure to components rendered on a page!
I am considering what it would take to migrate my own Django app at work to use django-components in the future, and I notice only one notable issue:
The {% component_dependencies %}
tag which injects <script>
-includes and <link rel="stylesheet">
-includes appears to only be configurable to inject both JS and CSS at the same time in the same place.
However my existing pages include CSS and JS separately for performance reasons, with CSS at the top in the <head>
(to immediately style HTML that appears later) and JS at the bottom after the <body>
(to avoid blocking initial HTML rendering). Therefore I would like to be able to spell something like:
{% load component_tags %}
<!DOCTYPE html>
<html>
<head>
<title>My example calendar</title>
{% component_css_dependencies %} ๐
</head>
<body>
{% component "calendar" date="2015-06-19" %}
</body>
{% component_js_dependencies %} ๐
<html>
Here I've split {% component_dependencies %}
into two forms, one which injects CSS and the other which injects JS:
{% component_css_dependencies %}
(or maybe {% component_css %}
, or maybe {% component_dependencies type='css' %}
){% component_js_dependencies %}
(or maybe {% component_js %}
, or maybe {% component_dependencies type='js' %}
)What are your thoughts on allowing separate injection by type, in this fashion?
(As a separate item, {% component_css_dependencies %}
and {% component_js_dependencies %}
is quite a lot to type. Something shorter like {% component_css %}
and {% component_js %}
might be nicer.)
Hi,
I just followed the documentation and installed the project.
I am trying to make the calendar component example work in an app called tmp
. This is a cookiecutterdjangoproject, so apps are in a folder called mysite
.
I am getting TemplateDoesNotExist error. Reason: my template is in C:\Users\...\projectroot\mysite\tmp\components\calendar
, but django is searching C:\Users\...\projectroot\mysite\templates
and C:\Users\...\projectroot\mysite\tmp\templates
.
How should I solve this?
projectroot/mysite/tmp/components.py:
from django_components import component
@component.register("calendar")
class Calendar(component.Component):
def context(self, date):
return {
"date": date,
}
def template(self, context):
return "mysite/tmp/components/calendar/calendar.html"
class Media:
css = 'mysite/tmp/components/calendar/calendar.css'
js = 'mysite/tmp/components/calendar/calendar.js'
Template settings:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [str(APPS_DIR / 'templates')], # APPS_DIR is projectroot/mysite
'OPTIONS': {
# https://docs.djangoproject.com/en/dev/ref/settings/#template-loaders
# https://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types
'loaders': [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
],
...
I'm really enjoying using this library but I'm running into an issue when I come to factor out common component hierarchies and I'm not sure if I'm doing something wrong, if it's not supported, or a bug.
I'm commonly placing the following (simplified a bit for this example) hierarchy of components in several of my templates:
{% component_block "container" %}
{% slot "content" %}
{% component_block "card-container" %}
{% slot "panels" %}
{% component_block "card" %}
{% slot "sections" %}
{% component_block "card-section" %}
{% slot "content" %}
{% component_block "heading" %}{% endcomponent_block %}
{% endslot %}
{% endcomponent_block %}
{% endslot %}
{% endcomponent_block %}
<form action="{{ action }}" method="POST">
{% component_block "card" %}
{% slot "sections" %}
<!-- content here -->
{% endslot %}
{% endcomponent_block %}
{% csrf_token %}
</form>
{% endslot %}
{% endcomponent_block %}
{% endslot %}
{% endcomponent_block %}
Normally (without using django-components) I'd factor out the HTML (that corresponds to the above) into a base template and use {% extends %}
and {% block %}
to place page specific content in place of <!-- content here -->
. However it appears that the inbuilt block
template tag only works if it's not nested inside another template tag (e.g. not inside a component slot).
I also tried creating a component whose template contained the above hierarchy of components and placed a {% slot "innercontent" %}temp{% endslot %}
in place of <!-- content here -->
but temp
never got replace by the externally provided slot content. I'm guessing it can't differentiate between the slots in the template providing data to other components and the slots it should be exposing when the component is being used (especially when they are nested within each other).
Is there something I'm missing, or another way to do what I want so I don't have to duplicate the block of nested components over and over again in each template? If not, is it something that can be added easily?
Looking at the README I really don't like how asymmetrical the css
and js
properties are:
...
class Media:
css = {'all': ['[your app]/components/calendar/calendar.css']}
js = ['[your app]/components/calendar/calendar.js']
To make components easier, I think we should allow those properties to be either just strings or lists, and that we will convert them to the format that MediaDefiningClass needs.
This could be contributed to Django directly, but let's start here.
Hi @EmilStenstrom, thank you for the cool library.
I have a feature request which I would be happy to implement and make a PR for.
You have a template tag for loading the component js and css component_dependencies_tag
. This would more than likely be included in the head of the document. Since the script tags generated by the Media render function are currently not deferred I would like to be able to insert the js dependencies at the bottom of the body of the document.
Django already has 2 methods on the Media class to render these assets separately link.
So my proposal is to add 2 additional template tags which could be called should the user wish to split the js and css in their document.
Let me know your thoughts.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.