I have two objects a Books and an Authors. The author is a property of the Book.
Book pojo:
#Entity
#Table(name = "BOOK")
public class Books {
private Long bookId;
private String bookTitle;
private Authors author;
// Getter and Setter
}
Authors pojo:
#Entity
#Table(name = "AUTUORS")
public class Authors {
private Long authorId;
private String authorFullName;
//getter and setter
}
I need to make a form with two inputs for entering book title and Author name.
Like the following:
<form action="#" class="form" enctype="multipart/form-data" method="post"
th:action="#{/management/add-book-form}" th:object="${book}">
<div class="form-row ">
<div class="form-group col-md-3">
<input type="text" class="form-control" th:field="*{book. getBookTitle()}"
placeholder="Author full name">
<input type="text" class="form-control" th:field="*{book. getAuthor()}"
placeholder="Author full name">
</div>
</div>
</form>
delete placeholder property from input , and access to field direct by field name:
<form action="#" class="form" enctype="multipart/form-data" method="post"
th:action="#{/management/add-book-form}" th:object="${book}">
<div class="form-row ">
<div class="form-group col-md-3">
<input type="text" class="form-control" th:field="*{bookTitle}" >
<input type="text" class="form-control" th:field="*{author.authorFullName}">
</div>
</div>
</form>
*{...} expressions automatically use the th:object. So the expression *{bookTitle} roughly translates to ${book.bookTitle} and *{author.authorFullName} to ${book.author.authorFullName}
This should work for you:
<input type="text" th:field="*{bookTitle}" />
<input type="text" th:field="*{author.authorFullName}" />
Related
I'm currently making a recipe application.
Every recipe will be containing several ingredients obviously.
So I made Recipe and Ingredient as OneToMany relationship. So that I can have multiple ingredients in a single recipe.
But the problem is when I try to add recipe using thymeleaf webpage.
I want to add ingredients dynamically, I mean I want to add ingredients as much as I need for each recipe using javascript to make the input boxes for ingredients increase or decrease dynamically.
Here is my Ingredient Entity Class:
public class Ingredient {
#Id
#GeneratedValue
private int id;
private String name;
private String amount;
}
This is Recipe Entity Table
public class Recipe {
#Id
#GeneratedValue
private int id;
private String name;
private String description;
private String instruction;
private Timestamp createdTime;
#OneToMany(cascade=CascadeType.ALL)
private List<Ingredient> ingredients = new ArrayList<>();
}
These are methods for adding recipe:
#GetMapping("/addRecipe")
public String addRecipeGet(Model model) {
model.addAttribute("recipe", new Recipe());
return "add_recipe";
}
#PostMapping("/addRecipe")
public String addRecipePost(Recipe recipe) {
recipeService.createRecipe(recipe);
return "home";
}
And I tried to bind the recipe object with thymeleaf like this:
<body>
<form method="POST" th:action="#{/addRecipe}" th:object="${recipe}" class="form-signup">
<label class="form-label pt-3" for="name">Recipe Name</label>
<input id="name" name="name" type="text" class="form-control mb-3" th:field="*{name}" placeholder="Recipe Name" />
<label class="form-label pt-3" for="description">Description</label>
<textarea id="description" name="description" type="text" class="form-control mb-3" th:field="*{description}" placeholder="Description"></textarea>
<label class="form-label pt-3" for="instruction">Instruction</label>
<textarea id="instruction" name="instruction" type="text" class="form-control mb-3" th:field="*{instruction}" placeholder="Instruction"></textarea>
<ul>
<li>
<div>
<input type="text" class="form-control mb-3" th:name="???" placeholder="ex) Onion"></input>
<input type="text" class="form-control mb-3" th:name="???" placeholder="ex) 300g"></input>
</div>
</li>
</ul>
<div class="d-grid col-8 mx-auto">
<button type="submit" class="btn btn-dark">Submit</button>
</div>
</form>
</body>
I just tried to bind only one ingredient for now but it's not working obviously.. I don't know what to put in the th:field or th:name
I have no idea how to post a list of data inside an object
Is even there a way to solve this problem??
You can bind list items using th:field="*{ingredients[i].name}" or name in the same format.
See https://www.baeldung.com/thymeleaf-list for a full guide on how to handle list binding in thymeleaf
I got a MVC web page and i try to get a value from a input type="datetime-local" and save the value in th:field. to be able to save these dates and also work with them
But it seams to work only in input="text" tags, not type="datetime-local" because when i debug, the date value of the input that is type="datetime-local"
I need the client to select the Date the event its goint to start
Here is an example of the whole form and the two inputs that save the date.
Client view
[enter image description here][1]
View
<div class="container">
<div class="row">
<div class="col-md-4 mt-5">
<form th:action="#{/guardar/} + ${usuario.id_user}" method="post" th:object="${event}">
<div class="form-group">
<label for="title" >Titulo </label>
<input type="text" id="title" placeholder="Titulo" class="form-control" th:field="*{title}"/>
</div>
<div class="form-group">
<label for="e_description" >Descripción</label>
<input type='text' name="e_description" th:field="*{e_description}" placeholder="Descripcion" class="form-control"/>
</div>
<div class="form-group">
<label for="startDate">Inicio de Evento:</label>
<input type="text" id="time" placeholder="Inicio de Evento" class="form-control" th:field="*{startDate}"/>
</div>
<div class="form-group">
<label for="endDate">Termino de Evento:</label>
<div class="input-group date" id="endDate">
<input type="datetime-local" id="time2" placeholder="Termino de Evento" class="form-control" th:field="*{endDate}"/>
<div class="input-group-addon input-group-append">
<div class="input-group-text">
<i class="fa fa-clock-o"></i>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="className" >ClassName</label>
<input type="text" name="className" th:field="*{className}" placeholder="className" class="form-control"/>
</div>
<div class="form-group">
<label for="icon">Icono</label>
<input type="text" name="icon" th:field="*{icon}" placeholder="icon" class="form-control" />
</div>
<div class="form-group">
<label for="allDay">¿Todo el día?</label>
<input type="checkbox" value="true" name="allDay" th:field="*{allDay}" />
</div>
<button class="btn btn-primary" type="submit">Submit form</button>
</form>
</div>
</div>
</div>
The Controller of /guardar/} + ${usuario.id_user}
#PostMapping("/guardar/{id}")
public String guardar(#Valid Event event, Errors errores,#PathVariable int id,Model model) throws ParseException {
/* if (errores.hasErrors()) {
return "agregar";
}*/
UserPlanD userPlanD = userService.encontrarUsuarioPorId(id);
model.addAttribute("usuario",userPlanD);
event.setUser(userPlanD);
Date inicio_evento = formatter.parse(event.getStartDate().toString());
String termino_evento = event.getStartDate().toString();
event.setStartDate(inicio_evento);
List<Event> eventicos = Arrays.asList(event);
System.out.println("Evento" + event + "y usuario: " + userPlanD);
eventService.guardar(event);
/*userPlanD.setEvents(eventicos);
userService.guardar(userPlanD);*/
return "redirect:/eventos";
}
The Model is the next one:
#Table(name="event_calendar")
public class Event implements Serializable {
//private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_event")
private Long id_event;
#Column(name = "title")
private String title;
#NotEmpty
private String e_description;
#NotEmpty
#JsonFormat(pattern="yyyy-MM-dd HH:mm:ss.SSSSSS")
#Column(columnDefinition = "DATETIME")
private Date startDate;
#NotEmpty
#JsonFormat(pattern="yyyy-MM-dd HH:mm:ss.SSSSSS")
#Column(columnDefinition = "DATETIME")
private Date endDate;
#NotEmpty
private String className;
#NotEmpty
private String icon;
#NotEmpty
private String allDay;
#ManyToOne
#JoinColumn(name = "id_user")
private UserPlanD user; ```
Here its a debug result of the controller result in the line the got the next code "System.out.println("Evento" + event + "y usuario: " + userPlanD)"
[1]: https://i.stack.imgur.com/QOYfW.png
I have an Entity as
#Entity
public class Foo {
#Id
#GeneratedValue
private Integer id;
#Size(min = 5,max = 50, message = "Valid title is 5-50 chars")
private String title;
#Lob
#Column(length=1000000)
private String description;
#NotNull(message = "Location must be specified")
private String location;
// getters & setters go here
}
and I have a method to save Foo as
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String addDetail(#ModelAttribute("foo") Foo foo) {
fooService.persistFoo(foo);
return "redirect:/";
}
at this point if I submit form with invalid data I get exception as
HTTP Status 500 - Request processing failed; nested exception is javax.validation.ConstraintViolationException: Validation failed for classes [com.rhcloud.pro.entity.Foo] during persist time for groups [javax.validation.groups.Default, ]
Now I want to implement form validation as
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String addDetail(#ModelAttribute("foo") #Valid Foo foo, BindingResult bindingResult) {
if (!bindingResult.hasErrors()) {
fooService.persistFoo(foo);
return "redirect:/";
}else{
return "add";
}
}
and add.jsp is
<form:errors path="foo"/>
<form:form commandName="foo" class="form" id="add">
<div class="form-group form-group-label">
<div class="row">
<div class="col-md-10 col-md-push-1">
<label class="floating-label" for="login-username">Title</label>
<form:input name="title" path="title" cssClass="form-control" />
<span class="form-help form-help-msg text-red"><i class="form-help-icon icon icon-error"></i></span>
</div>
</div>
</div>
<div class="form-group form-group-label">
<div class="row">
<div class="col-md-10 col-md-push-1">
<label class="floating-label" for="login-username">Location</label>
<form:input name="location" path="location" cssClass="form-control" />
</div>
</div>
</div>
<div class="form-group form-group-label">
<div class="row">
<div class="col-md-10 col-md-push-1">
<label class="floating-label" for="login-username">Description</label>
<form:textarea name="description" path="description" cssClass="form-control" />
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-10 col-md-push-1">
<button
class="btn btn-block btn-blue waves-button waves-effect waves-light">Add</button>
</div>
</div>
</div>
</form:form>
now if I submit form with invalid data I don't get exception and I redirect to my add page but I don't see any error messages, but If I give correct data to form then the form is redirected to add page, I can not figure out how to get form validation done correctly.
I -> Hi I have different bootstrap modals in one page general.jsp.Modals are wrapped through c:if condition.So only one modal should be enable on general.jsp on click of button.For this I am delegating one ajax request to controller and adding Boolean variable to model attribute and returning it.
But the problem is that boolean variable is not appearing in requestScope because of which <c:if test="${requestScope.isAddCategoryAttribute}"> is not able to execute and modal is not enabling to jsp .How do I handle such scenario using ajax in spring mvc?
2-> If condition is true and modal is enabled , then I have to submit data through modal, which is having its input field binded through CategoryAttribute entity , CategoryAttribute is a collection entity of a Category class.
But the problem is that , in general.jsp page category Object is already binded and populated in UI. And here modal is present in the same page general.jsp with different form tag.
So how would I handle posting data of collection entity inside modal .So that it will persist the collection data of binded entity class?
Any sample code in controller side would be helpful to deal such situation thanks in advance
This is my Category class
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "CATEGORY")
public class Category implements Serializable {
#OneToMany(mappedBy = "category", targetEntity = CategoryAttribute.class, cascade = { CascadeType.ALL }, orphanRemoval = true)
(name = "name")
#BatchSize(size = 50)
protected Map<String, CategoryAttribute> categoryAttributes = new HashMap<String, CategoryAttribute>();
setter getter and many more attribute
}
This is CategoryAttribute class which is used in modal
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "CATEGORY_ATTRIBUTE")
public class CategoryAttribute implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "CATEGORY_ATTRIBUTE_ID")
protected Long id;
#Column(name = "NAME", nullable = false)
protected String name;
#Column(name = "VALUE")
protected String value;
#ManyToOne(targetEntity = Category.class, optional = false)
#JoinColumn(name = "CATEGORY_ID")
})
protected Category category;
setter getter
}
This is my general.jsp which is having already data populated related to category and it has button which is causing to open modal and submit the category attribute data
<form:form action="saveCategory" method="post" id="categoryForm"
modelAttribute="category">
<div class="tab-content">
<div id="general" class="tab-pane fade in active">
<div class="bodycontainer">
/** have some input fields which is already populated and bind with category object
</div>
/** this file have buttons which is causing to open below bootstrap modal
<%#include file="advanced.jsp"%>
</div>
</div>
</form:form>
<div class="listgrid-toolbar-footer"></div>
<c:if test="${requestScope.isAddCategoryAttribute}">
<div class="modal fade" id="modalCategoryAttribute" tabindex="-1"
role="dialog" aria-labelledby="myModelCattLabel"
aria-hidden="true">
<div class="modal-dialog" aria-hidden="true">
<div class="modal-content">
<form:form action="submitCategoryAttribute" modelAttribute="category">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">×</button>
<h3 class="modal-title">Add Cattegory Attribute</h3>
</div>
<div class="modal-body">
<div class="panel panel-default">
<div class="panel-heading">
<fieldset class="Key">
<legend class="ActiveDateRange">Key</legend>
<div class="form-group">
<label for="key">Key*:</label>
<div class='input-group date' id='name'>
<form:input path="categoryAttributesMap['check'].name"
cssClass="form-control" />
<!-- <input type="text" class="form-control" /> -->
</div>
</div>
</fieldset>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<fieldset class="Description">
<legend class="ActiveDateRange">Description</legend>
<div class="form-group">
<label for="key">Attribute Value*:</label>
<div class='input-group date' id='attributeValue'>
<form:input path="categoryAttributesMap['check'].value"
cssClass="form-control" />
<!-- <input type="text" class="form-control" /> -->
</div>
</div>
</fieldset>
</div>
</div>
</div>
<div class="modal-footer">
<span class="text-muted"><input type="submit"
id="addCategoryAttrButton" class="btn btn-primary"
value="Save" /></span>
</div>
</form:form>
</div>
</div>
</div>
</c:if>
Advance.jsp
<div id="listgridthree" class="listgrid-toolbar">
<ul>
<li>
<button type="submit" id="category_attribute" class="btn btn-primary">Add</button>
<button type="submit" class="btn btn-primary">Edit</button>
<button id="delete" type="submit"
class="btn btn-primary disabled">Delete</button>
</li>
</ul>
</div>
I want to set values for Set elements of login from JSP .
JSP page:
<form action="Registered" method="post">
<div class="form-group">
<label>Company Name</label>
<s:textfield name="name" value="%{name}" id="name"/>
</div>
<div class="form-group">
<label>Address</label>
<s:textarea name="address" value="%{address}" id="address"/>
</div>
<div class="form-group">
<label>User Name</label>
<s:textfield name="logins[0].userName" value="%{logins[0].userName}" id="userName"/>
</div>
<div class="form-group">
<label>User Id</label>
<s:textfield name="logins[0].userId" value="%{logins[0].userId}" id="userId"/>
</div>
<div class="form-group">
<label>Mail Id</label>
<s:textfield name="logins[0].userMailid" value="%{logins[0].userMailid}" id="userMailid"/>
</div>
Pojo Classes:
public class Client implements java.io.Serializable {
private Set logins = new HashSet(0);
//getter and setter
}
public class Login implements java.io.Serializable {
private Long id;
private Client client;
private String userId;
private String userName;
private String userMailid;
}
Action Class:
public String register() {
Client cl = new Client();
System.out.println(cl.getName() + " " + cl.getAddress());
}
I want to set values of set in to my Action class for Client and Login.
How to do this?
You can use a submit button like this:
<form action="Registered" method="post">
<div class="form-group">
<label>Company Name</label>
<s:textfield name="name" value="%{name}" id="name"/>
</div>
<div class="form-group">
<label>Address</label>
<s:textarea name="address" value="%{address}" id="address"/>
</div>
<div class="form-group">
<label>User Name</label>
<s:textfield name="logins[0].userName" value="%{logins[0].userName}" id="userName"/>
</div>
<div class="form-group">
<label>User Id</label>
<s:textfield name="logins[0].userId" value="%{logins[0].userId}" id="userId"/>
</div>
<div class="form-group">
<label>Mail Id</label>
<s:textfield name="logins[0].userMailid" value="%{logins[0].userMailid}" id="userMailid"/>
</div>
<input type="submit" value="Submit">
</form>
EDIT
A nice tutorial
After make properties file like:
#Global messages
name= name
submit = Submit
I believe you has made Registered.jsp.
An you can run your project!
To bind fildes to Set you should put annotations on this property
public class Client implements java.io.Serializable {
#Element(value = Login.class)
#Key(value = Long.class)
#KeyProperty(value = "id")
#CreateIfNull(value = true)
private Set logins = new HashSet(0);
//getter and setter
//now you need a property for login id, it should be initialized before JSP is populated
private Long loginId;
//getter and setter
}
now binding to the fields of the JSP change to
<s:textfield name="logins(%{loginId}).userName" id="userName"/>
the same for other fields that are bound to a set.
If you are using iterator tag to iterate through a set and you have an instance of Login pushed on top of the value stack then you can get its id instead of using loginId.