Thymeleaf + Spring MVC - selected date field on HTML5 is null on controller - html

The following input field for a date object works, apparently, nicely. But when it reaches the controller, the value for executionDate is null.
<form role="form" action="#" th:object="${pojo}" th:action="#{/scheduler/create}" method="post">
<div class="col-lg-5 col-sm-5 col-xs-10" >
<div class="well with-header">
<div class="header">
<label th:for="datepicker0">Execution Date: </label>
</div>
<div class="form-group input-group">
<input id="datepicker0" type="text" name="executionDate" th:field="*{executionDate}" class="form-control"></input>
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
</div>
</div>
</div>
// rest of the page
</form>
Relevant part of controller is:
#RequestMapping(value = "/scheduler/create", method = RequestMethod.POST)
public String createSchedulerPost(#Valid #ModelAttribute("pojo") SchedulerPojo pojo, BindingResult result, ModelMap model) {
System.out.println(pojo.getDescription());
System.out.println(pojo.isRecurrent());
System.out.println(pojo.getExecutionDate());
System.out.println(pojo.getStartDate());
System.out.println(pojo.getTerminationDate());
System.out.println(pojo.getFailStrategy());
(...) // I'm just verifying whether the SchedulerPojo pojo object has values for now...
}
The SchedulerPojo DTO is:
public class SchedulerPojo {
private String id;
private String description;
private Date executionDate;
private boolean recurrent;
private Date startDate;
private Date terminationDate;
private SchedulerFailStrategy failStrategy;
// other attributes, getters and setters
}
Other, fields as the description String and recurrent boolean checkbox inputs return the given value on the HTML.
What am I missing here?

According to Thymeleaf+Spring tutorial th:field generates code the same as you set id and name tags:
<input type="text" th:field="*{datePlanted}" />
Equivalent code :
<input type="text" id="datePlanted" name="datePlanted" th:value="*{datePlanted}" />
Maybe you need to remove id=datepicker0 to executionDate and bind the class on datepicker?
<input class="date" type="text" th:field="*{executionDate}" class="form-control"></input>
...
<script>
$(document).ready(function () {
$('.date').datepicker({dateFormat: 'dd.mm.yy'});
});
</script>

Related

Model Binding in razor page does not bind object

I have a small project where I am trying to add to the database. I get a null reference exception but I think the issue is that the model binding does not work properly.
Here is the razor :
<form method="post" class="col-sm-12" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<div class="col-sm-12">
<label>Name</label>
<span></span>
</div>
<div class="col-sm-12">
<input class="col" asp-for="Product.Name" />
<span asp-validation-for="Product.Name" class="text-danger"></span>
</div>
<div class="col-sm-12">
<label>Description</label>
</div>
<div class="col-sm-12">
<textarea cols="60" rows="5" asp-for="#Model.Product.Description"></textarea>
<span asp-validation-for="Product.Description" class="text-danger"></span>
</div>
<div class="col-sm-12 ">
<label>Image</label>
</div>
<div class="col-sm-12">
<input type="file" asp-for="Image" />
<span asp-validation-for="Image" class="text-danger"></span>
</div>
<div class="col-sm-12">
<label>Categories</label>
</div>
<select name="categorycombo" asp-for="Product.CategoryId">
<option value="">Choose Category</option>
#foreach (var category in #Model.Categories)
{
<option value="#category.Id.ToString()">#category.Name.ToString()</option>
}
</select>
<div class="col-sm-12 ">
<input type="submit" value="Add" />
</div>
</div>
</form>
And here is the OnPost method :
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return await GetPage();
}
var path = Path.Combine(_webHostEnvironment.WebRootPath, "Images/Products");
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
if (Image.Length > 0)
{
var fileStream = new FileStream(Path.Combine(path, Image.FileName), FileMode.Create);
***Product.ImageUrl = Path.Combine("Images/Products", Image.FileName);***
await Image.CopyToAsync(fileStream);
}
await _productRepo.Add(Product);
return RedirectToPage("./AddProduct");
}
on the line where I create the ImageUrl I get NullReference exception for product, and it should not be null if the binding is working properly. At the same time maybe there is something I can't see.
I forgot to add the code that does the model binding here it is :
[BindProperty]
public IEnumerable<ProductViewModel> Products { get; private set; }
[BindProperty]
public IEnumerable<CategoryViewModel> Categories { get; private set; }
[BindProperty]
public ProductViewModel Product { get; private set; }
[Required]
[BindProperty]
public IFormFile Image { get; set; }
Solved :
How ?
Simple, though I don't understand exactly why.
[BindProperty]
public ProductViewModel Product { get; private set; }
in the previous snippet we remove the private set; and replace it with set; and it works.
the reasoning I don't understand because I have the same code for a different class and that works, and the only difference between the two is that the other class does don have and IForm File in the form.
Online I found some bits of info that say that the code that does model binding is not part of the page model so adding private or internal to the property setter will prevent it from being set by the model binder.
I don't know what I am talking about but it seems like it fixed it.

