Thymeleaf iteration stuck at 0 in dynamically created form (Spring Boot) - spring-boot

I'm trying to create a table from a list phases where each row has forms that will relate to the list item phase for that row - so row 1 has a cell for "Phase 1" and then a button that will rename "Phase 1", then the next row has "Phase 2" and a button for that.
However, when I try to access the index of that list iteration from within the form it always returns 0, so the first cell of row 2 still says "Phase 2" but the form still passes the index of "Phase 1" to the HTTP request. It can definitely still see the list, because if I change it to return phaseStat.size rather than the phaseStat.indexit gives the correct number.
The cells containing the phase name work fine, it's only once I get inside the <form> tag that it gets stuck on the first item of the list. How do I get the form to keep pace with the iteration with the rest of the table?
<table class="table">
<tr th:each="phase : ${phases}">
<td class="table-light" th:text="${phase}"></td>
<td>
<form th:action="#{/tasks/phases/rename}">
<button type="button" class="btn btn-outline-primary btn-sm" title="Rename" onclick="openForm('renamephaseform')">Rename</button>
<div class="form-popup card mb-3" id="renamephaseform">
<h3 class="card-header">Rename
<button type="button" class="btn btn-outline-secondary btn-sm closebutton" title="Close menu" onclick="closeForm('renamephaseform')">⛌</button>
<br>
</h3>
<div class="card-body">
<input type="text" class="form-control" id="phasename" placeholder="Phase name" th:name="newname">
<button type="submit" class="btn btn-primary" title="Rename" th:name="phasenumber" th:value="${phaseStat.index}">Rename <span th:text="${phase}"></span></button>
</div>
</div>
</form>
</td>
</tr>
</table>
<script>
function openForm(name) {
document.getElementById(name).style.display = "block";
}
function closeForm(name) {
document.getElementById(name).style.display = "none";
}
</script>
Edit:
The weird thing is, the iteration works perfectly fine in this example and I can't see what the difference is...
<table class="table">
<tr th:each="album : ${albums}">
<td class="table-light" th:text="${album.name} + ' (' + ${album.artist} + ')'"></td>
<td>
<form th:action="#{/index}">
<button type="submit" class="btn btn-primary btn-sm" th:name="id" th:value="${album.id}">Open album</button>
</form>
</td>
</tr></table>

So, what I ended up doing that made this work (thanks to andrewJames) is including the iteration index in the form id to create a unique name.
So for the Open button I included
th:attr="onclick='openForm(\'renamephaseform' + ${phaseStat.index} + '\')'", in the Closebutton th:attr="onclick='closeForm(\'renamephaseform' + ${phaseStat.index} + '\')'" and in the form tag th:attr="id='renamephaseform' + ${phaseStat.index}".
Elswhere, I've sometimes used string values for this (eg the phase name, task name etc) to make it easier to review in the Inspector.

Related

Submit Button not getting correct route to add new data in Laravel

