Search code examples
djangodjango-formsdjango-crispy-formsalpine.jshtmx

django htmx change hx-get url after user input from radio buttons


This is forms.py:

class OrderForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.attrs = {
            "hx_get": reverse("planner:detail", kwargs={"slug": self.instance.venue}),
            "hx_target": "#services",
        }

    class Meta:
        model = Order
        fields = ["venue"]

        widgets = {"venue": forms.RadioSelect()}

HTML:

<div id="venue-options" class="p-3">
  {% crispy form %}
</div>

This is the error when you click one of the radio buttons: The current path, planner/detail/None/, matched the last one. It says None/ because when you join the page none of the radio buttons are clicked so there is no slug to replace it. I need a way to replace None with the slug / id of the object chosen by the user. I need the url to be changed everytime the choise is changed.

I am open to using apline.js but i would like a way of doing it in htmx/django.

Thank you so much.


Solution

  • Basically you are changing a single attribute (hx_get) based on a click. HTMX would make this a roundtrip to the server which seems inefficient as all the data is there on the page (assuming the value of the radiobuttons is the slug you are after). You can do this with pure javascript which would make the process much faster

    <script>
        //get the form
        const venueForm = document.getElementById('venue-options')
        //when implementing, replace [name='radio'] with name of radio input fields
        const venueRadioButtons = document.querySelectorAll("input[name='radio']")
        //get the default venue URL for later alteration
        const venueURL = venueForm.getAttribute('hx_get')
        
        // create a clickhandler to change the URL to selected radiobutton
        const clickHandler = () => {
          //get the slug value
          let radioButtonSlug=document.querySelector("input[name='radio']:checked").value
          //use reguylar expression to replace last '/word/' value with slug value
          let newVenueUrl = venueURL.replace(/\/\w+\/$/, "/" + radioButtonSlug + "/")
          //reset the the hx_get value
          venueForm.setAttribute('hx_get', newVenueUrl)
        };
        
        // Assign the handler to the radiobuttons
        venueRadioButtons.forEach(i => i.onchange = () => clickHandler());
    </script>