Adding css class to input tag thymleaf + spring

I am new to spring + thymleaf, I have implemented a form with validation all are working fine but if form field is empty or null, I have to make the filed red. which I am not able to do. please find the code below: class name and id are renamed
My Class:
public class Comp implements Serializable {
private static final long serialVersionUID = 1L;
#JsonProperty("name")
#NotNull
#NotBlank
private String name;
#JsonProperty("accId")
#NotNull
#NotBlank
private String accId;
}
My Controller method:
#RequestMapping(value = "/companyAccountHtml", method = RequestMethod.GET)
public String companyAccount(HttpServletRequest request, Model model) {
model.addAttribute("companyAccess", new CompanyAccess());
return "addcompanyaccount";
}
#RequestMapping(value = "/addCompanyAccount", method = RequestMethod.POST)
public String addCompanyAccount(#Valid CompanyAccess companyAccess, BindingResult result,
HttpServletRequest request, Model model) {
if(result.hasErrors()){
return "addcompanyaccount";
}
return "redirect:/cred";
}
HTML:
<form id="comp" name="comp" action="#" th:action="#{/addCompanyAccount/}"
th:object="${companyAccess}" method="post" >
<div class="c" style="margin-left: auto; margin-right: auto; float: none;">
<p class="hed">Add Company Account</p>
<label for="ad">Name*</label>
<input type="text" th:field="*{name}" name="name" maxlength="40"
th:classappend="${#fields.hasErrors('name')}? has-error : ">
<label for="acc">Id*</label>
<input type="text" th:field="*{accId}" name="accId" maxlength="12"
th:classappend="${#fields.hasErrors('accId')}? has-error : ">
</div>
<div class="clear"></div>
<div class="vltl_button-wrapper">
<input type="submit" id="submitBtn" class="ccc" value=" Save "></button>
<input type="button" class="ccc" value="Cancel" onClick="document.location.href='../cred'">
</div>
</form>
CSS
.has-error{
border:1px solid red!important;
}
Getting error in th:classappend="${#fields.hasErrors('name')}? has-error : " with the input tag. If I make a use of p tag the red line is coming down of input text, I want the input box will be red if fields are blank or null. I tried th:if also which is not populating the text filed itself only on error it shows.
Please let me know how to proceed. Already a lot of CSS return on input tag
Thank you.
You need to add the false condition to your th:classappend expression. For example on the name field:
<input type="text" th:field="*{name}" name="name" maxlength="40"
th:classappend="${#fields.hasErrors('name')}? has-error : ''">
Note the empty single-quoted string after : in the th:classappend. What you have currently is an invalid ternary expression. If you used a ternary in Java it would be:
int x = booleanCondition ? 1 : ; // Error because the right side doesn't have a value
The same concept applies here.

How to show error message in login page when user fail to login with Spring Boot?

