Form is empty when submitted using Thymeleaf - spring-boot

I want to fill a list of applications for a university in the frontend. Each entry is supposed to hold two buttons: one for accepting the application and one for rejecting it. I created one form for each submit-button each.
<div class="container">
<div class="row">
<div class="col-12">
<table class="table table-hover">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">Firstname</th>
<th scope="col">Lastname</th>
<th scope="col">Grade</th>
<th scope="col">NC</th>
<th scope="col">Course</th>
<th scope="col">Certificate</th>
<th scope="col">Recommendation</th>
<th scope="col">Decision</th>
</tr>
</thead>
<tbody>
<tr th:each="applicationOpen, rowStat: ${lstOpApplications}">
<th th:text="${rowStat.count}">1</th>
<td th:text="${applicationOpen.firstname}">firstname</td>
<td th:text="${applicationOpen.lastname}">lastname</td>
<td th:text="${applicationOpen.highschool_grade}">grade</td>
<td th:text="${applicationOpen.nc}">nc</td>
<td th:text="${applicationOpen.name}">coursename</td>
<td th:text="${applicationOpen.highschool_certificate}">certificate</td>
<td th:text="${applicationOpen.document}">recommendation</td>
<td>
<form action="#" th:action="#{/Bewerberubersicht}" th:object="${decisionForm}" method="post">
<input type="hidden" name="application_id" th:field="*{application_id}" value=${applicationOpen.id}"/>
<input type="hidden" name="decision" th:field="*{decision}" value=1/>
<button type="submit" class="btn btn-success"><i class="fas fa-edit"></i>Accept</button>
</form>
<form action="#" th:action="#{/Bewerberubersicht}" th:object="${decisionForm}" method="post">
<input type="hidden" name="application_id" th:field="*{application_id}" value=${applicationOpen.id}/>
<input type="hidden" name="decision" th:field="*{decision}" value=2/>
<button type="submit" class="btn btn-danger"><i class="fas fa-edit"></i>Reject</button>
</form>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
When I look in the Browser's Dev-Tools I can see that the content of the POST-request is
application_id: ""
decision: ""
When I replace value=${applicationOpen.id} with e.g. value=5 it is still empty. Hence, it should not be a problem with applicantOpen. Also, the list in the frontend is being filled just fine, so all of that should work. I first thought is is a problem with the DecisionForm class, but it seems my subsequent problems are caused by the issue described here.

The th:field attribute overrides content of name and value attributes. The decisionForm object seems to have empty fields so all forms have empty values.
Basically using th:object with th:field is convenient when you need to have your form prepopulated with values. It establishes initial state of your form, not the target. Using them makes sense for single form, not for multiple forms in loop with varying values.
In your case: please remove both th:object and th:field attributes. Instead use value="1" or value="2" for decision input, and th:value="${applicationOpen.id}" for application_id input.

Related

passing a query result received from a controler in blade, back to another controller in laravel 8

