Giter VIP home page Giter VIP logo

django-components's People

Contributors

ar4s avatar bradleykirton avatar danjac avatar david-guillot avatar dependabot[bot] avatar dylanjcastillo avatar ekaj2 avatar emilstenstrom avatar franciscobmacedo avatar gabdug avatar github-actions[bot] avatar hanifbirgani avatar hjalves avatar housunus avatar imankulov avatar jurooravec avatar lemontheme avatar mands avatar pre-commit-ci[bot] avatar rafae56038 avatar rbeard0330 avatar real-gecko avatar rwblokzijl avatar ryanhiebert avatar simkimsia avatar spapas avatar tanssinet avatar telenieko avatar timothyis avatar vojtechpetru avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-components's Issues

I can't load javascript and css

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.

Automatically look for CSS and JS files in component directory

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.

Make `{% component %}` play well with `{% block %}`

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.

jquery problem

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.

Lots of print output in 0.11

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'>

Passing variable from view function to component_block part

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.

Check if slot is not empty

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).

Feature request

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.

  • component_css_dependencies_tag
  • component_js_dependencies_tag

Let me know your thoughts.

django-components not working when deployed to apache2 server

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?

Future: Push component updates from server to client

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:

  1. After the first render is complete we add a new js-file in the component_js_dependencies area
  2. That JS sets up a websocket connection to the server
  3. On the server side we add a update_client method to components, that rerenders the component with a new context dict, and sends that to all connected clients
  4. Each client listens to update-events, finds the component in the HTML via a unique ID, and replaces it with the new HTML (in a way that doesn't break focus if this is a form)

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

"context" is empty in template method

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?

Ability to choose which components JS/CSS to load

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 %} :

  • If the ComponentDependencyMiddleware is disabled, JS from all components will be loaded, which is suboptimal
  • If the middleware is enabled, no component JS will be loaded, as the page template doesn't hold any {% 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 ๐Ÿ˜‰

Make django-components look for templates in a specific place

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',
            ],
           ...

slot.super?

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 %}

Packing css & js components files into one file

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;

Same slot node name in nested component results in infinite recursion

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 :)

test_log.txt

Originally posted by @mands in #64 (comment)

Question about component scope

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!

Use component name as variable

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

Zero documentation on location of component modules

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.

Class decorator for registering components

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):
    ...

Single file components

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!"); };
            }
        })()
    """

`{% csrf_token %}` not available inside component HTML

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!

Nested slots don't work

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>

Complex arguments for component tag

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 %}

because {% component_js_dependencies %} loads all the components, so best to check to prevent null elements

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!"); };
    }
})()

component not registered !

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!

Allow single quoting of component names

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('"\'')

runserver hot reload doesn't work on django 3.2 when component's python file is modified

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:

  1. clone django-components repository
  2. modify sampleproject/requirements.txt: freeze django to version 3.2 django==3.2
  3. install requirements pip install -r requirements.txt
  4. run the project python3 manage.py migrate && python3 manage.py runserver
  5. update file sampleproject/components/calendar/calendar.py (eg. add raise Exception('hello') inside method get_context_data
  6. Refresh the page in the browser and observe that change is not propagated (eg. the exception is not raised)
  7. Kill the runserver command and run it again to confirm that in this case the change is propagated (eg. the exception is raised)

templatetags folder is missing when installed by pip

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.

Handling missing context_variables in slotted templates and passing kwargs in {% component_block %}

Sorry for putting both of these in one issue, but they're both so minor it seemed excessive to open separate issues:

  1. 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.

  2. 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 FilterExpressions 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.

Automate releases to PyPI with GitHub Actions

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.

Use new `{% slot %}` and `{% fill %}` tags to enable nested components

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.

{% block %} does not work inside a slot

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?

Document how to bundle component media using a popular asset manager library

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?

  • Max 2 HTTP requests when adding django-components no matter the number of components, which means better scaling to larger code bases.
  • Chance of better gzip compression when bundling files together
  • If we preprocess the CSS and JS files there's a chance to modify them as needed for new features. Automatic isolation of JS and CSS blocks?

Downsides?

  • Worse caching when since the bundled files are different whenever a single component is different for a page. With separate files caching will likely be better.
  • Hard problem to solve?

Things to consider:

  • How does this work together with collectstatic?
  • How will this work together with cache headers?
  • How will this work together with gzipping?

Access to "request" and other global context variables

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.

Duplicate node / deepcopy bug in 0.13

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

Slot is not executed in conditional {% if %} block

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.

Add automatic code formatting with Black

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.

Allow rendering JS / CSS parts of {% component_dependencies %} separately?

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:

  • CSS: {% component_css_dependencies %} (or maybe {% component_css %}, or maybe {% component_dependencies type='css' %})
  • JS: {% 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.)

Add keyword "optional" to slot to make it optional to fill

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.

Allow Media.css property to be a list

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.