I am facing problem for Submit Button not getting correct route to add new data.
2 Blade file with 2 Submit Button which need to save 2 data to 2 different tables.
Problem facing - Data submitted in 1 table for both submit button....
addnewBuffalo.blade.php
<div class="box-header with-border" align="right">
<button type="submit" class="btn btn-success btn"><i class="fa fa-floppy-o"></i> <b>Add
Buffalo</b></button><a href="" class="btn btn-warning btn"><i class="fa fa-refresh">
</i> <b> Refresh</b></a>
</div>
addnewcow.blade.php
<div class="box-header with-border" align="right">
<button type="submit" class="btn btn-success btn"><i class="fa fa-floppy-o"></i> <b>Add
Cow</b></button><a href="" class="btn btn-warning btn"><i class="fa fa-refresh"></i> <b>
Refresh</b></a>
</div>
web.php
Route:: post('submit', 'App\Http\Controllers\addnewbuffaloController#addbuffaloData')
->name('submit');
Route:: post('submit', 'App\Http\Controllers\addnewcowController#addcowData')
->name('submit');
You need to create 2 separate Route Names. Having ->name('submit') for both won't work. And having the same path won't work
Route::post('submit=buffalo', 'App\Http\Controllers\addnewbuffaloController#addbuffaloData')
->name('submit-buffalo');
Route::post('submit-cow', 'App\Http\Controllers\addnewcowController#addcowData')
->name('submit-cow');
Or if the form is wrapped by one form tag then you can handle both submissions in the one Controller action
<button type="submit" name="buffalo-submission">Save Buffalo</button>
<button type="submit" name="cow-submission">Save Cow</button>
Then in the controller action code you could check
if ($request->has('buffalo-submission') {
Do buffalo code
} else if ($request->has('cow-submission')) {
do cow code
}

Update multiple cart items quantity. Spring Boot - Thymeleaf

I need help with updating a "quantity" of Product in my cart from a submit button, I'm clueless. I have successfully added the Product on the Carts page, I have an Update Button that should update the new quantity input value on the UI, just help and tips with updating the List of Cart Items when changes are been made to the quantity of the individual items. Thanks
//Iterating over the cartItems to be displayed on the carts page
<tr th:each="cartItem : ${cart.cartItems}">
<td class="product-name">
<h2 class="h5 text-black" th:text="${cartItem.product.productName}">Polo Shirt</h2>
</td>
<td>
<div class="input-group mb-3" style="max-width: 120px;">
<input type="number" class="form-control quantity text-center" th:value="${cartItem.quantity}" placeholder="" aria-label="Example text with button addon" aria-describedby="button-addon1">
</div>
</td>
<td th:text="${'₦' + #numbers.formatDecimal(cartItem.price, 0, 'COMMA', 0, 'POINT')}"></td>
<td><a th:href="${'/cart/removeCartItem/' + cartItem.cartItemId}" class="btn btn-primary height-auto btn-sm">X</a></td>
</tr>
//The update button
<div class="col-md-6 mb-3 mb-md-0">
<button class="btn btn-primary btn-sm btn-block">Update Cart</button>
</div>

Spring + Thymeleaf - Call a function using received parameter

I have a table filled with a List of String that I receive from a controller, and then I want to put a button for each one to call to another function and get some objects related with that string.
<tbody th:each="titulo : ${listaColecciones}">
<tr>
<th th:utext="${titulo}"></th>
<th>
<form class="navbar-form navbar-left" action="#" th:action="#{/twittercontrolador/recuperarColeccion}" th:object="${textocoleccion}" th:value="${titulo}" method="post">
<button type="submit" class="btn btn-primary" value="Filtrar">Recuperar coleccion</button>
</form>
</th>
</tr>
</tbody>
But it seems not to work, it doesn't get the ${titulo} as a parameter for the function
Edit: Here I have a picture of what I'm trying to do:
As you can see, I get a List (Thre're database table names) in the controller from a method1, and I pass that list to the view.
There, I'm trying to put a table with 2 columns, first is the string/table name, and second is a button to call a second method which will return the objects in that table.
So, as you may suppose, the <tbody th:each="titulo : ${listaColecciones}">is the list of database table names.
<th th:utext="${titulo}"></th>
The names to know which table are you getting from the database
<form class="navbar-form navbar-left" action="#" th:action="#{/twittercontrolador/recuperarColeccion}" th:object="${textocoleccion}" th:value="${titulo}" method="post">
<button type="submit" class="btn btn-primary" value="Filtrar">Recuperar coleccion</button>
</form>
And here is where I'm getting the problems, the button. th:action="#{/twittercontrolador/recuperarColeccion}" is the second method in the controller and I don't know how to pass it the string (${titulo}) as a parameter for it.
Note that th:object="${textocoleccion}"is the name of the string I will receive in the second method but I can not set it to the value of the strings.
For all those who may have the same problem, this works for me:
<form class="navbar-form navbar-left" action="#" th:action="#{/twittercontrolador/recuperarColeccion}" th:object="${textocoleccion}" method="post" >
<button class="btn btn-success" type="submit" id="textocoleccion" name="textocoleccion" th:value="${titulo}">RECUPERAR</button>
</form>
I guess the key is to use id and name tags :D
Thanks to all
If you want to pass informations about the button you have clicked, then you should use input or button as tag and (that's important) a name and value attribute.
<input type="submit" name="somePostParamName" th:value="${titulo}" />

xpath preceding-sibling not working

I am trying to click on the first button which deletes the item which is the second button.
<tr>
<td>
<div class="btn-group">
<button class="btn btn btn-danger" name="delete" type="button">
</div>
</td>
<td>
<span class="class"></span>
</td>
<td>
<button class="btn" name="item" type="button">
</td>
</tr>
XPath
//button[contains(.,'${ITEM}')]/preceding-sibling::button[#name='delete']
I'm going to assume you're just not showing us the button text in your example HTML, since neither of your buttons seems to have any content.
preceding-sibling would not work here, since the two buttons are not siblings. However preceding::button should work in this case. Note the [1] at the end which is needed in order to select the closest match:
//button[contains(.,'${ITEM}')]/preceding::button[#name='delete'][1]
The following should also work, and is in my opinion a bit cleaner:
//tr[.//button[contains(., '${ITEM}')]]//button[#name ='delete']

Watir-Webdriver - Parsing through table and clicking start/stop toggle

Please be gentle. I'm very new to Ruby and Watir. In general also new to UI automation testing. I'm trying to parse through a table then click a toggle that start/stops an application. The applications that can be turned on and off are not set. They can range from 1 to 'infinite' number applications. I need something that will parse through each row and click the toggle. if the application is started, I need to turn it off and vice-versa. No matter how many rows exist. The row also contains an element in the first column that allows the application to be clicked and brought to another page that gives details about said application. The toggle exists in the last column of the table. Here is the HTML I'm looking at with two applications deployed. It may be something simple that I'm missing. I'm also normally an IT admin that just got thrown into this. Thanks for all the help
<table id="apps_data" class="table table-striped table-bordered table-hover ng-scope">
<thead>
<tr>
</thead>
<tbody>
<tr class="link ng-scope" ng-repeat="app in services.data | orderBy:services.sort">
<td class="ng-binding" ng-click="click_app(app.Id)">Zenoss</td>
<td class="ng-binding deploy-success" ng-class="app.deploymentClass">
<span class="glyphicon glyphicon-ok" ng-class="app.deploymentIcon"></span>
successful
</td>
<td class="ng-binding">default</td>
<td>
<div class="toggle btn-group" data-toggle="buttons">
<label class="ng-binding btn btn-success active" ng-click="clickRunning(app, 'start', servicesService)" ng-class="app.runningClass">
<input class="ng-pristine ng-valid" type="radio" value="1" ng-model="app.Running" name="running0">
started
</label>
<label class="ng-binding btn btn-default off" ng-click="clickRunning(app, 'stop', servicesService)" ng-class="app.notRunningClass">
<input class="ng-pristine ng-valid" type="radio" value="stopped" ng-model="app.Running" name="running0">
</label>
</div>
</td>
</tr>
<tr class="link ng-scope" ng-repeat="app in services.data | orderBy:services.sort">
<td class="ng-binding" ng-click="click_app(app.Id)">Zenoss</td>
<td class="ng-binding deploy-success" ng-class="app.deploymentClass">
<span class="glyphicon glyphicon-ok" ng-class="app.deploymentIcon"></span>
successful
</td>
<td class="ng-binding">default</td>
<td>
<div class="toggle btn-group" data-toggle="buttons">
<label class="ng-binding btn btn-success active" ng-click="clickRunning(app, 'start', servicesService)" ng-class="app.runningClass">
<input class="ng-pristine ng-valid" type="radio" value="1" ng-model="app.Running" name="running1">
started
</label>
<label class="ng-binding btn btn-default off" ng-click="clickRunning(app, 'stop', servicesService)" ng-class="app.notRunningClass">
<input class="ng-pristine ng-valid" type="radio" value="stopped" ng-model="app.Running" name="running1">
</label>
</div>
</td>
</tr>
</tbody>
</table>
I have this so far, but it's just going to the first line.
if ff.div(:class, 'toggle btn-group').label(:class, 'ng-binding btn btn-success active').exist?
ff.div(:class, 'toggle btn-group').label(:class, 'ng-binding btn btn-default off').click; sleep 1
ff.div(:class, 'toggle btn-group').label(:class, 'ng-binding btn btn-default off').exist?
ff.div(:class, 'toggle btn-group').label(:class, 'ng-binding btn btn-default off').click; sleep 1
end
This might do what you want:
apps = browser.table(:id => 'apps_data').tbody.trs
apps.each do |app|
set_radios = app.radios.find_all{ |radio| !radio.set? }
if set_radios.length == 2
# Neither radio button is set, so do nothing?
else
set_radios.first.set
end
end
What this does is:
Gets a collection of all tr elements in the table body. Each tr element is assumed to represent an "app".
Iterates through each row (app):
Counts the number of radio buttons that are not set.
If neither of the 2 radio buttons is set, it does nothing.
If only one unset radio button is found, it is set.
Note that since the 2 radio buttons of the app have the same name attribute value, setting the one radio button will automatically unset the other.

Resources