spring+ thymeleaf unable to update - spring-mvc

Hi I am working with spring MVC and thymeleaf and I am not able to update data from my controller as I have following code.The main problem I am facing is that my put method is not getting called.
#GetMapping("/{id}/edit")
public String editUser(#PathVariable("id") int id, Model model) {
logger.info("++++++++++++[edit User]\n\n" + userService.findById(id));
model.addAttribute("user", userService.findById(id));
return "user/edit";
}
#PutMapping("/{id}/edit")
public String updateUser(#PathVariable("id") int id, #ModelAttribute("user") User user, Model model) {
logger.info("\n\n+++++++++++++++++inside Update");
User toUpdate = userService.findById(user.getId());
user.setUserName(user.getUserName() != null ? user.getUserName() : toUpdate.getUserName());
user.setName(user.getName() != null ? user.getName() : toUpdate.getName());
logger.info(user.toString());
userService.updateUser(user);
model.addAttribute("user", userService.findById(user.getId()));
return "redirect:/user/" + id;
}
and my html page
<form action="#" th:action="#{/user/__${user.id}__}" method="put"
th:object="${user}">
<div class="form-group">
<label for="txtUserName">User-name</label> <input
class="form-control" id="txtUserName" placeholder="User Name"
th:feild="${user.userName}" />
</div>
<div class="form-group">
<label for="txtName">First Name</label> <input
class="form-control" id="txtName" placeholder="Full Name"
th:feild="${user.name}" />
</div>
<div class="form-group">
<label for="calDob">Date of Birth</label> <input
class="form-control" id="calDob" placeholder="dd/MM/yyyy" />
</div>
<button type="submit" th:method="put" class="btn btn-success">Update</button>
<a href="#" th:href="#{/user/__${user.id}__}"
class="btn btn-primary">Cancel</a> <a th:method="delete"
href="javascript:deleteUser('${user.id}');" class="btn btn-danger">Delete</a>
</form>
any help will be usefull thanks

PUT is not a valid argument for method attibute of the form tag. See HTML specification.
Valid methods are GET and POST. And as it's not a REST API, you can use POST method to update.
So just update your mapping from:
#PutMapping("/{id}/edit")
to
#PostMapping("/{id}/edit")
And form tag to:
<form action="#" th:action="#{/user/__${user.id}__}/edit" method="post" th:object="${user}">

Related

How to pass a js variable to the controller in ASP.NET Core

I am sending an id in my js code and I want to pass that variable to my controller. Any advice on how I can do that?
<input class="btn_confirm" type="submit" id={i}
onclick="id_click(this.id)" value="Delete" />
var id;
function id_click(clicked_id) {
id = clicked_id;
}
I tried different things but nothing worked out.
I tried as below:
Model:
public class ReceiveModel
{
public int Id { get; set; }
public string Name { get; set; }
public string SomeKey { get; set; }
}
View:
<div class="row">
<div class="col-md-4">
<form id="form" asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<input id="1" type="submit" value="Create" class="btn btn-primary" />
</div>
<div class="form-group">
<input id="2" type="submit" value="Create" class="btn btn-primary" />
</div>
<div class="form-group">
<input id="3" type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script>
$("input[type='submit']").click(function ()
{
var tempid = this.id
var tmpInput = $("<input type='text' name='SomeKey' hidden/>");
tmpInput.attr("value", tempid );
var form = $("#form")
form.append(tmpInput)
form.submit()
})
</script>
Result:
You can lookup API requests. If you want to send one parameter as a primitive type (string, integer, etc.) you can use query strings in your API calls. For example, let's assume you have an API endpoint like this: localhost:5000/api/YourController. You can send params via API get calls like this localhost:5000/api/YourController?yourParam=<param-value>. In this example your API call type is GET.
If you want to send complex types (like classes, objects) to your controller you can lookup POST API requests.
You can find more details in this documentation.

Asp.Net Core Client side validation is not working

I am trying to use client side validation and its not working. My model is:
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
my layout used by the view has:
<script src="~/js/jquery-3.6.0.min.js" type="text/javascript"></script>
<script src="~/js/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>
<script src="~/js/jquery.validate.js" type="text/javascript"></script>
my view has:
<div class="form-group">
<label asp-for="Email"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
when I check the form html in the browser it shows:
<div class="form-group">
<label for="Email">Email</label>
<input class="form-control" type="email" data-val="true" data-val-required="The Email field is required." id="Email" name="Email" value="">
<span class="text-danger field-validation-valid" data-valmsg-for="Email" data-valmsg-replace="true"></span>
</div>
but when I click the submit button, the form is been posted to the server which means the client side validation is not working.
For some reasons you have to add asp-validation-summary just below form tag
<form id="myForm">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
.....
.....
</form>
The solution is that you should load the jquery.validate script before the unobtrusive script. Found the answer here
Uncaught TypeError: Cannot set property 'unobtrusive' of undefined

IFormFile in model is always null

I have a file upload form to be submitted.And Below is the ViewModel and it's DataAnnotations. Upon the form submit, the ModelState is getting false. When checked for File property in the ViewModel, it is null. Despite I kept the enctype="multipart/form-data, I'm still getting null.
Could anyone please help me.
public class ExcelUploadViewModel
{
/// <summary>
/// Gets or Sets the FileName
/// </summary>
[Required(ErrorMessage = "FileName is required")]
public string FileName { get; set; }
[Required(ErrorMessage = "File is required")]
[DataType(DataType.Upload)]
public IFormFile File { get; set; }
}
Controller.cs
[HttpPost]
public async Task<IActionResult> UploadExcel(ExcelUploadViewModel excelUploadModel)
{
if (ModelState.IsValid)
{
// HttpResponseMessage response;
TransactionResultBase transactionResultBase = new TransactionResultBase();
IFormFile file = Request.Form.Files[0];
}
}
And FormUpload.cshtml
<div align="left">
<form id="uploadForm" enctype="multipart/form-data" name="uploadForm" asp-action="UploadExcel" method="post" >
<div class="form-group form-group-lg form-group-sm row " >
<div class="col-sm-12 col-md-10 col-lg-10 uploadDiv" style="display: flex !important">
<label asp-for="FileName" class="col-sm-12 col-md-10 col-lg-10" style="font-size: 15px; max-width: fit-content ">File Name :</label>
<input asp-for="FileName" class="form form-control fileName"
type="text"
name="fileName"
placeholder="Enter your file name"
id="fileName" />
<span asp-validation-for="FileName" class="text-danger"></span>
<input asp-for="File" required class="form-control file" type="file" placeholder="File Name" id="file" name="uploadFile" />
</div>
</div>
<small>Please upload .xls or .xlxs or json or xml formatted files only</small>
<div class="form-group form-group-lg form-group-sm row">
<div class="col-sm-12 col-md-10 col-lg-10">
<input type="submit" class="btn btn-primary" name="submit" id="fileUploadButton" value="Upload" />
<input type="reset" class="btn btn-Gray" name="result" id="resetButton" value="Reset" />
</div>
</div>
</form>
</div>
Tag helpers produce id and name attiribute according to the model. So dont use both tag helpers and name attiribute at the same time.
If you want to use tag helper asp-for is enough.If you want to use "name" attiribute then you should use it according to your model and property name. In this situation since you used name attiribute for file input name="uploadFile" your model cannot determine which property is that, so you should correct it name="File"
Be careful it changes if you are using viewmodel in the view.

Spring ModelAttribute not biding values Tomcat 9, Spring 5 MVC

I migrated from Spring 3 to 5, upgraded to Tomcat 9. After upgrading not able to get the values from JSP to Controller. #ModelAttribute is not binding the values entered in JSP, while submitting the form.
JSP Code:
<form:form action="/login" modelAttribute="identity" id="loginForm" cssClass="clearfix nodisplay">
<div class="grouping text">
<label for="email">E-mail Address</label>
<form:input path="email" id="email" cssClass="regInput" cssErrorClass="error" />
<form:errors path="email" cssClass="errors" />
</div>
<div class="grouping text">
<label for="pwd">Password</label>
<form:password path="pwd" id="pwd" cssClass="regInput" cssErrorClass="error" autocomplete="off" />
<form:errors path="pwd" cssClass="errors" />
</div>
<div class="grouping remember">
<input type="checkbox" name="remember" id="remember" />
<label for="remember">Remember Me</label>
</div>
<div class="btns clearfix">
<span class="login-btn">
<input type="hidden" name="cookieExist" id="cookieExist" value="false" />
<button type="button" name="login" class="btn js-login-btn"><span class="pictos">K</span> Login</button>
</span>
<span class="password-forget">
I forgot my password
</span>
</div>
</form:form>
Controller Code
#Controller
public class LoginController {
#RequestMapping(method=RequestMethod.GET, value="/login")
public String loginGet(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap,
#ModelAttribute Identity identity){
// commented business logic code
return "login";
}
#RequestMapping(method=RequestMethod.POST, value="/login")
public String loginPost(HttpServletRequest request, HttpServletResponse response,
ModelMap modelMap, #ModelAttribute("identity") Identity identity, BindingResult bindingResult) {
//commented out business logic
return "dashboard";
}
#ModelAttribute("identity")
public Identity formBackingObject() {
return new Identity();
}
}
I have migrated with no webxml way, not sure what else i'm missing here?
No need of action here in the form tag. Mention method in the form tag. So chnage to:
<form:form modelAttribute="identity" method="post" id="loginForm" cssClass="clearfix nodisplay">
And also change your primary action button to:
<input type="submit" ... />

Spring Boot with Thymeleaf post list

I want to post a list of strings to my controller.
But it always only take the first selected value.
my thymeleaf html form:
<form action="/add" method="post">
<div class="form-group">
<label for="roleId">ID</label> <input type="text" class="form-control" id="roleId" name="id" required="required" />
</div>
<div class="form-group">
<label for="rolePrivileges">Privileges</label>
<select class="form-control" id="rolePrivileges" name="privileges" multiple="multiple" size="10" required="required">
<option th:each="type : ${privilegesList}" th:value="${type}" th:text="${type}">Privilege</option>
</select>
</div>
<button type="submit" class="btn btn-default">Create</button>
</form>
my controller:
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String addSomething(Model model, #ModelAttribute("id") String id,
#ModelAttribute("privileges") List<String> privileges) {
// add something with a service
return "redirect:/roles";
}
I think you have to Annotate the privilges with
#RequestParam("privileges")
It is not a ModelAttribute but you receive it from the request
Edit: two SO threads to better understand the difference between #RequestParam and #ModelAttribute.

Resources