Flask select which form to POST by button click

I'm trying to have only one of two forms POST depending on which button from a btn-group is selected. Currently all of the forms POST with no issue, but there are two forms where only one or the other value is needed. I've unsuccessfully tried to parse the not needed value out at the app.py, so I decided to try and make this so only one or the other value gets posted.

Here is the code from the .html where I'm having trouble, it's a fieldset from a larger form the rest of which is working for now.

 <fieldset class="row mb-3, container" id="program_value_form_id">
        <legend for="value_range" class="col-sm-2 col-form-label">Value Range:</legend>
            <p>
                <div class="btn-group, com-sm-1" role="group" aria-label="Basic radio toggle button group">
                    <input type="radio" onchange="swapConfig(this)" class="btn-check" name="btnradio_valuer" id="btnradio_value1" autocomplete="off" value="valuerange1" checked>
                    <label class="btn btn-outline-primary" for="btnradio_value1">100-200</label>

                    <input type="radio" onchange="swapConfig(this)" class="btn-check" name="btnradio_valuer" id="btnradio_valuer2" autocomplete="off" value="valuerange2">
                    <label class="btn btn-outline-primary" for="btnradio_valuer2">400-500mhz</label>
                </div>
            </p>
            <div id="btnradio_valuer1Swap">
                <label for="value" class="col-sm-2 col-form-label">Value:</label>
                <p>
                    <div class="col-sm-4">
                        <input id="value1" type="number" class="form-control" placeholder="xxx.xxx 100-200" name="value1" step="0.001" min="100" max="200">
                        <span class="validity"></span>
                    </div>
                </p>
            </div>
            <div id="btnradio_valuer2Swap" style="display:none">
                <label for="value" class="col-sm-2 col-form-label">Value:</label>
                <p>
                    <div class="col-sm-4">
                        <input id="value2" type="number" class="form-control" placeholder="xxx.xxx 400-500" name="value2" step="0.001" min="400" max="500">
                        <span class="validity"></span>
                    </div>
                </p>
            </div>                  
    </fieldset>

The forms swap depending on button click. Here is the js for that I got from on here to swap them.

<script>
    function swapConfig(x) {
      var radioName = document.getElementsByName(x.name);
      for(i = 0 ; i < radioName.length; i++){
        document.getElementById(radioName[i].id.concat("Swap")).style.display="none";
      }
      document.getElementById(x.id.concat("Swap")).style.display="initial";
    }
</script>

I have tried if statements and if's inside of for's, none have worked. In frustration I've deleted them, but I could try and rewrite them again if they are needed though I wouldn't expect much from them since my html experience is limited. Please let me know if there needs to be any corrections to what I've written or if there is a better way or place to do what I am trying to do.

1 answer

  • answered 2022-05-07 20:50 Detlef

    The following example allows you to exclude and hide parts of the form.

    When a fieldset or input is disabled, it is no longer part of the form data that can be queried on the server side. For this reason, depending on the value of the radio buttons, parts of the form that are referenced by specifying dataset properties are disabled. The JavaScript code activates and deactivates the elements of the form that are not required.

    The appearance of certain elements can also be changed using the diabled property. Additional style sheet rules are required for this. Thus an entire row of the form is hidden when the contained input field is deactivated.

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <title></title>
      <link 
        rel="stylesheet" 
        href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" 
        integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" 
        crossorigin="anonymous">
      <style>
        /*
        Toggle the appearance of the row containing an input field whose property 
        has been set to disabled.
         */
        div.row:has(input.value-control[disabled]) {
          display: none;
        }
      </style>
    </head>
    <body>
    
      <div class="container my-4">
    
        <form method="post">
          <div class="row mb-3">
    
            <!-- The button group to switch between the form parts. -->
            <div class="col btn-group" role="group" aria-label="Basic radio toggle button group">
    
              <!-- The data-target and data-parent properties reference the parts to be switched. -->
              <input
                id="btnradio1"
                class="btn-check"
                name="btnradio"
                type="radio"
                autocomplete="off"
                data-parent=".value-control"
                data-target="#value-control-1"
                checked
              >
              <label class="btn btn-outline-primary" for="btnradio1">100-200 Mhz</label>
    
              <input
                id="btnradio2"
                class="btn-check"
                name="btnradio"
                type="radio"
                autocomplete="off"
                data-parent=".value-control"
                data-target="#value-control-2"
              >
              <label class="btn btn-outline-primary" for="btnradio2">400-500 Mhz</label>
            </div>
          </div>
    
          <div class="row mb-3">
            <label for="value-control-1" class="col-sm-2 col-form-label">Value:</label>
            <div class="col-sm-10">
              <!-- 
              The references of the radio buttons refer to the class and id attributes 
              of the input field. 
              -->
              <input
                id="value-control-1"
                class="form-control value-control"
                name="value"
                type="number"
                step="0.001" min="100" max="200"
                placeholder="xxx.xxx 100-200"
                required
              >
            </div>
          </div>
    
          <div class="row mb-3">
            <label for="value-control-2" class="col-sm-2 col-form-label">Value:</label>
            <div class="col-sm-10">
              <input
                id="value-control-2"
                class="form-control value-control"
                name="value"
                type="number"
                step="0.001" min="400" max="500"
                placeholder="xxx.xxx 400-500"
                required
                disabled
              >
            </div>
          </div>
    
          <div class="d-grid">
            <button type="submit" class="btn btn-primary">Submit</button>
          </div>
        </form>
    
      </div>
    
    
      <script
        src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
        crossorigin="anonymous"></script>
    
      <script type="text/javascript">
      (() => {
        // Wait for the document content to load. This listener is not absolutely 
        // necessary at this point, since the script element is at the end of the document.
        window.addEventListener('DOMContentLoaded', () => {
          // Select the toggle buttons based on their properties.
          const radioSel = 'input[name="btnradio"][data-target][data-parent]';
          const radioBtns = document.querySelectorAll(radioSel);
          radioBtns.forEach(btn => {
            // Register a listener for the change event for each element found.
            btn.addEventListener('change', evt => {
              // Change the disabled property of the referenced elements.
              const parent = document.querySelectorAll(evt.target.dataset.parent);
              const target = document.querySelector(evt.target.dataset.target);
              parent.forEach(elem => elem.disabled = true );
              target && (target.disabled = !evt.target.checked);
            });
          });
        });
      })();
      </script>
    
    </body>
    </html>
    
    from flask import (
        Flask,
        render_template,
        request
    )
    
    app = Flask(__name__)
    
    @app.route('/', methods=['GET', 'POST'])
    def index():
        if request.method == 'POST':
            print(request.form.get('value', type=float))
        return render_template('index.html')
    

    With the listener for DOMContentLoaded the execution of the code is delayed until the content of the HTML page is completely loaded.

    The listener for the change event notices if an input field has changed. The changing field is then stored as a target within the event object. Basically, the variant used corresponds to adding an onchange attribute, which can be added. However, the separation of HTML and JavaScript is done more cleanly here.

    With the querySelector or the querySelectorAll one or more elements can be selected from the document using the selector. In this case it is searched for the tag and used classes or ids and existing properties. This option gives you more leeway than getElementById or getElementsByClassName.

    I use the forEach function to iterate over the selected elements.

    A dataset allows custom parameters added to an element to be read and written via JavaScript. Used here to describe the referenced parts of the form.

    Basically, there are several ways to write functions in JavaScript. Arrow functions are used in the example. However, the normal way with the function keyword is always possible.

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum