Django and stimulusjs values

Django and stimulusjs values

Intrroduction

Recently i was experimenting with Stimulus as a light weight javascript library to use with django, and i found a great video course at Stimulus - Symfony Cast.

The problem

I had some values passed from django view to the html template via context and i wanted to access those values on javascript stimulus controller

Solution

Stimulus has a builtin method to do that, its called Stimulus Values, let us assume that we need to pass the django user email to javascript, first we need to create a stimulus controller on the html then we pass the user email as a value like this (I will assume that you have a working django setup with stimulus)

<div
  data-controller="email-ctrl"
  data-email-ctrl-user-email-value="{{ user.email }}"
>
  ...
</div>

Notice the name is important and follow this pattern data-{controller_name}-{value-name}-value, the value name is written in the html as kebab-case and will automatically transfered into camelCase so user-email will become userEmail on the javascript side, in your stimuluse controller define the values that you are expecting and use it

import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static values = {
    userEmail: { type: String, default: "" },
  };

  connect() {
    console.log("Controller connected to: ", this.element);
    // access the passed value
    console.log(this.userEmailValue);
  }
}

all good so far, but when i watched the video on the above mentioned course,I found that in Symfony PHP framework which use twig template engine, they have a nicer way Twig Function for defining the controller with its values, something similar to this

<div {{ stimulus_controller("email-ctrl" , { "user-email": user.email}) }}>
  ...
</div>

and i wondered if i can have something similar in django so i built a simple template tag for it

# <django_app>/templatetags/stimulus.py
import re
from django import template

register = template.Library()

def convert(name: str):
    """convert camelCase to kebab-case"""
    return re.sub(r"(?<!^)(?=[A-Z])", "-", name).lower()

@register.simple_tag
def stimulus_controller(controller_name: str, **kwargs):
    """Render a Stimulus controller tag."""

    stimulus_values = [
        f"data-{controller_name}-{convert(k)}-value={v.strip()}"
        for k, v in kwargs.items()
        if v.strip() != ""
    ]
    return f"data-controller={controller_name} {' '.join(stimulus_values)}"

then in your template use it like this

{% load stimulus %}
...
...
<div {% stimulus_controller  'email-ctrl' userEmail=user.email %} >
...
</div>

now when django render the template it will generate the same above html with data- attrributes

isn't it beutiful :D

s