Now i am doing project with Spring Boot. I wanted to show error message when I fail to login. When I did Maven project I did it easily with BindingResult. I followed several instruction to complete the task what I wanted to do. But I couldn't get any proper solution. I need a proper solution in simplest way.
Here my Controller class
#RequestMapping(value = "/loginCheck", method = RequestMethod.POST)
public String checkLogin(#RequestParam String roll, #RequestParam String pass) {
if (studentService.existsByRollAndPass(roll, pass)) {
return "Welcome";
} else {
return "Login";
}
And my html file is
<form class="form-horizontal" method="post" action="/loginCheck">
<fieldset>
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Roll</label>
<div class="col-md-4">
<input id="textInput" name="roll" type="text"
placeholder="Roll" class="form-control input-md">
</div>
</div>
<!-- Password input-->
<div class="form-group">
<label class="col-md-4 control-label" for="password">Password</label>
<div class="col-md-4">
<input id="password" name="pass" type="password"
placeholder="password" class="form-control input-md">
</div>
</div>
<!-- Button -->
<div class="form-group">
<label class="col-md-4 control-label" for="login"></label>
<div class="col-md-4">
<button id="login" name="login" class="btn btn-primary">Login</button>
</div>
</div>
</fieldset>
</form>
You can put an error parameter to the URL like localhost:8080/login?error. Then, with the help of Thymeleaf, you can add this div to the html.
<div th:if="${param.error}" class="alert alert-danger">
Invalid username and password.
</div>
This div will be displayed if there is an error parameter at the URL.
However, you may need to change
return "Login"
to
return "redirect:Login?error";
After wasting 3 hours i solved this problem. I changed my html header
<html xmlns:th="http://www.w3.org/1999/xhtml" lang="en">
to
<html xmlns:th="http://www.w3.org/1999/xhtml" xmlns:sf="http://www.w3.org/1999/xhtml" lang="en">
And added Model in Controller class. Now my controller class is
#RequestMapping(value = "/loginCheck", method = RequestMethod.POST)
public String checkLogin(#RequestParam String roll, #RequestParam String pass, Model model) {
if (studentService.existsByRollAndPass(roll, pass))
{
return "Welcome";
}
else
{
model.addAttribute("logError","logError");
return "Login";
}
}
To catch the error I put a single line code in html file.
<span th:if="${logError != null}" class="error">Wrong user or password</span>
Everything working fine now !!!
You can also do this by implementing an AuthenticationFailureHandler and redirecting with a parameter to indicate that there was a login error.
In your class that extends WebSecurityConfigurerAdapter, in the override of the configure method, make sure to add your failureHandler
#Override
protected void configure(HttpSecurity http) throws Exception {
...
.failureHandler(getAuthenticationFailureHandler())
...
}
#Bean
public AuthenticationFailureHandler getAuthenticationFailureHandler() {
return new MyAuthenticationFailureHandler();
}
And in your class that implements AuthenticationFailureHandler (ex: MyAuthenticationFailureHandler), implement the onAuthenticationFailure method and redirect to the login page and add a parameter to the URL such as loginError=true.
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
httpServletResponse.sendRedirect("/login?loginError=true");
}
Then in your login.html page, use ${param.loginError} to check for this URL parameter.
<p class="text-danger" th:if="${param.loginError}" th:text="'Wrong username or password'"></p>

How to populate select element in thymeleaf springboot?

