Here is the form I have ( many dishes where each has an input number ( quantity of dishes to order ).
The problem is that I would like to show the price of an order before the order is done, for this I need to sum somehow input of the ${dish.price}, but how can this be done?
<form action="#" th:action="#{/menu}" th:object="${order}" method="post">
<div th:each="dish : ${dishList}">
<div>
<h4 th:inline="text">[[${dish.name}]]<span class="price" th:text="${dish.price}">45</span></h4>
<p th:text="${dish.category}">DRINKS</p>
<p th:text="${dish.description}">
Aperiam tempore sit,perferendis numquam repudiandae porro
voluptate dicta saepe facilis.
</p>
<div>
<button class="decrement" type="button" onclick="stepperDecrement(this)">-</button>
<input
th:value="0"
th:name="${'dishIdQuantityMap[' + dish.id + ']'}"
type="number"
min="0"
max="100"
step="1"
/>
<button class="increment" type="button" onclick="stepperIncrement(this)">+</button>
</div>
</div>
</div>
</div>
<button type="submit" value="Submit">Confirm order</button>
</form>
JS ( Just inputs +1 to input type"number" when the button is clicked )
function stepperDecrement(btn){
const inputEl = btn.nextElementSibling;
const calcStep =inputEl.step * -1;
const newValue = parseInt(inputEl.value) + calcStep;
if(newValue >= inputEl.min && newValue <= inputEl.max){
inputEl.value = newValue;
}
}
function stepperIncrement(btn){
const inputEl = btn.previousElementSibling;
const calcStep = inputEl.step * 1;
const newValue = parseInt(inputEl.value) + calcStep;
if(newValue >= inputEl.min && newValue <= inputEl.max){
inputEl.value = newValue;
}
}
Of course yes, it is possible.
To get server data inside your thymeleaf templates, you can proceed various ways, and it depends on the context where you need that data.
Inside Javascript, (CSP "script-src 'unsafe-inline' ..." or <script th:inline="javascript" nonce="" ...> are required because writing JS inline is a bad way regarding all XSS caveats. Thanks OWASP), you can try to write : let productCategory = /*[[${productCategory}]]*/ '';
Inside Javascript with ES6+ modules (with webpack or any other solution), you can check an endpoint of your webapp (using Promise feature with polyfill) which will load data inside a form input element. And make your operations as usual. Have fun.
Related
Good Morning,
I am developing a system which can accept multiple object at the same time, technology used are:
Spring 5.2.5.RELEASE For the backend,
Jsp for Front layer.
The main goal is to let the user put 16 (predefined number, so it is not dynamic the lenght of the array) records of a "Delta P" data with only one form.
As the "nome_operatore" and "data_operazione_delta_p" are equal in all the records, they are submitted only ones and then replicated in the controller for all records submitted.
Since now I came out with the subsequent classes following various tutorials here on SO and over the net.
In general, the view is correctly displayed (I scanned the code generated by Spring and it is correct as far as I know) and the GetMapping to display the form page works correctly as well (I debugged to see if some data were not correct, but I found no errors).
The only problem is that when I submit the form, the page freezes and after a while Chrome display an advise saying that is impossibile to load the page.
The server is still running, as the server keeps logging correctly, but the line
logger.info("submitted form to create multiple Delta P data");
is never reached.
No errors are displayed either in Chrome console.
If this is not the correct way to upload multiple items at one time, how this could be done in Spring 5?
EDIT
After investigation I found chrome giving a RESULT_CODE_HUNG error, but on the net I found nothing useful to fix it, only people complaining about "chrome killing pages", can someone explain what this error means at least? I tried to document myself but with no success. The same error shows up also in Edge and Firefox.
List wrapper
package com.entsorgafin.dto;
import com.entsorgafin.model.Dato_delta_p;
import java.util.ArrayList;
import java.util.List;
public class DeltaPListWrapper
{
private List<Dato_delta_p> deltaPList;
public DeltaPListWrapper()
{
this.deltaPList = new ArrayList<>();
}
public List<Dato_delta_p> getDeltaPList()
{
return deltaPList;
}
public void setDeltaPList(List<Dato_delta_p> deltaPList)
{
this.deltaPList = deltaPList;
}
public void add(Dato_delta_p dato_delta_p)
{
this.deltaPList.add(dato_delta_p);
}
}
Controller methods
/**
* Shows the form to insert a new delta p data series in the system.
* <p>
* Returns the form page.
*
* #param model ModelMap of the UI
* #return The form page to insert one record for each sector
*/
#GetMapping("/addDeltaP")
public String addDeltaP(ModelMap model)
{
logger.info("adding Delta P data");
logger.debug("finding infos for front end representation");
//finding users to relate the records with
List<Utente> users = utentiService.findAllUsers();
logger.debug("found " + users.size() + " users");
Map<Integer, String> userForFE = new HashMap<>();
for(Utente utente : users)
{
userForFE.put(utente.getId_utente(), utente.getNome() + " " + utente.getCognome());
}
model.addAttribute("users", userForFE);
//finding active sectors
List<Settore> activeSectors = new ArrayList<>();
activeSectors.addAll(settoriService.findActiveSectorForPhase("act"));
activeSectors.addAll(settoriService.findActiveSectorForPhase("cur"));
logger.debug("found " + activeSectors.size() + " active sectors");
//creating wrapper which contains multiple Delta P records
DeltaPListWrapper listWrapper = new DeltaPListWrapper();
//Pre-filling sector field for delta P data
for(Settore sect : activeSectors)
{
Dato_delta_p dato_delta_p = new Dato_delta_p();
dato_delta_p.setSettore(sect);
listWrapper.add(dato_delta_p);
}
model.addAttribute("deltaPData", listWrapper);
model.addAttribute("activeSectorNumber", activeSectors.size());
return "uploadDeltaPData";
}
/**
* Saves a new series of data record in the database.
*
* #param listWrapper List of Delta p data to create
* #return Returns the homepage
*/
#PostMapping("/addDeltaP")
public String addDeltaP(#ModelAttribute("deltaPData") DeltaPListWrapper listWrapper)
{
logger.info("submitted form to create multiple Delta P data");
/*
getting Date of the first record, operations are performed on the same date, so
every record will have the same property for data_operazione
The same stands for the user who performed the operations
*/
LocalDate dataOperazione = listWrapper.getDeltaPList().get(0).getData_operazione_delta_p();
Utente idUtente = listWrapper.getDeltaPList().get(0).getUtente_id_utente();
/*
Filling delta P data with active batch for the sector they are from
*/
for(Dato_delta_p dato_delta_p : listWrapper.getDeltaPList())
{
dato_delta_p.setUtente_id_utente(idUtente);
dato_delta_p.setData_operazione_delta_p(dataOperazione);
String phase;
Settore used = settoriService.findSectorById(dato_delta_p.getSettore().getId_settore());
if(used.getFase().equals("act"))
{
phase = "act";
} else
{
phase = "cur";
}
Lotto referencedLotto = lottoService
.findActiveBatchInSectorAndDate(dato_delta_p.getData_operazione_delta_p(), dato_delta_p
.getSettore(), phase);
logger.debug("found Lotto with ID " + referencedLotto.getId_lotto() + " for Delta P record");
dato_delta_p.setLotto_id_lotto(referencedLotto);
//creating the data
dati_delta_pService.createDeltaPData(dato_delta_p);
logger.info("Delta P data created correctly");
}
return "redirect:/entsorgafin/home";
}
JSP view
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<jsp:include page="header.jsp"/>
<div class="container">
<h1>Inserisci i dati delta P</h1>
<form:form method="post" modelAttribute="deltaPData" onsubmit="enableFields(${activeSectorNumber})">
<div class="row">
<div class="form-group col">
<label for="utente_id_utente">Nome dell'operatore</label>
<form:select class="form-control" id="utente_id_utente" path="${deltaPList[0].utente_id_utente.id_utente}" required="required">
<form:option value="" />
<form:options items="${users}" />
</form:select>
</div>
<div class="form-group col">
<label for="data_operazione_delta_p">Data dell'operazione</label>
<form:input path="${deltaPList[0].data_operazione_delta_p}" type="date" class="form-control" id="data_operazione_delta_p" required="required" />
</div>
</div>
<div class="row text-center">
<div class="col my-auto">Numero del settore</div>
<div class="col my-auto">Valore deltaP rilevato</div>
<div class="col my-auto">Velocità ventilatore</div>
<div class="col my-auto">Settore pieno</div>
<div class="col my-auto">Settore in caricamento</div>
</div>
<c:forEach items="${deltaPData.deltaPList}" varStatus="i">
<form:input path="deltaPList[${i.index}].id_dato_delta_p" type="hidden" id="id_dati_delta_p" />
<div class="row text-center">
<div class="form-group col">
<form:input path="deltaPList[${i.index}].settore.id_settore" class="form-control text-center" id="settore${i.index}" required="required" disabled="true"/>
</div>
<div class="form-group col">
<form:input path="deltaPList[${i.index}].valore_delta_p" type="number" step="0.01" class="form-control" id="valore_delta_p" required="required" />
</div>
<div class="form-group col">
<form:input path="deltaPList[${i.index}].velocita_ventilatore" type="number" step="0.01" class="form-control" id="velocita_ventilatore" required="required" />
</div>
<div class="form-group col my-auto">
<form:checkbox path="deltaPList[${i.index}].stato_settore_pieno" id="stato_settore_pieno${i.index}" value="true" onclick="disableSettoreCaricoBox(${i.index})"/>
</div>
<div class="form-group col my-auto">
<form:checkbox path="deltaPList[${i.index}].stato_settore_carico" id="stato_settore_carico${i.index}" value="true" onclick="disableSettorePienoBox(${i.index})"/>
</div>
</div>
</c:forEach>
<input type="submit" value="create" class="btn btn-primary btn-sm">
</form:form>
</div>
<jsp:include page="footer.jsp"/>
<script>
function disableSettoreCaricoBox(i)
{
const checked = document.getElementById('stato_settore_pieno' + i).checked;
document.getElementById("stato_settore_carico" + i).disabled = !!checked;
}
function disableSettorePienoBox(i)
{
const checked = document.getElementById('stato_settore_carico' + i).checked;
document.getElementById("stato_settore_pieno" + i).disabled = !!checked;
}
function enableFields(i)
{
for(let x = 0; x < i; x++)
{
document.getElementById("settore" + x).disabled = false;
}
}
</script>
I actually feel kind of an idiot for not noticing it before, after focusing on Spring possible errors I lost a minor point in the code where the error actually is: Javascript function.
function enableFields(i)
{
for(let x = 0; x < i; i++)
{
document.getElementById("settore" + x).disabled = false;
}
}
should be
function enableFields(i)
{
for(let x = 0; x < i; x++)
{
document.getElementById("settore" + x).disabled = false;
}
}
I'll correct the quetion code, hope this could anyway help someone who's searching an example of multi row submitting in Spring 5.
Those are the fields that I have that I want to write a conditional statement for in a PDF form that I am creating in Adobe Acrobat Pro X. In the form if I tick the checkbox I would like FP1 to get the value from QxHxW1. If the checkbox is not ticked I want FP1 to register as "0". I have been trying to do this with different tutorials that I have found online and each time I get some sort of SyntaxError.
is there anything I can do to fix this? Am I way off with the way that this is written?
FrenchPane1 is a checkbox
FP1 is a text box
QxHxW1 is a text box
Using javascript, this would be:
var check = document.getElementsByClassName('check');
for( var i = 0; i < check.length; i++ ){
check[i].onchange = function() {
var isChecked = this.checked;
var target = document.querySelector(this.dataset.target);
var source = document.querySelector(this.dataset.source);
target.value = isChecked ? source.value : '0';
}
}
<div>
<label for="FrenchPane1"><input type="checkbox" id="FrenchPane1" data-target="#FP1" data-source="#QxHxW1" class="check"> FrenchPane1</label>
<input type="text" name="FP1" id="FP1">
<input type="text" name="QxHxW1" id="QxHxW1" value="Some values">
</div>
<div>
<label for="FrenchPane1"><input type="checkbox" id="FrenchPane2" data-target="#FP2" data-source="#QxHxW2" class="check"> FrenchPane1</label>
<input type="text" name="FP2" id="FP2">
<input type="text" name="QxHxW2" id="QxHxW2" value="Some values 2">
</div>
I have written the following code in JSFiddle to able so get the sum of combined values of the checkboxes.
Script
var inputs = document.getElementsByClassName('sum'),
total = document.getElementById('payment-total');
for (var i=0; i < inputs.length; i++) {
inputs[i].onchange = function() {
var add = this.value * (this.checked ? 1 : -1);
total.innerHTML = parseFloat(total.innerHTML) + add
}
}
Code
<input value="33" type="checkbox" class="sum" data-toggle="checkbox">
<input value="50" type="checkbox" class="sum" data-toggle="checkbox">
<input value="62" type="checkbox" class="sum" data-toggle="checkbox">
<span id="payment-total">0</span>
There it works perfect, when I implement this in my system there is no reslut or any error.
The checkboxes in my system are genarated by an MySQL output.
Any suggestions what migh be wrong?
Your code is probably running before the elements are dynamically generated, so the event handlers are not being attached. Try delegating the event handlers using .on() method:
$total = $('#payment-total');
$(document).on("click", ".sum", function() {
var add = this.value * (this.checked ? 1 : -1);
$total.text(function(i, value) {
return parseFloat(value) + add;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input value="33" type="checkbox" class="sum" data-toggle="checkbox">
<input value="50" type="checkbox" class="sum" data-toggle="checkbox">
<input value="62" type="checkbox" class="sum" data-toggle="checkbox">
<span id="payment-total">0</span>
I prefer to use pure javascript for your solution because you didn't use Jquery on your code. I think problem reason comes from Javascript eventListener. When you create a new element to your document, you should add its events.
In first code i create a checkbox but this is not work as others. link_1
<http://jsfiddle.net/3oweu107/1/>
However in second code i add event as other checkbox so payment-total value calculation done by new event. link_2
<http://jsfiddle.net/3oweu107/2/>
i hope this will help your problem :)
I have a HTML page with dinamycally changing number of select elements.
<script>
function getValues() {
var selects = document.getElementsByTagName('select'),
arr = Array.prototype.slice.call(selects),
selectValues = arr.map(function (select) {
return select.value;
});
return selectValues;
}
</script>
<script type='text/javascript'>
function moreSelect() {
for (i = 0; i < number; i++) {
// Append a node with a random text
container.appendChild(document.createTextNode("Name " + (i+1) + ": "));
// Create an <input> element, set its type and name attributes
var input = document.createElement("select");
input.name = "name" + (i+1);
container.appendChild(input);
// Append a line break
container.appendChild(document.createElement("br"));
}
</script>
<form action="action"method="POST" onsubmit="return getValues;">
More selects (max. 9):<br>
<p>
<input type="number" id="name" name="name" value="0"
min="0" max="9"><br />
<button type="button" onclick="moreSelect()">Add</button>
<br>
<p>
<br>
<div id="container" /></div>
<p>
<br> <br> <input type="submit" value="Go">
</form>
I want to collect this values to a List or an Array before the POST method and give this parameter list to my Java controller like this:
#RequestParam("allValues") List<String> allValues
Edit: I edited it, but doesn't works.
Get all selects, transform them to a real Array by Array.prototype.slice. Now you can use map to get all values. getElementsByTagName returns a HTMLCollection, that does not support map(), etc.
var selects = document.getElementsByTagName('select'),
arr = Array.prototype.slice.call(selects),
selectValues = arr.map(function (select) {
return select.value;
});
Now selectValues is an Array of the select values.
You can add one hidden form parameter say with name "allValues" and using javascript before posting Form, you can add all select values in that parameter.
I would like to add some JavaScript to do the following.
I would have 3 fields like this.
<input type="text" name="a" />
<input type="text" name="b" />
<input type="hidden" name="c" />
say if I entered 100 in the first field and 19 in the second field.
it would divide 100 by 19 and round it up to no decimal places, and then replace the value of the third hidden field by the answer, so in the case it would be (100/19) 5.26... rounded up to 6
however I am not sure how to actually implement this.
Say your form looks like this;
<form id="myForm" method="POST">
<input type="text" name="a" />
<input type="text" name="b" />
<input type="hidden" name="c" />
</form>
You can access the form like this;
function doAction(action)
{
var frm = document.forms.myForm;
frm.c.value = frm.a.value/frm.b.value;
}
You can trigger the action by adding a button that can be clicked, or setting the form's submit action.
Edit: Doesn't round up, not sure how to do that :(
A nice easy method is to pass the form to a function, and allow that function to do the calculation.
The form should look like:
<form>
<input type="text" name="a" />
<input type="text" name="b" />
<input type="hidden" name="c" />
<input type="button" value="Click" onClick="doCalculate(this.form)" />
</form>
and the javascript:
function doCalculate(theForm){
var aVal = parseFloat(theForm.a.value);
var bVal = parseFloat(theForm.b.value);
var cVal = 0;
if(!isNaN(aVal) && !isNaN(bVal)){
cVal = Math.ceil(aVal/bVal);
}
theForm.c.value = cVal;
}
Working example here --> http://jsfiddle.net/azajs/
Edit: This can also be done when the form is submitting by having a similar call in the onsubmit of the form:
<form onsubmit="doCalculate(this);" >
...
</form>
A dumbed-down way, which assumes your form is document.forms[0]:
<input type="text" name="a" onchange="myFunction" />
<input type="text" name="b" onchange="myFunction" />
<input type="hidden" name="c" />
function myFunction() {
var inpA = document.forms[0].a;
var inpB = document.forms[0].b;
var aVal = parseFloat(inpA.value);
var bVal = parseFloat(inpB.value);
if (!isNaN(aVal) && !isNaN(bVal) && bVal !== 0) {
document.forms[0].c.value = Math.ceil(aVal/ bVal);
}
}
EDIT: Math.round => Math.ceil
After the form elements:
<script type="text/javascript">
(function() {
var a= document.getElementsByName('a')[0];
var b= document.getElementsByName('b')[0];
var c= document.getElementsByName('c')[0];
a.onchange=b.onchange=a.onkeyup=b.onkeyup= function() {
c.value= Math.ceil(a.value/b.value);
};
})();
</script>
This recalculates on each key press, remove the keyup binding if you don't want that.
Add a unique id to each input and use document.getElementById to avoid any ambiguity with name. If this form is never going to be submitted you can omit name entirely.
Math.ceil() will return NaN if either value cannot be read as a number, or Infinity if you divide by zero. You may wish to check for these conditions and write a different value.
You do this by binding an eventlistner to the from element. You either create your own (Javascript native event handlers) or use your favorit javascript framework. My example is for using the jQuery jQuery bind method javascript framework.
/* first set and id to your input hidden and form element so you can reach it in fast way */
<form id="myForm"><input type="hidden" id="total" name="c" /></form>
/* Javascript code using jquery */
$('#form').bind('submit', function () {
$('#total').val(function () {
var num = parseFloat($('#form input[name=a]').val()) / parseFloat($('#form input[name=b]').val());
return Math.floor(num) === num ? num : Math.floor(num) + 1;
});
});