ModelAttribute Doesn't return any value from front end to back end - spring

I'm using spring boot and thymeleaf to create a form to collect the data from front-end and update the database at back-end. I'm having trouble to pass the object value by using ModelAttribute. I can almost guaranty my repository and my bean work fine because I have written Junit test case against it and I can see the update from DB. I tried to use th:field at the html page, but it doesn't give me any default value in the field, so I have to use th:value. The print out statements in the controller just keep return 0. It feels like (#ModelAttribute("city") CityBean city) just never pass any data into the variable city. I can't really tell where the problem is after hours of the debugging. I will attach my code here. Thank you very much for helping.
My bean:
public class CityBean {
int cityID;
int population;
String cityName;
String state;
My Repository/DAO:
public int updatePopulation(CityBean city) {
String sql = "UPDATE CITY SET population = ? WHERE cityID = ?";
Object[] args = {city.getPopulation(), city.getCityID()};
int[] types = {Types.VARCHAR, Types.INTEGER};
return jdbcTemplate.update(sql, args, types);
}
My controller:
#RequestMapping(value = "/action", method = RequestMethod.POST)
public String updatePopulation(#ModelAttribute("city") CityBean city) {
System.out.println("This is city ID " + city.getCityID());
System.out.println("This is city population " + city.getPopulation());
cityRepository.updatePopulation(city);
return "redirect:/cityInfo";
}
My Front-end HTML:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>CS6400 Fall 2020 Team 017 Project</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
</head>
<body>
<h1 style="text-align:center">City Population Update Form</h1>
<br>
<form action="#" th:action="#{/action}" th:object="${city}" method="post" modelAttribute="city">
>
<table class="table">
<thead>
<tr>
<th scope="col">City ID</th>
<th scope="col">City Name</th>
<th scope="col">State</th>
<th scope="col">Population</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
<tr >
<td><input type="text=" th:value="*{cityID}" readonly="readonly"></td>
<td><input type="text=" th:value="*{cityName}" readonly="readonly"></td>
<td><input type="text=" th:value="*{state}" readonly="readonly"></td>
<td><input type="text=" th:value="*{population}" ></td>
<td>
<button type="submit" class="btn btn-primary">Update Population</button>
</td>
</tr>
</tbody>
</table>
</form>
</body>
</html>

Problem solved, I added name="pramName" in the input tag then everything works fine.

Related

findAll() in spring boot

When I try to select all details of my database, I don't get data s into a table structure in my jsp page. The array is printed in my jsp but don't know how to make it single objects.
Here is my mapping
#RequestMapping("/viewall")
public ModelAndView findAll(ModelAndView mav){
List<aswathyDTO>li= dao.findAll();
for (aswathyDTO aswathyDTO : li) {
System.out.println(li);
}
mav.addObject("li",li);
mav.setViewName("li");
return new ModelAndView("displayall.jsp","li",li);
}
and here is my jsp page
<body>
${li }
<table>
<tr>
<th>id</th>
<th>name</th>
<th>age</th>
<c:forEach items="${li}" var="li">
<tr>
<td>${li.id}</td>
<td>${li.name}</td>
<td>${li.age}</td>
</tr>
</c:forEach>
</table>
</body>
Your JSP should look like this:
<body>
<table>
<tr>
<th>id</th>
<th>name</th>
<th>age</th>
<c:forEach items="${li}" var="element">
<tr>
<td>${element.id}</td>
<td>${element.name}</td>
<td>${element.age}</td>
</tr>
</c:forEach>
</table>
</body>
Also make sure that you import the standard library:
<%# taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>

How to Load Data From a Json Using Thymeleaf Template

I have a rest api returns a Json value as a Output of the service call.
eg:- https://localhost:8080/getEmployees/loadAll
this returns following json values
eg:-
{
"employees":[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName":"Jones"}
]
}
I need to load the following json values to my thymeleaf table.
In normal way returning values in controller using modal in spring can retun values as list like following.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Employee List</title>
</head>
<body>
<h1>Welcome</h1>
<br>
<h3>Employee List</h3>
<br />
<table border="1">
<tr>
<td>Employee First Name</td>
<td>Employee Last Name</td>
</tr>
<tr th:each="emp : ${empList}">
<td th:text="${emp.firstName}">First Name</td>
<td th:text="${emp.name}">Last Name</td>
</tr>
</table>
</body>
</html>
is there a way to accomplish this using above json using thymeleaf?
You can do something like that using the following structure.
When you call the service
https://localhost:8080/getEmployees/loadAll
you will need to pass the employees data using model.addAttribute.
For instance, let's say you have the following method:
#RequestMapping(value="/getEmployees/loadAll")
String getAllEmployees(Model model) {
model.addAttribute("empList", <your service here that generates the data>);
return "pagenamehere";
}
The above method, will only be executed when you make a call using the following url: https://localhost:8080/getEmployees/loadAll
and it will add your empList data as an attribute. Then, the return string indicates the name of the page that will load. You will need to use your own page with the thymeleaf code.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Employee List</title>
</head>
<body>
<h1>Welcome</h1>
<br>
<h3>Employee List</h3>
<br />
<table border="1">
<tr>
<td>Employee First Name</td>
<td>Employee Last Name</td>
</tr>
<tr th:each="emp : ${empList}">
<td th:text="${emp.firstName}">First Name</td>
<td th:text="${emp.lastNname}">Last Name</td>
</tr>
</table>
</body>
</html>
Now, thymeleaf will be able to display the given data.
I think that you are a little confused. Thymeleaf templates are compiled on server side generating html code. Then, no thymeleaf code found on client side.
The json data got of the api response is generated on client side.
One way is use javascript to load the api response data into a html table.
Another way can you take is modify the controller that calls to the thymeleaf template to get the JSon value. If you store this response (on an object List named empList on your example) yo can add the object into the Controller response (Model or ModelAndView objects) as a template attribute.

Spring Boot And Thymeleaf remain on the same page on post request is made

I've created an web app that searches for online car ads and populates the page with a few tables after a post request.It looks like this:
After Search:
Every table element has a save button which should save those values to the database but my problem is that the page gets refreshed after submitting a post request. How can I do this without refreshing the page?
Table:
<form th:action="#{/saveAd}" method="POST">
<table class="table table-sm table-hover">
<thead class="thead-dark">
<tr>
<th>Imagine</th>
<th>Titlu Anunt</th>
<!-- <th style="width: 16.66%">Link</th> -->
<th>Pret</th>
<th>Oras</th>
</tr>
</thead>
<tbody id="myTable">
<th:block th:each="element : ${lista}">
<trth:onclick="'javascript:rowClicked(\'' + ${element.url} + '\');'">
<td><img th:src="#{${element.img}}" class="size" /></td>
<td th:text="${element.title}"></td>
<td th:text="${element.pret}"></td>
<td th:text="${element.oras}"></td>
<td><input class="btn btn-danger" type="submit"value="Save"></td>
</tr>
</th:block>
</tbody>
Controller:
#RequestMapping(path = "/saveAd", method = RequestMethod.POST)
public String saveAd(#ModelAttribute("adValue") AdValue adValue) {
System.out.println(adValue.getImg());
System.out.println(adValue.getLink());
System.out.println(adValue.getOras());
System.out.println(adValue.getPret());
System.out.println(adValue.getTitle());
return "home";
}
And also, how could I bind the list to a model object after pressing the save button?
I guess you may like this project. It is similar with what you need :
https://github.com/adinafometescu/tutorials/tree/master/spring-elasticsearch
You can use .bootstrapTable(). It a very method to update dynamically your table.
<table id="car-table" class="table table-striped">
<thead>
<tr>
<th data-field="id">Id</th>
<th data-field="title">Title</th>
<th data-field="price">Price</th>
<th data-field="city">City</th>
<th data-width="10" data-formatter="saveButtonFormatter"/>
</tr>
</thead>
</table>
The beauty is that it will map the data-field to a java object.
js stuff:
function saveButtonFormatter(value, row, index){
var adId = row.id;
return "<button class=\"btn btn-danger \" data-title=\"Save\"
data-toggle=\"modal\" onclick=\"saveAd(\'"+adId+"\')\"
</button>"
}
The function saveAd(adId) will call the rest endpoint and will update the bootstrap table on success.
I see that in your thymeleaf you don't have inputs. I suggest to not post your entire object if you don't need user input, just the id.
// anotate the controller class with #RestController
#Autowired
AdService adService;
#PostMapping(path = "/ad/{id}")
public ResponseEntity<?> saveAd(#PathVariable("id") String id) {
adService.saveAd(id);
return new ResponseEntity<>(HttpStatus.ACCEPTED);
}
P.S : don't write code in Romanian :D

ModelAttribute not working with lists in spring

I want to bind a List using ModelAttribute. The list contains objects of type Transaction each of which contains transactionid (type int). This is my controller code:
#RequestMapping(value = "/approvecreditdebit.do", method = RequestMethod.POST)
public ModelAndView doActions(HttpServletRequest request,
#ModelAttribute("clc") Clc transactionList, BindingResult result,
ModelMap model) {
/*
* switch (action) { case "approve":
*/
System.out.println("Obj = " + transactionList.getClass());
System.out.println("Val = " + transactionList.getTransactionList());
Users users = new Users();
return new ModelAndView("internal","internal",users);
}
This is my jsp code:
<form:form action="approvecreditdebit.do" method="POST"
modelAttribute="clc">
<table border="1">
<tr>
<th>no</th>
<th>ID</th>
</tr>
<c:forEach items="${clc.transactionList}"
var="transaction" varStatus="status">
<tr>
<td>${status.index}</td>
<td><input name = "transaction[${status.index}].transactionId"
value="${transaction.transactionId}" /></td>
</tr>
</c:forEach>
</table>
<br>
<br>
<center>
<input type="submit" value="approve" />
</center>
</form:form>
This is the Clc class:
public class Clc{
private List<Transaction> transactionList;
public List<Transaction> getTransactionList() {
return transactionList;
}
public void setTransactionList(List<Transaction> transactionList) {
this.transactionList = transactionList;
}
}
The value of transactionList is not being set to the values received from the form. I receive the following error:
Request processing failed; nested exception is java.lang.NullPointerException
I tried searching for the solution on google and got a lot of solutions from stackoverflow but none of them seem to work.
Try something like this (notice the use of <form:input>). I just tried it on a simple Spring MVC app and it works (list is not null and has the values from the form when I try to access it in my POST method).
<c:forEach var="transaction" varStatus="status" items="${clc.transactionList}">
<tr>
<td>${status.index}</td>
<td><form:input path="transactionList[${status.index}].id" /></td>
</tr>
</c:forEach>

Grails - sorting g:sortableColumn with hasMany relation in scaffolding

I have 3 domain classes:
class Material {
String sku
String description
String uom
String category
String type
double standardPrice
static hasMany = [prices: Price]
static constraints = {
sku(blank:false, nullable:false)
description(blank:false, nullable:false)
}
}
class Price {
double price
static belongsTo = [material: Material, priceList: PriceList]
static constraints = {
}
}
class PriceList {
String priceListName
Date validFrom
Date validTo
Boolean isValid
//static belongsTo = [supplier: Supplier]
static hasMany =[prices: Price]
static constraints = {
}
}
my PriceList update gsp is following:
<%# page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<meta name="layout" content="main"/>
<title>Update price list</title>
</head>
<body>
<g:form name="priceListlUpdateForm" id="${priceListInstance.id}">
<div class="buttons" role="navigation">
<g:actionSubmit action="save" class="edit" value="Update" />
<g:actionSubmit action="index" class = "cancel" value = "Cancel" />
<g:actionSubmit action="delete" class ="delete" value="Delete" />
</div>
<div class="body">
<h1>Update price list</h1>
</div>
<table>
<tbody>
<td>Price list name</td>
<td>
<g:textField name ="priceListName" value="${priceListInstance.priceListName}" />
</td>
</tr>
<tr>
<td>Valid From</td>
<td>
<g:datePicker name="validFrom" precision = 'day' value = "${priceListInstance.validFrom}" />
</td>
</tr>
<tr>
<td>Valid To</td>
<td>
<g:datePicker name="validTo" precision ='day' value = "${priceListInstance.validTo}" />
</td>
</tr>
</g:form>
</tbody>
</table>
<div class="constent scaffold-list" role=main>
<h1>Materials for price list</h1>
<table>
<thead>
<tr>
<g:sortableColumn property="sku" title="SKU" />
<g:sortableColumn property="description" title="Description" />
</tr>
</thead>
<tbody>
<g:each in="${pricesInPriceList}" status="i" var="pricesRow">
<tr>
<td>${pricesRow.material.sku}</td>
<td>${pricesRow.material.description}</td>
</tr>
</g:each>
</tbody>
</table>
</div>
</body>
</html>
update in PriceList Controller is following:
def update(long id) {
PriceList row=PriceList.get(id)
def pricesInPriceList = row.prices
[priceListInstance: row, pricesInPriceList: pricesInPriceList]
//render "this is update controller"
}
Everything is working fine except sorting.
When I click sortablecolumn on sku or description sorting is not working (rows are sorted randomly).
I stuck with this sorting. Thank you for help.
Regards,
To get the sorting work, you will need to implement a list method in your controller.. The list code will look like this:
def list(Integer max) {
params.max = Math.min(max ?: 10, 100)
[priceListInstanceList: PriceList.list(params), priceListInstanceTotal:
PriceList.count()]
}
Maybe it will be useful for somebody.
I have changed my update method in PriceList controller as follows:
def update(long id) {
PriceList row=PriceList.get(id)
//default sorting
def pricesInPriceList = row.prices.sort{it.material.sku}
if (params.sort && params.order == "asc") {
pricesInPriceList.asList().sort{it.material."${params.sort}"}
}
if (params.sort && params.order == "desc"){
pricesInPriceList.asList().sort{it.material."${params.sort}"}.reverse()
}
[priceListInstance: row, pricesInPriceList: pricesInPriceList]
}
now sorting with child works perfect.

Resources