I am new to Thymeleaf, I tried to post object to controller but didn't get any success. Here is a form template I am using:
<form id="customerRecord" th:action="#{/saveData}" method="post" th:object="${customerData}">
<input type="hidden" th:value="${name}" th:field="*{name}">
<button type="submit" class="btn btn-primary" >Save Record</button>
</form>
Controller:
#PostMapping("/saveData")
public String saveCustomerData(#ModelAttribute("customerData") CustomerData customerData, Model model) {
try {
LOG.info("Working {}", writer.writeValueAsString(customerData));
} catch (JsonProcessingException e) {
LOG.info("Problem");
}
return "success";
}
CustomerData class:
public class CustomerData {
private AuthorizeRequestItem name;
private AuthorizeRequestItem mobileNumber;
private AuthorizeRequestItem countryCode;
private AuthorizeRequestItem emailUser;
private AuthorizeRequestItem emailDomain;
}
AuthorizeRequestItem class:
public class AuthorizeRequestItem {
private Date date;
private String validator;
private Boolean valid;
private String data;
}
Problem is the CustomerData it self contain nested objects.
I need to pass complete CustomerData to controller, but when I tried to pass object in input field, it (controller) received a null value for nested objects of CustomerData.
I have implemented Thymeleaf forms to pass Objects containing string variable and it is working good for me.
Any help would be much appreciated.
This will work,when we are using post in thyme leaf we will use ajax call this will get your value and pass it to your controller now when you click submit button value will be pass to your controller.
For example:
<div id="form Data">
<input id="app Id" type="hidden" t h:value="${app Id}" />
<input type="submit" on click="redirection()"/>
</div>
<script type='text/java script'>
function redirection(){
let app id = document.get Element By Id('app Id').value;
let u r l ="this will be your u r l where you want to redirect"
window.open(u r l,"_self");
Related
I have an Entity "User". I have an Enum "Usertyp". Users have a field "usertyp". I want to change the "Usertyp" by passing a DTO to my controller. The problem is that the usertype gets changed to Null in the DB
Another minor problem is that I want the default value of the selectfield to have the users current usertype as default value. I tried with "
th:selected="${u.usertyp}">
and also with an if statement. Neither worked.
I am very grateful for any help. I really struggle with Thymeleaf.
Controller:
#PostMapping("editUser/{userId}")
public String editUser(#ModelAttribute("sessionUser") User sessionUser, #Valid #ModelAttribute("userDTO") UserDTO userDTO, #PathVariable Long userId, Model model){
if(sessionUser==null || sessionUser.getUsertyp() == Usertyp.USER)
{
return "redirect:/";
}
else {
User changedUser = userService.findById(userId);
changedUser.setUsertyp(Usertyp.fromString(userDTO.getUsertyp()));
userService.save(changedUser);
return "redirect:/administration";
}
}
DTO
public class UserDTO {
//TODO usertyp anpassem
private String usertyp;
public UserDTO(String usertyp) {
this.usertyp = usertyp;
}
public String getUsertyp() {
return usertyp;
}
public void setUsertyp(String usertyp) {
this.usertyp = usertyp;
}
}
Template
<ul class="list-group list-group-flush">
<span th:each="u : ${userList}">
<li class="list-group-item">
<span th:text="${u.username}"></span>
<form th:object="${userDTO}" th:action="#{/editUser/{userId}(userId=${u.id})}" method="Post" id="Rolle">
<select th:field="*{usertyp}" form="Rolle">
<option
th:each="usertyp : ${T(com.example.myproject.entities.Usertyp).values()}"
th:text="${usertyp.displayText}"
th:value="${usertyp.displayText}">
</option>
</select>
<input class="btn btn-primary" type="submit" value="Speichern">
</form>
</li>
</span>
</ul>
I already changed my DTO field type from "Usertyp" to String
th:selected="${u.usertyp}">
The th:selected property should convert to selected="selected" or just selected in raw html, I think instead you want something like th:selected="${u.usertyp == usertyp}"
You didn't show your #GetMapping setup for the thyme leaf page, so I didn't include a user list, but here's a basic example of what I think you're attempting to do:
User Controller:
#Controller
public class UserController {
#GetMapping("user")
public String getUserTypePage(#ModelAttribute("userDTO") UserDTO userDTO) {
// just setting it to admin so that it will show the default selection of not the first item
userDTO.setUserType(UserType.ADMIN);
return "user";
}
#PostMapping("user")
public void postUserTypePage(#ModelAttribute("userDTO") UserDTO userDTO) {
System.out.println("USER DTO TYPE - " + userDTO.getUserType().getDisplayText());
}
}
UserType enum:
public enum UserType {
USER("Standard User"),
ADMIN("Administrator");
private final String displayText;
UserType(String displayText) {
this.displayText = displayText;
}
public String getDisplayText() {
return displayText;
}
}
UserDTO:
public class UserDTO {
private UserType userType;
public UserDTO(UserType userType) {
this.userType = userType;
}
public UserType getUserType() {
return userType;
}
public void setUserType(UserType userType) {
this.userType = userType;
}
}
Thymeleaf view:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<title>User Type</title>
</head>
<body>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<form th:object="${userDTO}" th:action="#{/user}" method="POST" id="Rolle">
<select th:field="*{userType}" form="Rolle">
<option
th:each="uType : ${T(com.example.demo.models.UserType).values()}"
th:text="${uType.displayText}"
th:value="${uType}"
th:selected="${userType == uType}">
</option>
</select>
<input class="btn btn-primary" type="submit" value="Speichern">
</form>
</li>
</ul>
</body>
</html>
Specifically you want the th:value to be bound to the enum value (if you'd prefer to use an enum rather than a string):
th:value="${uType}"
And then the th:selected set based off of equality of the enum to the UserType option in being looped through:
th:selected="${userType == uType}">
A few additional things to check:
Are you establishing the #ModelAttribute("userDTO") in the GET variant of your controller?
Log out the value of the userType in your post method to confirm it's value before any database operation (to confirm that it is actually coming in as null from the post and not being set to null somewhere in the db operation).
Try just passing along the value for the userType in the form (instead of using a select input item) to confirm that the currentValue for your model is getting fed through i.e.: <input th:field="*{userType}" th:value="${userType}">
I have ReservationController that have 2 methods:
#GetMapping
public String getReservationPage(final Model model,
final #PathVariable String hotelId,
final #PathVariable String roomId) {
final RoomApi roomApi = roomClient.findById(roomId).getBody();
model.addAttribute("roomApi", roomApi);
model.addAttribute("hotelId", hotelId);
model.addAttribute("roomId", roomId);
model.addAttribute("reservationForm", new ReservationApi().toBuilder()
.room(roomApi)
.build());
return "reservation";
}
#PostMapping
public String createReservation(final #PathVariable String roomId,
final #PathVariable String hotelId,
final #ModelAttribute("reservationForm") ReservationApi reservationApi) {
final Reservation reservation = reservationMapper.toDomain(reservationApi);
reservationService.save(reservation);
return "redirect:/";
}
And I have one problem, that relate to the roomApi. So how can I transfer roomApi from the getReservationPage to the crateReservation in reservationForm. I also have thymeleaf page with some form, but when I click submit button, roomApi is null in reservation. I think thats because of thymeleaf form does not contain any information about roomApi in reservation, but Im addinig it with builder.
<form th:object="${reservationForm}"
method="post"
th:action="#{/hotels/{hotelId}/rooms/{roomId}/reservations(hotelId=${hotelId}, roomId=${roomId})}">
<div class="form-group">
<label for="additionalInformation">Additional Information</label>
<input type="text" th:field="*{additionalInformation}" th:name="additionalInformation" class="form-control form-control-sm" id="additionalInformation">
</div>>
<button type="submit">Reserve</button>
</form>
This question already has answers here:
#Autowired for #ModelAttribute
(2 answers)
Closed 2 years ago.
I am using a pojo for handling form request and I am trying to access service using Autowired. But it keeps returning null inspite of whatever I try changing. I will publish all my code, please take a look into it.
CategoryAddForm:
In this page, I am trying to use categoryService but it seems be empty(null) and when I try using any function inside the service, I get nullpointerexception. I have not tried to initialize the autowired class anywhere.
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Component
public class CategoryAddForm {
private Long id;
private String title;
private String description;
private String language;
private String image_url;
#Autowired
CategoryService categoryService;
public Category save() {
Category category;
if(this.id==null) {
if(this.language==null || this.language.trim().equals("en")) {
category = Category.builder()
.title_en(this.title)
.description_en(this.description)
.image_url(this.image_url)
.en_available(true)
.count(0l).build();
System.out.println("New for English: \n id: "+this.id+" \n title:"+this.title+"\n description: "+this.description+"\n language: "+this.language);
System.out.println(categoryService);
// categoryService.save(category);
}
else {
category = Category.builder()
.title_np(this.title)
.description_np(this.description)
.np_available(true)
.en_available(false)
.count(0l).build();
System.out.println("New for Nepali: \n id: "+this.id+" \n title:"+this.title+"\n description: "+this.description+"\n language: "+this.language);
System.out.println(categoryService);
// categoryService.save(category);
}
}
else {
if(this.language==null || this.language.trim().equals("en")) {
category = Category.builder()
.id(this.id)
.title_en(this.title)
.description_en(this.description)
.en_available(true)
.image_url(this.image_url).build();
}
else {
category = Category.builder()
.id(this.id)
.title_np(this.title)
.description_np(this.description)
.np_available(true)
.image_url(this.image_url).build();
}
}
System.out.println(category);
return categoryService.save(category);
}
}
Form page:
This page sends categoryForm object to /save in controller which invokes the save function that is inside CategoryAddForm
<form th:action="#{'/admin/category/save'}" method="post" th:object="${categoryForm}">
<div class="form-group my-1 p-2 row">
<label for="categoryTitle">Title</label>
<input type="title" class="form-control" name="title" id="categoryTitle" th:field="*{title}">
</div>
<div class="form-group my-1 p-2 row">
<label for="categoryDescription">Description</label>
<textarea rows="5" type="description" class="form-control" name="description" id="categoryDescription" th:field="*{description}">
</textarea>
</div>
<div class="form-check my-1 p-2 row">
<label for="languages">Select Language</label>
<div id="languages" class="row ml-2">
<div class="col-2" >
<input class="form-check-input" type="radio" value="en" th:field="*{language}" id="englishLanguage" th:selected="selected">
<label class="form-check-label" for="englishLanguage">
English
</label>
</div>
<div class="col-2" >
<input class="form-check-input" type="radio" value="ne" th:field="*{language}" id="nepaliLanguage">
<label class="form-check-label" for="nepaliLanguage">
Nepali
</label>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary m-2">Submit</button>
</form>
Category Service Implementation:
This is just for the reference and proof that I have not done anything wrong.
#Service
public class CategoryServiceImpl implements CategoryService {
#Autowired
private CategoryRepository repository;
#Override
public Category save(Category document) {
return repository.save(document);
}
#Override
public Category getById(Long id) {
return repository.getOne(id);
}
#Override
public void delete(Category document) {
repository.delete(document);
}
#Override
public void deleteById(Long id) {
repository.deleteById(id);
}
#Override
public List<Category> getAllCategories() {
return repository.findAll();
}
}
save route in CategoryAdminController:
This function is taking categoryAddForm from the form and calls save() function in categoryAddForm.
#PostMapping(value = "/save")
public ModelAndView submitCategory(#ModelAttribute("categoryForm") CategoryAddForm categoryForm, BindingResult result){
categoryForm.save();
if(result.hasErrors()){
return new ModelAndView("redirect:/admin/category/add?error");
}
return new ModelAndView("redirect:/admin/category/add");
}
The problem is that you are creating a new CategoryAddForm every time you make a reuqest and you are not letting spring manage your beans. If you are creating a new instance of CategorAddForm, spring won't know that he needs to inject your service into it. I think you can try to inject by constructor.
I have a problem,my web app have a passcode form, user will give a Passcode string and app will riderict user to questions page for a spesific event. my controller will find this even by this passcode. i tried with this way but my passcode field is always null.
<form method="get" th:action="#{/findEvent(passcode=${passcode})}">
Passcode:<br>
<input type="text" th:name="${passcode}"><br>
<div>
<button type="submit">Find</button>
</div>
</form>
#GetMapping(value = "/findEvent")
public String resetPassword(#RequestParam(value="passcode",required=false) String passcode) {
if(passcode==null)
return "passcode";
Event event=eventService.findByPassCode(passcode);
List<Question> questions=questionService.findQuestionsByPasscode(passcode);
return "questions";
}
#RequestMapping(value = "/findEvent", method = RequestMethod.POST)
public String findEvent(#RequestParam("passcode") String passcode) {
Event event=eventService.findByPassCode(passcode);
List<Question> questions=questionService.findQuestionsByPasscode(passcode);
return "questions";
}
Same problem with mine
Request parameter with thymeleaf
How can i achieve this ?? can you help me
Use name="passcode" instead
<input type="text" name="passcode" value="1234" />
Since its the same as the object name, just use
#RequestParam String passcode
i am trying to get question and it's multiple options. i am getting successfully Question but its options getting null.
<c:forEach begin="0" end="${optionsCount}" varStatus="loop">
<form:input path="options[${loop.index}].mcq"/>
</c:forEach>
public class OnlineTestQuestionBean {
private String optionsCount;
private Long questionId;
private String question;
private Set<QuestionOptionBean> options;
//setter getter
}
public class QuestionOptionBean {
private Long optionId;
private String mcq;
//setter getter
}
following is Controller Code :-
#Controller
public class OnlineTestController {
#RequestMapping(value = "/savequestion", method = RequestMethod.GET)
public String addQuestion(Model model) {
model.addAttribute("OnlineTestQuestionBean", onlineTestQuestionBean);
return "addquestion";
}
#RequestMapping(value = "/savequestion", method = RequestMethod.POST)
public String saveQuestion(#ModelAttribute("OnlineTestQuestionBean")OnlineTestQuestionBean onlineTestQuestionBean, Model model) {
return null;
}
}
Following is Spring Form code :-
<c:forEach begin="0" end="${optionsCount}" varStatus="loop">
<form:input path="options[${loop.index}].mcq"/>
</c:forEach>
When i submit that time i get "Cannot get element with index 0 from Set of size 0, accessed using property path" this Exception,
suppose i used following code i get null set value.
<input type="text" path="options.mcq"/>
Try using the following in the form :
<c:forEach
<c:forEach items="${options}" var="option">
<form:input path="option.mcq"/>
</c:forEach>