I have a view that received a query result $necps from a controller, and I want to send to another controler with a form like below.
I am using a foreach to create the hidden inputs, but in the controller I get just the last record.
First question is : can I do that in a more elegant way? Sendind the entire query result at once?
Second : If not, how can I send all the array using foreach?
No Js please. Thanks a lot.
#if (isset($necps))
<div style="float:left; margin-left:20px;" >
<form style="display:inline;" action="{{route('mostra_varios_parts')}}" method="post">
#csrf
<button type="submit" class="btn btn-sm btn-mapa bi-globe texto_p"> Mapa</button>
#foreach($necps as $necp)
<input value="{{$necp->id_part}}" name="parts[id]" type="hidden">
<input value="{{$necp->latitude}}" name="parts[latitude]" type="hidden">
<input value="{{$necp->longitude}}" name="parts[longitude]" type="hidden">
<input value="{{$necp->nome_part}}" name="parts[nome_part]" type="hidden">
<input value="{{$necp->endereco}}" name="parts[endereco]" type="hidden">
#endforeach
</form>
</div>
<br>
<br>
<table class="table table-sm tabela-necessidade">
<thead>
<tr>
<th scope="col" class="texto_p">Nome</th>
<th scope="col" class="texto_p">Necessidade</th>
<th scope="col" class="texto_p">Categoria</th>
<th scope="col" class="texto_p">Data</th>
<th scope="col" class="texto_p">Quant</th>
<th scope="col" class="texto_p">Unidade</th>
<th scope="col" class="texto_p">Local</th>
<th scope="col" class="texto_p">Observações</th>
<!--<th scope="col" class="texto_p">Distância/Kms</th>-->
<th class="texto_p" colspan="1">Ações</th>
</tr>
</thead>
<tbody>
#if (count($necps)>0)
#foreach($necps as $necp)
<div>
<tr>
<td class="texto_p">{{$necp->nome_part}}</td>
<td class="texto_p">{{$necp->desc_nec}}</td>
<td class="texto_p">{{$necp->desc_cat}}</td>
<td class="texto_p">{{$necp->data}}</td>
<td class="texto_p">{{$necp->quant}}</td>
<td class="texto_p">{{$necp->desc_unid}}</td>
<td class="texto_p">{{$necp->endereco}} - {{$necp->cidade}}</td>
<td class="texto_p">{{$necp->obs}}</td>
<!--<td class="texto_p">{{$necp->distancia}}</td>-->
<td>
<form action="" method="post">
#csrf
<button type="submit" class="btn btn-sm btn-conectar bi-arrow-repeat texto_p"> Conectar</button>
<input value="{{$part->id}}" name="id_part_t" type="hidden">
<input value="{{$necp->id_nec_part}}" name="id_nec_part_t" type="hidden">
</form>
</td>
</tr>
</div>
#endforeach
#else
<td><td>Nenhum registro encontrado</td></td>
#endif
</tbody>
</table>
#endif
The name attribute for your hidden inputs need to be unique. you can post the fields as an array like so:
#foreach($necps as $necp)
<input value="{{$necp->id_part}}" name="parts[{{ $loop->index }}][id]" type="hidden">
<input value="{{$necp->latitude}}" name="parts[{{ $loop->index }}][latitude]" type="hidden">
<input value="{{$necp->longitude}}" name="parts[{{ $loop->index }}][longitude]" type="hidden">
<input value="{{$necp->nome_part}}" name="parts[{{ $loop->index }}][nome_part]" type="hidden">
<input value="{{$necp->endereco}}" name="parts[{{ $loop->index }}][endereco]" type="hidden">
#endforeach
with $loop->index as array key you post 1 array for every $necp

Thymeleaf binding a selected value from a table

I'm having a table with multiple elements that are generated from a List and every table element from that list has a button.By clicking that button there is a post submit request which should bind the values from that table data element to a #ModelAttribute object in spring boot.
The problem is that i'm able to map the whole list but I want to bind only the table element where the button was pressed.
<div class="table-responsive">
<form th:action="#{/saveAd}" th:object="${object}" method="POST">
<table class="table table-sm table-hover">
<thead class="thead-dark">
<tr>
<th>Image</th>
<th>Title</th>
<!-- <th style="width: 16.66%">Link</th> -->
<th>Price</th>
<th>City</th>
</tr>
</thead>
<tbody id="myTable">
<th:block th:each="element, itemStat: *{lista}">
<tr
th:onclick="'javascript:rowClicked(\'' + *{lista[__${itemStat.index}__].url} + '\');'">
<input type="hidden" readonly="readonly"
th:name="?"
th:value="${element.getUrl()}" />
<td>
<input type="hidden" readonly="readonly" th:name="img" th:value="${element.getImg()}" />
<img th:src="*{lista[__${itemStat.index}__].img}" class="size" name="img" />
</td>
<td>
<input type="hidden" readonly="readonly" th:name="?" th:value="${element.getTitle()}" />
<span th:text="*{lista[__${itemStat.index}__].title}"></span>
</td>
<td>
<input type="hidden" readonly="readonly" th:name="?" th:value="${element.getPrice()}" />
<span th:text="*{lista[__${itemStat.index}__].price}"></span>
</td>
<td>
<input type="hidden" readonly="readonly" th:name="?" th:value="${element.getCity()}" />
<span th:text="*{lista[__${itemStat.index}__].city}"></span>
</td>
<td><input class="btn btn-danger" type="submit"
value="Save"></td>
</tr>
</th:block>
</tbody>
</table>
</form>
</div>
The Controller:
#RequestMapping(path = "/saveAd", method = RequestMethod.POST)
public String saveAd(#ModelAttribute("Value") ListCreationAutovitDto listCreationAutovitDto) {
return "home";
}
I have a hidden input type for every td which should map the values but i've tried naming it in different ways but i can't make it work.Are there any ways to bind only the values where the button was pressed?
Idea 1: Make each td contain a form pointing to your controller method. Then bind the values you want to pass to the model by using hidden input fields in the form. Each button would then do a submit for the form it is in.
Idea 2: If you're mapping json to your java objects in your app, you can construct the json request body in JavaScript to contain only the stuff you want for that request

Form submit button in table without function