I am writing a web application using thymeleaf, springboot. I have one model class with id, name, address, state and district fields. I have 3 tables user table, state table with id, state_name, state_code, and district table with id, district_code, district_name, state_code.
How to map List of states to user table state field?.
Q1. When I load my newrecord view it should fatch all record from state table and populate in select element?.
Q2. When I select state from select fatch all dstrict list of that state?.
Q3. When I open same record in edit mode state and district list show its default value?.
Controller
#RequestMapping("user/new")
public String newUser(Model model){
model.addAttribute("user", new User());
return "userform";
}
#RequestMapping("user/edit/{id}")
public String update(#PathVariable Integer id, Model model){
model.addAttribute("user", userService.getProductById(id));
return "userform";
}
Model
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String address;
private String state;
private String dist;
//getter setter
}
public class State {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer state_id;
private String state_name;
private String state_code;
}
Thymeleaf view
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
</head>
<body>
<div class="container">
<h2>User Details</h2>
<div>
<form class="form-horizontal" th:object="${user}" th:action="#{/user}" method="post">
<input type="hidden" th:field="*{id}"/>
<div class="form-group">
<label class="col-sm-2 control-label">Name:</label>
<div class="col-sm-10">
<input type="text" class="form-control" th:field="*{name}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Address:</label>
<div class="col-sm-10">
<input type="text" class="form-control" th:field="*{address}"/>
</div>
</div>
**//NOTE:- These select list not working I am able to display above information not this list**
*<div class="form-group">
<label class="col-sm-2 control-label">State:</label>
<div class="col-sm-10">
<select class="form-control" name="selectState" th:field="*{state}" >
<option th:each="sopt:${state}" th:value="?" th:text="?">State</option>
</select>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Dist:</label>
<div class="col-sm-10">
<select class="form-control" name="selectDistrict" th:field="*{dist}" >
<option th:each="sopt:${dist}" th:value="?" th:text="?">Dist</option>
</select>
</div>
</div>*
<div class="row">
<button type="submit" class="btn btn-default">Submit</button>
</div>
</form>
</div>
</div>
</body>
</html>
For Q1 i got solution by using What is #ModelAttribute in Spring MVC?
#ModelAttribute("states")
public List<State> populateStates() {
List<State> listStates = new ArrayList<State>();
for (State e : stateService.listAllState()) {
System.out.println(e.getState_code());
listStates.add(e);
}
return listStates;
}
Q3 problem also solved by this when you open it in edit mode it will select your saved value
<select th:field="*{states}" id="state" onChange="onstatechange(this)" class="infobox">
<option value="0">Select Your State</option>
<option th:each="state : ${states}" th:value="${state.state_id}" th:text="${state.state_name}"></option>
</select>
For Q2 you can use ajax call or javascript onChange can solve my problem.

Spring MVC form prepopulate or get value from readonly input tag

I have a form with all fields, less one of it, filled from user. This is the class passed through the form
public class CarForm {
private String id;
private Integer initialKm;
private String carChassis;
private String note;
private String carType;
private Integer fleet;
The only one field, fleet, I would like to set before pass the form, or better, set it from HTML. For example:
<div class="form-group">
<label>Fleet application</label> <input type="text"
class="form-control" th:field="*{fleet}"
th:placeholder="${fleetApplication}" readonly="readonly">
</div>
So I would like to show ${fleetApplication.application} and set into fleet this value, or, if it is possible, set another value${fleetApplication.idFleet}.
Is it possible one of these solutions?Thanks
Update: as suggested by #Faraj Farook I resolved so:
<div class="form-group">
<label>Fleet application</label>
<!-- Show fleet application -->
<input class="form-control" type="text" th:value="${fleetApplication.application}" readonly="readonly" />
<!-- Save into fleet the value of idFleet -->
<input type="hidden" name="fleet" th:value="${fleetApplication.idFleet}" />
</div>
Setting it in the server side
controller
String action(Model model){
CarForm carForm = new CarForm();
carForm.setFleet(<some value>);
model.addAttribute("obj", carForm);
return view.html;
}
view.html
<div class="form-group">
<label>Fleet application</label>
<input type="text" th:field="*{fleet}" readonly/>
</div>
setting it in the client side
view.html
<div class="form-group">
<label>Fleet application</label>
<input type="text" readonly th:value="${someValueVariable}"/>
<input type="hidden" name="fleet" th:value="${someValueVariable}"/>
</div>