How to populate a form:select and select a default value? - spring

I have an edit user form which has textfields(username, lastname..) and a select of countries. I'm having problems with this select because i don't know the better way to populate it. I've tried populating with jquery with success but i cannot select a default value through commandName.
<form:form method="POST" commandName="user" action="registerUser.html">
<form:errors path="*" cssClass="errorblock" element="div" />
<spring:message code="app.user.username"/><form:input path="username" /><form:errors path="username" cssClass="error" /><br/>
<spring:message code="app.user.firstname"/> <form:input type="text" path="firstName" /> <form:errors path="firstName" cssClass="error"/><br/>
<spring:message code="app.user.password"/> <form:input type="password" path="password" /><form:errors path="password" cssClass="error"/><br/>
<spring:message code="app.user.repassword"/> <form:input type="password" path="confirmPassword" /><form:errors path="confirmPassword" cssClass="error"/><br/>
<spring:message code="app.user.email"/> <form:input type="text" path="email" /><form:errors path="email" cssClass="error"/><br/>
<spring:message code="app.user.country"/> <form:select path="isoCode" items="${countryList}"/><form:errors path="isoCode" cssClass="error"/><br/>
<input type="submit" value="Enviar" />
</form:form>
I've take a look to this tutorial, so i've tried with a map but i don't know how to return the data to be accesible in the jsp because in the tutorial uses a SimpleFormController but i wouldn't like to code a SimpleFormController for each form. This is my controller to return the view of the form and i have another to catch the submit.
#RequestMapping(method=RequestMethod.GET, value="/editUserForm")
public String recordUserRequestHandler(ModelMap model) throws Exception {
model.addAttribute("user", new User());
Map<String, Map<String, String>> referenceData = new HashMap<String, Map<String, String>>();
Map<String, String> country = new LinkedHashMap<String, String>();
country.put("US", "United Stated");
country.put("CHINA", "China");
country.put("SG", "Singapore");
country.put("MY", "Malaysia");
referenceData.put("countryList", country);
return "EditUserForm";
}
is it possible to pass the referenceData to the jsp to be accessed by the form:select?
<spring:message code="app.user.country"/> <form:select path="isoCode" items="${countryList}"/><form:errors path="isoCode" cssClass="error"/><br/>