Can anyone explains me, why the submit buttons no and yes in the following code not trigger?
Without the table, it works.
<table class="table">
<thead>
<tr>
<th scope="col">Group</th>
<th scope="col">Yes No</th>
</tr>
</thead>
#foreach($invitations as $invitation)
{!! Form::open(array('route'=>'store.groupentry')) !!}
<tbody>
<tr>
<td>
Do you want to enter group {{$invitation->group_name}}?
</td>
<td>
<input type="hidden" name="idgroup" value="{{ $invitation->idgroup }} "/>
<input type="hidden" name="groupname" value="{{ $invitation->group_name }} "/>
<button type="submit" class="btn btn-default" name = "submitbutton" value = "save">Yes</button>
<button type="submit" class="btn btn-default" name = "submitbutton" value = "nosave">No</button>
{{ csrf_field() }}
</td>
</tr>
</tbody>
{!! Form::close() !!}
#endforeach
</table>
Maybe not valid html generation. You generate many forms wrap many tbody in one table. I think you need create one form, and before submit set hidden values with js

Spring MVC4 + Thymeleaf Form data to Controller

I am working on a Spring MVC4 application that uses Thymeleaf as a templating engine. I have a table with team member information that has an embedded form in each row with a delete button to allow deleting a user by row. below is the table section and a screenshot of what it currently looks like...
<table class="bordered">
<thead>
<tr>
<th data-field="id">Name</th>
<th data-field="name">Password</th>
<th data-field="price">Email</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${users}">
<td th:text="${user.userName}">Name</td>
<td th:text="${user.password}">Password</td>
<td th:text="${user.email}">Email</td>
<td>
<!-- Submit the user to be deleted -->
<form th:object="${user}" class="col s12" action="/deleteUser" method="post">
<button class="btn waves-effect waves-light red col" type="submit" name="deleteUser">
Delete
</button>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
</form>
</td>
</tr>
</tbody>
</table>
When I click the delete button my TeamController picks up the request but all the instance variables are null, I'm fairly new to Spring MVC4 and Thymeleaf so not sure if this is a valid approach or not? I am assuming that the object in the form is a reference to the user object in the row so not sure why its coming null on the controller side?
Note: the user object I am passing in the form is an instance of UserAccount.java that lives in the Model.
Was able to fix it with below updates to my form...
<td>
<!-- Submit the user to be deleted -->
<form th:object="${UserAccount}" class="col s12" th:action="#{/deleteUser}" method="post">
<button class="btn waves-effect waves-light red col" type="submit" name="deleteUser">Delete</button>
<input type="hidden" id="userName" name="userName" th:value="${user.userName}" />
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
</form>

Can parsley.js work with knockout.js?

I just learned about parsley.js and I'm trying to add it's validation capabilities to my project that is already wired up with knockout.js bindings. Here is the markup:
<form id="form-add-gift" data-bind="submit: addGift" data-validate="parsley">
<table class="table table-striped">
<thead>
<tr>
<th>Gift</th><th>Description</th><th>Url</th><th></th>
</tr>
</thead>
<tfoot>
<tr>
<td><input id="txtName" name="txtName" type="text" data-required="true" data-bind="value: newGift().name" /></td>
<td><input id="txtDescription" name="txtDescription" type="text" data-bind="value: newGift().description" /></td>
<td><input id="txtUrl" name="txtUrl" type="text" data-type="url" data-bind="value: newGift().url" /></td>
<td><button id="btnAdd" name="btnAdd" class="btn" type="submit" data-bind="disable: newGift().name.length > 0">Add gift</button></td>
</tr>
</tfoot>
<tbody data-bind="foreach: gifts">
<tr>
<td id="tdName" data-bind="text: name"></td>
<td id="tdDescription" data-bind="text: description"></td>
<td id="tdUrl" data-bind="text: url"></td>
<td><a id="btnRemove" class="btn btn-danger" href="#" data-bind="disabled: $parent.isClaimed, click: $parent.removeGift">Remove</a></td>
</tr>
</tbody>
</table>
</form>
When I click the "Add gift" button, my knockout.js addGift() function fires and the parsley.js validation occurs afterward. Obviously this is incorrect. Is there any way to get parsley.js to play nice with the knockout.js bindings?
I don't think parsley.js meant to work directly with KnockoutJs, but this can't stop you from using them both nicely.
Quick look through the Documentation -> Javascript - > Form you can use this method:
$('#form').parsley('isValid');
Useful if you want to integrate the form validation process inside
custom functions, without triggering error messages.
UPDATE
you can try this too:
$( '#form' ).parsley( 'validate' );
Useful if you want to integrate the form validation process inside
custom functions.

Resources