0

I'm working on a Django project involving the use of validating forms. I have my validation working, including all the rules I have applied, in one approach (the form is created when the page is rendered), but now I am trying a different approach to gain some efficiency in the number of lines of code I am using of the overall website.

It's come to my attention that I have to use the same HTML code to create a form in multiple scenarios (i.e formABC and formCBA will use the same inputs), so my new approach involves creating the form with JQuery using $(document).ready() and store the form's HTML code in a module JS files. That way, I can just call the function anytime I need that form created for a certain URL.

Let me try and break it down how my setup was vs. how it is now to shed some light where my issue may be.

Original Setup - that does work

My base.html code involves the layout

<body>
    <script 
      src="/static/js/bootstrap/bootstrap.bundle.min.js"
    ></script>
    <script 
      src="/static/js/jquery/jquery-3.6.0.min.js"
    ></script>
    <script 
      src="/static/js/jquery/jquery.validate.min.js"
    ></script>
    <script 
      src="/static/js/jquery/additional-methods.min.js"
    ></script>
    <script 
      src="/static/js/jquery/jquery-ui.min.js"
    ></script>
    <div 
      class="d-flex flex-row vh-100"
    >
      {% include "navbar.html" %}
      {% block content %}
      {% endblock content %}
    </div>
    {% csrf_token %}
    <script 
      src="/static/js/authenticate.js"
    ></script>
    <script 
      src="/static/js/validation.js"
    ></script>
</body>

Where block content is the area Django will add the specific app's HTML code I want to render. This is where my content lives, including any forms I am validating. As you can see, I have a validation.js file listed at the bottom where I store ALL my form's validators, rules, addMethods, setDefaults, etc. It kicks off when the DOM is ready (I believe) and looks like:

$(function) {
   $.validator.setDefaults({
        
        .......
    })

    $.validator.addMethod(....) {
        ....
    })

    $("#formABC").validate({
        
        rules: {
            ....
        },
        messages: {
            ....
        },
    })

   $("#form123").validate({
        
        rules: {
            ....
        },
        messages: {
            ....
        },
    })


       [....A lot more forms captured here.....]

   $("#formXYZ").validate({
        
        rules: {
            ....
        },
        messages: {
            ....
        },
    })
}

And finally, my HTML <main> content will have the creation of the form that will look like:

{% extends 'base.html' %}
{% load static %}
{% block content %}

<main>
 <form 
        method='POST' 
        id='formABC'
        novalidate
    >
        {% csrf_token %}

        [...inputs...]

  </form>
</main>

<script 
    type="module"
    src="/static/js/formABC.js"
></script>

{% endblock content %}

...where formABC.js just captures any JQuery code that is specific to this form.

NEW Setup - Forms are created from functions

Nothing changes with my base.html or validation.js file. My <main> content gets shorten to:

{% extends 'base.html' %}
{% load static %}
{% block content %}

<main>
 <div id="formABC"></div>
</main>

<script 
    type="module"
    src="/static/js/formABC.js"
></script>

{% endblock content %}

...where formABC.js captures any JQuery code that is specific to this form AND ...

import {create_formABC} from "./forms.mjs"

$(document).ready(function () {

    var form = $("#formABC")

    create_formABC(form)
})

And my new JS module, called forms.mjs, that I plan to store all my forms like so:

export function create_formABC(section) {
    var form = `
        <form 
            method='POST' 
            id="formABC" 
            novalidate
        >
            <input 
                type="hidden" 
                name="csrfmiddlewaretoken" 
                value="${csrftoken}"
            >
           
                [...same HTML code as before....]
        </form>
    `

    $(section).append(form)

To Summarize my Confusion

Why is $("#formABC").validate() not working when my form appears in this setup? Is it because my .validate() and .append(form) happen at the same time?

What makes it more confusing to me is that I have the JQuery autocomplete plugin working on this setup for inputs that need it, but it is tied to an event handler $(document).on(focus)

Sparky
  • 98,165
  • 25
  • 199
  • 285
Franklin
  • 121
  • 1
  • 2
  • 8
  • This is probably just a declaration mistake. You add a form after the DOM is loaded. You can solve this by approaching it on another way. $("body").on("click", "#formABC", function(){ this.validate}), because body already exists :) – Wimanicesir Jan 19 '23 at 14:11
  • @Wimanicesir - Ok, assuming I use this in place of $(function) {} in my validation.js? I guess this is what some people refer to as "rebinding" is that correct? – Franklin Jan 19 '23 at 14:22
  • Rebinding is not exatly what I explained but you could do it like that as well :) That is when you rebind a value to the 'this' keyword inside your function. I tried to explain this: https://stackoverflow.com/questions/10280569/jquery-select-dynamically-created-html-element – Wimanicesir Jan 19 '23 at 15:38
  • Thank you so much for the help! This worked as intended!! – Franklin Jan 19 '23 at 17:46
  • You cannot do "rebinding" with this plugin. All subsequent calls to `.validate()` are ignored. `.validate()` is a one-time initialization kind of thing. – Sparky Jan 19 '23 at 19:53

1 Answers1

0

Comments I received fixed my issue! Here was the solution:

All my validation for forms stored in validation.js were triggered with the jquery handler $(function () {}) but I needed to change that to something JQuery could 'find' when the document is loaded but before the form has been appended. So I used

$("body").on("click", function(){

   [..here is all my validation code. The includes rules, messages, setDefaults, etc....]

})

Thank you for the help!

Franklin
  • 121
  • 1
  • 2
  • 8
  • Typically, when I have forms that get appended after declaration, I use the `.rules()` method to add rules to the new form elements as needed. Otherwise, why can't you use a callback on your form append? Append -> callback -> `.validate()` initialization. – Sparky Jan 19 '23 at 19:08