Also you don't need to use hashmap for selects. Personally I use simple List with beans which holds my select options.
public class ListOption {
private String id;
private String name;
public ListOption(String id, String name) {
this.id = id;
this.name = name;
}
public ListOption() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
in your controller
List<ListOption> selectOptions = new List<ListOption>();
// add Your options
selectOptions.add(new ListOption("id","value");
then put isoCode object into your model with desired (selected) value then spring will manage to mark the value as selected.
in your jsp
<form:select path="isoCode" items="${countryList}" itemValue="id" itemLabel="name"/>

Related

Model attribute value is not passed to input type text in Thymeleaf

I'm trying to set model attribute(entryNumber) value to input type text in Thymeleaf. But input value is always empty though the entryNumber value is present.
Empty Entry Number field
Please see my AllocationController, LedgerDto and receive-allocation.html files.
AllocationController
/**
* This method allows to enter receive allocation details.
*/
#GetMapping("/admin/receive-allocation")
public String receiveAllocation(final ModelMap model) {
model.addAttribute("entryNumber", allocationService.getLedgerEntryNumber());
model.addAttribute("votes", allocationService.getAllVotes());
model.addAttribute("divisions", userService.getAllDivisions());
return "receive-allocation";
}
When I'm debugging the application, entryNumber is present in the ModelMap. Refer the below image.
entryNumber is present in the ModelMap
LedgerDto
public class LedgerDto {
#NotEmpty
private String voteNumber;
#NotEmpty
private String division;
#NotEmpty
private String entryNumber;
public String getVoteNumber() {
return voteNumber;
}
public void setVoteNumber(String voteNumber) {
this.voteNumber = voteNumber;
}
public String getDivision() {
return division;
}
public void setDivision(String division) {
this.division = division;
}
public String getEntryNumber() {
return entryNumber;
}
public void setEntryNumber(String entryNumber) {
this.entryNumber = entryNumber;
}
receive-allocation.html
<form th:action="#{/admin/receive-allocation}"
th:object="${ledgerDto}" method="post">
<div class="form-row">
<div class="form-group col-md-2"
th:classappend="${#fields.hasErrors('entryNumber')}? 'has-error':''">
<label for="inputEntryNumber">Entry Number</label> <input
type="text" class="form-control"
th:field="*{entryNumber}">
<p class="error-message"
th:each="error: ${#fields.errors('entryNumber')}"
th:text="${error}">Validation error</p>
</div>
Please help me to solve this.
It is not possible to use th:field when you want to prefill your form with values from your model attribute. In this case you have th:with in combination th:value
<form name='form' action="#" th:action="#{/internal/user/account/datachange}" method='POST' th:object="${userDTO}">
<table>
<tr>
<td><label for="name">Name:</label></td>
<td><input type="text" name="name" id="name" th:with="name=*{name}" th:value="${user.name}" required></td>
</tr>
</table>
</form>

Spring boot+Web mvc+JPA using CrudRepository giving issue on insert of a row using save method throwing EntityExistsException

Among CRUD operation Create is giving error of "A different object with the same identifier value was already associated with the session" Rest all (Read, Update and Delete) is working fine.
Im using oracle sql as database and there is one more entity of product with many to one mapping with categories class.
EntityClass
#Entity
public class Categories {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
public Categories() {
super();
}
public Categories(Integer id,String name) {
this.id=id;
this.name=name;
}
public Categories(String name) {
this.name=name;
}
//with setters and getters
}
JSP page
<body onload="document.getElementById('name').disabled = true;document.getElementById('hidden').disabled = true;">
<div align="center">
<h4>Add or Modify or Delete Categories</h4>
<form:form method="POST" action="/categories" modelAttribute="categories">
<table>
<tr>
<td><form:label path="name">Name</form:label></td>
<td>
<form:select path="name">
<form:option value="NONE" label="Select" />
<form:options items="${categoriesList}" />
</form:select>
</td>
</tr>
<tr>
<td>Operations</td>
<td>
<input type="radio" name="Ops" value="Add" checked="checked" onclick="document.getElementById('name').disabled = true; document.getElementById('newName').disabled = false;document.getElementById('hidden').disabled = true;">Add</input><br/>
<input type="radio" name="Ops" value="Modify" onclick="document.getElementById('name').disabled = false; document.getElementById('newName').disabled = false;document.getElementById('hidden').disabled = true;">Modify</input><br/>
<input type="radio" name="Ops" value="Delete" onclick="document.getElementById('name').disabled = false; document.getElementById('newName').disabled = true;document.getElementById('hidden').disabled = false;">Delete</input><br/>
</td>
</tr>
<tr>
<td>Name</td>
<td><input type="text" name="newName" id="newName"/>
<input type="hidden" id="hidden" name="newName" value="dummy"/>
</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Submit" /></td>
</tr>
</table>
</form:form>
</div>
</body>
Controller Class
#Controller
public class CategoriesController {
#Autowired
private CategoriesService cservice;
#RequestMapping(value = "/categories", method = RequestMethod.GET)
public ModelAndView categories() {
// view name model
ModelAndView modelAndView = new ModelAndView("categories", "categories", new Categories());
return modelAndView;
}
#RequestMapping(value = "/categories", method = RequestMethod.POST)
public String opsOnCategories(#ModelAttribute("categories") Categories cat,#RequestParam("Ops") String ops,#RequestParam("newName") String name)
{
if(ops.equals("Modify"))
{
cservice.modifyCategory(new Categories(Integer.parseInt(cat.getName()), name));
}else if(ops.equals("Add"))
{
cservice.addCategory(new Categories(name));
}else
{
cservice.deleteCategory(Integer.parseInt(cat.getName()));
}
return "categories";
}
#ModelAttribute("categoriesList")
public Map<String, String> getCategoryList() {
Map<String, String> categoriesList = new HashMap<String, String>();
List<Categories> ls=cservice.getAll();
for(int i=0;i<ls.size();i++)
{
categoriesList.put(ls.get(i).getId().toString(), ls.get(i).getName());
}
return categoriesList;
}
}
Can anyone please help on this.
Previous one due to which there was error
insert into CATEGORIES(ID,NAME) values (1,'Mobile');
insert into CATEGORIES(ID,NAME) values (2,'Laptop');
**Changes made to remove error*
insert into CATEGORIES(ID,NAME) values (hibernate_sequence.nextval,'Mobile');
insert into CATEGORIES(ID,NAME) values (hibernate_sequence.nextval,'Laptop');
My initial guess is that there something wrong with #Id #GeneratedValue with Oracle Database specifically.
There are couple of things that you can do:
1- Try to connect to any other Database type just to test the functionality - so that you can rule out what doesn't matter
2- Try to use the #org.springframework.data.annotation.Id alongside with the #Id of javax persistence
Something that look like this
#Id
#org.springframework.data.annotation.Id
private Integer id;
3- Create a class that Generates random Integer Ids and refer to it using the annotations (#GenericGenerator & #GeneratedValue)

hibernate validation not working while one-to-one mapping in between two entities

During form submission, if there is any validation error then form shows the errors messages under the fields. But the actual problem is in another place. I have two entities User and UserDetails. These entities are mapped with each other by bidirectional one-to-one mapping. Validation is working only with the User entity fields but not with the UserDetails entity.
Spring - 5.0.2`
Hibernate - 5.2.10
User.java
#Entity
#Table(name="users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#NotEmpty(message="{common.error.msg}")
private String first_name;
#NotEmpty(message="{common.error.msg}")
private String last_name;
#NotEmpty(message="{common.error.msg}")
private String status;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "user", fetch = FetchType.LAZY)
private UserDetails userDetails;
//Getter and setter methods
}
UserDetails.java
#Entity
#Table(name="user_details")
public class UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int user_id;
#NotEmpty(message="{common.error.msg}")
private String address;
#NotEmpty(message="{common.error.msg}")
private String mobile;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id")
private User user;
//Getter and setter methods
}
Get and Post methods in the controller class
#GetMapping(value="/create")
public String loadUserForm(Model model) {
model.addAttribute("command", new User());
return "backend/oms/user/form"; //JSP
}
#PostMapping(value="/create")
public String Save(#Valid #ModelAttribute("command") User user, BindingResult br, Model model, HttpSession session, RedirectAttributes ra) {
if(br.hasErrors()) {
return "backend/oms/user/form"; //JSP
} else {
try {
int id = userService.save(user);
if(id > 0) {
ra.addFlashAttribute("flash_msg", "ok|User added!");
return "redirect:/oms/user/edit/"+id;
} else {
return "backend/oms/user/create"; //JSP
}
} catch (ConstraintViolationException ex) {
model.addAttribute("err", "Something wrong! Please try again.");
return "backend/oms/user/form"; //JSP
}
}
}
messages.properties
common.error.msg=This field is required!
form.jsp
<form:form action="/oms/user/create" method="post" modelAttribute="command">
<label>First Name</label>
<form:input path="first_name" class="form-control" placeholder="First Name" value="" />
<form:errors cssClass="error" path="first_name" />
<label>Last Name</label>
<form:input path="last_name" class="form-control" placeholder="Last Name" value="" />
<form:errors cssClass="error" path="last_name" />
<label>Mobile</label>
<form:input path="userDetails.mobile" class="form-control" placeholder="Mobile" value="" />
<form:errors cssClass="error" path="userDetails.mobile" />
<label>Address</label>
<form:textarea path="UserDetails.address" class="form-control" placeholder="Address" value="" />
<form:errors cssClass="error" path="userDetails.address" />
<label>Status</label>
<form:select class="form-control" path="status">
<option value="">Choose...</option>
<option value="E">Enable</option>
<option value="D">Disable</option>
</form:select>
<form:errors path="status" cssClass="error"/>
<input type="submit" class="btn btn-primary" value="Save" />
</form>
Please see the screenshot
As you can see the image only fields from the User entity is validating but fields those are from the UserDetails are not validating. Please help.
It is solved now. #Valid annotation solved my problem. I need to put #Valid annotation before the entity variable declaration like below --
#OneToMany(mappedBy="majorHead", cascade = CascadeType.ALL)
#Valid
private List<MinorHead> minorHead = new ArrayList<MinorHead>();

Using thymeleaf to post form data to a Controller that uses #ModelAttribute (complex objects)

There is the Element class:
public class Element {
private Long id;
private Name name;
// Getters and Setters ...
}
And the Name class:
public class Name {
private String en;
private String fr;
private String de;
// Getters and Setters ...
}
There is a getElementsController:
#GetMapping("/elements/create")
public String getElementsCreate() {
return "private/new-element";
}
There is a NewElementController controller:
#PostMapping("/elements/create")
public String postElementsCreate(#ModelAttribute Element element) {
System.out.println(element)
return null;
}
There is a form that posts data to the NewElementController:
<form method="post" th:object="${element}" th:action="#{/elements/create}">
<input type="text" value="1" name="id" placeholder="Id"/>
// How should I make the input fields for:
element.name.en ?
element.name.fr ?
element.name.de ?
<button type="submit">Save element</button>
</form>
Setting the Id works, but I can not access the name field (it is an object)
I have tried with th:field="*{name}" and with th:field="*{name.en}", but it does not work in that way.
Try following:
<form method="post" th:object="${element}" th:action="#{/elements/create}">
<input type="text" name="id" th:value="*{id}" placeholder="Id"/>
<input type="text" name="name.en" th:value="*{name.en}" placeholder="Name (EN)"/>
<input type="text" name="name.fr" th:value="*{name.fr}" placeholder="Name (FR)"/>
<input type="text" name="name.de" th:value="*{name.de}" placeholder="Name (DE)"/>
<button type="submit">Save element</button>
</form>
Yor controller method for GET should be like this:
#GetMapping("/elements/create")
public String getElementsCreate(Model model) {
Element element = new Element();
Name name = new Name();
element.setName(name);
model.addAttribute("element", element);
return "private/new-element.html";
}

listing values in spring

I am doing following
List list=new ArrayList();
list.add(new String[] {"1","java"});
model.addAttribute("tagList", list);
And in view
<form:select path="probTag">
<form:options items="${tagList}" itemLabel="${tagList[0]}" itemValue="${tagList[1]}"/>
</form:select>
but this is not working. What else can be done to solve the problem ???
<form:options> can't work with arrays this way. Use either a class to encapsulate option
class Tag {
public String id;
public String name;
public Tag(String id, String name) {
this.id = id;
this.name = name;
}
}
-
list.add(new Tag("1","java"));
-
<form:select path="probTag">
<form:options items="${tagList}" itemLabel="name" itemValue="id" />
</form:select>
or iterate over the options manually
<form:select path="probTag">
<c:forEach var = "t" items = "${tagList}">
<form:option value="${t[0]}">${t[1]}</form:option>
</c:forEach>
</form:select>

Resources