Issue
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.
Solution
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/[email protected]/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/[email protected]/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.
Answered By - Detlef
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.