Thymeleaf - populate dropdown menu from object list - java

Currently, the methods return only their own links into the required fields, ie. the last html element for available tests returns only availableTestList in the div that is supposed to list all available tests. Same for "/currentTest" and for the dropdown menu, which shows no options at all.
I started trying some fixes from here on SO, and now my html broke down completely, giving me the error:
An error happened during template parsing (template: "templates/Teacher.html")
and in java console:
"Neither BindingResult nor plain target object for bean name 'test' available as request attribute"
Any ideas?
Below is the controller code first, with the html afterwards.
#Controller
public class TeacherController {
TestController testcont = TestController.getInstance();
#RequestMapping(value = "sendTest", method = RequestMethod.POST)
public String sendTest(Model model) throws IOException, ServletException{
for(Test test : testcont.showAllTests()){
if(test.getName().equals("selection")){
testcont.SetActiveTest(test);
System.out.println(testcont.getActiveTest());
//return "Test sent successfully to students! <a href='/Teacher'>Back</a>";
}
}
model.addAttribute("tests", testcont.showAllTests());
return "sendTest";
}
#RequestMapping(value = "resetCurrentTest", method = RequestMethod.POST)
public String resetCurrentTest(Model model){
testcont.SetActiveTest(null);
model.addAttribute("tests", testcont.showAllTests());
return "resetCurrentTest";
}
#RequestMapping(value = "currentTestOptions", method = RequestMethod.GET)
//#ModelAttribute("/currentTestOptions")
//#GetMapping("/currentTestOptions")
public String currentTestOptions(Model model) {
model.addAttribute("tests", testcont.showAllTests());
return "currentTestOptions";
}
#RequestMapping(value = "getActiveTest", method = RequestMethod.GET)
public String getActiveTest(){
return testcont.getActiveTest().toString();
}
}
The HTML
<body>
<p>
<a href='/Teacher/NewTest'>New Test upload</a>
</p>
<div
style='height: 150px; width: 400px; border: 1px solid #ccc; font: 16px/26px Georgia, Garamond, Serif; overflow: auto;'>
<form th:action='${sendTest}' th:object="${tests}" method='post'>
<fieldset>
<label>Select test</label>
<select id="tests" name="tests" class="form-control" th:field="${tests}">
<option value="">Select test</option>
<option
th:each="test : ${tests}"
th:value="${test.getName}"
th:text="${test.getName}"
></option>
</select>
</fieldset>
<input type='submit' value='Submit'>
</form>
</div>
<form action='${resetCurrentTest}' method='post'>
<input type='submit' value='Clear'>
</form>
<a> Current Test for students: </a>
<p th:text="${getActiveTest}" ></p>
<p>All available tests on server:</p>
<div
style='height: 200px; width: 400px; border: 1px solid #ccc; font: 16px/26px Georgia, Garamond, Serif; overflow: auto;'>
<th:block th:each="test : ${tests}">
</div>
</body>
in the controller, the 3rd method "currentTestOptions" is supposed to return the full list of objects, and in the HTML I am to iterate through the list using test : currentTestOptions, and then as the value retrieve the test names to show in the dropdown.
Current console error when trying to open the local page /Teacher is:
Neither BindingResult nor plain target object for bean name 'test' available as request attribute

try this code
<option th:each="test : ${currentTestOptions}"
th:value="${test.getName}"
th:text="${test.getName}"></option>
for more thymeleaf-forum/Create-drop-down-list
thymeleaf-select-option

Bolow is my controller code:
ModelAndView view = new ModelAndView("view/index");
UserIdentity userIdentity = (UserIdentity) request.getSession().getAttribute(SessionConstant.ACCOUNT_SESSION_KEY);
if(userIdentity == null){
return null;
}
List<PayBill> payBills = payBillService.getBillDetailByUserId(userIdentity.getId());
if(payBills != null && payBills.size() > 0){
view.addObject("bill",payBills.get(0));
}
return view;
Bolow is my html code:
<div class="centerBox">
<div class="centerBox1" th:if="${bill != null}">
<p style="color:#999;">当月水费金额</p>
<p style="color:red;font-size:40px;" th:text="${bill.paymentAmount}">100.00</p>
</div>
<div class="centerBox1" th:if="${bill == null}">
<p style="color:#999;">当月水费金额</p>
<p style="color:red;font-size:40px;">0.00</p>
</div>
<button type="button" onclick="btn()" class="mui-btn mui-btn-primary" style="width: 100%;border-radius: 20px;margin:30px 0px 10px 0px" data-loading-icon="mui-spinner mui-spinner-custom" >立即缴费</button>
<p>往期水费记录</p>
<!-- image -->
<div class="bottomBox">
<img src="/images/bottom.png" width="100%" alt="" />
</div>
</div>
Attention please, use this code th:if="${bill != null} to avoid get a null value. if it's null, it giving me the error.

In html file you have:
<select class="form-control" th:field="${test.getName}">
Thymeleaf expects that you will pass attribute called test through model. You can do it like this:
model.addAttribute("test", yourObjectRepresentingTest);
Do this in a controller method that returns view to your html. For example:
#GetMapping("/showTests")
public String showTests(Model model) {
// some controller logic if you need
SampleTest sampleTest = new SampleTest(); // <- this is your backing bean object that will be bound to thymeleaf view
model.addAttribute("test", sampleTest);
return "showtests"; // <- this is a file name of a html containing your view
}
You may also need to add th:object to your html file:
<form th:action="#{/sendTest}" th:object="${test}" method='post'>

Related

How to re-render previous page when validating form

I have a controller that renders a chores.html page with various sorts of chores.
#GetMapping("/chores")
public String getDueChores(Model model)
{
var tomorrow = LocalDate.now().plusDays(1);
var chores = choreRepository.findByDueBefore(tomorrow);
model.addAttribute("choresDue", chores);
model.addAttribute("allChores", choreRepository.findAll());
model.addAttribute("chore", new Chore());
model.addAttribute("chores", new ArrayList<Chore>());
return "chores";
}
The same page also has a form for adding a new chore. Here's the controller method:
#PostMapping("/chores")
public String addNewChore(#ModelAttribute #Valid Chore chore)
{
chore.setDue(LocalDate.now().plusDays(chore.getDaysBetween()));
choreRepository.save(chore);
return "redirect:/chores";
}
Now I want to display the errors if the new chore is invalid.
Attempt 1:
#PostMapping("/chores")
public String addNewChore(#ModelAttribute #Valid Chore chore,
Errors errors)
{
if (errors.hasErrors())
{
return "chores";
}
chore.setDue(LocalDate.now().plusDays(chore.getDaysBetween()));
choreRepository.save(chore);
return "redirect:/chores";
}
This shows the error message, but sense it's not going through the logic in the GET controller method, all the other chores on the page don't get populated.
Attempt 2:
#PostMapping("/chores")
public String addNewChore(#ModelAttribute #Valid Chore chore,
Errors errors)
{
if (errors.hasErrors())
{
return "redirect:/chores";
}
chore.setDue(LocalDate.now().plusDays(chore.getDaysBetween()));
choreRepository.save(chore);
return "redirect:/chores";
}
This doesn't work because the error information is lost on the redirect, and the errors aren't displayed.
Could anyone point me in the right direction, please?
Here's chores.html, if it's relevant:
<body>
<h1>Due today...</h1>
<form method="post" th:action="#{/chore}" th:object="${chore}">
<ul>
<li th:each="chore: ${choresDue}">
<input type="checkbox" name="choreIds" th:value="${chore.id}"/>
<label th:text="${chore.name}"></label>
</li>
</ul>
<input type="submit" value="Mark Chores Complete">
</form>
<form method="post" action="#" th:action="#{/chores}" th:object="${chore}">
<input type="text" th:field="*{name}" placeholder="Chore name">
<span class="validationError"
th:if="${#fields.hasErrors('name')}"
th:errors="*{name}">Chore name is invalid</span>
<br>
<input type="text" th:field="*{daysBetween}" placeholder="Do chore every # days">
<span class="validationError"
th:if="${#fields.hasErrors('daysBetween')}"
th:errors="*{daysBetween}">Chore name is invalid</span>
<br>
<input type="submit" value="Add chore">
</form>
<hr>
<h1>All Chores</h1>
<form th:method="delete" th:action="#{/deleteChore}" th:object="${chore}">
<ul>
<li th:each="chore: ${allChores}">
<input type="checkbox" name="choreIds" th:value="${chore.id}"/>
<label th:text="${chore.name} + ' every ' + ${chore.daysBetween} + ' days'"></label>
</li>
</ul>
<input type="submit" value="Delete selected chores">
</form>
</body>
Solution is to add Errors to the Model.
#PostMapping("/chores")
public String addNewChore(#ModelAttribute #Valid Chore chore,
Errors errors,
Model model)
{
if (errors.hasErrors())
{
model.addAttribute("error", errors);
var tomorrow = LocalDate.now().plusDays(1);
var chores = choreRepository.findByDueBefore(tomorrow);
model.addAttribute("choresDue", chores);
model.addAttribute("allChores", choreRepository.findAll());
return "chores";
}
chore.setDue(LocalDate.now().plusDays(chore.getDaysBetween()));
choreRepository.save(chore);
return "redirect:/chores";
}

spring return object on button click out of list

Hi guys hope you can help me, because i cant get further at the moment
I have my Controller.
#RequestMapping(value="/kundenseite", method= RequestMethod.GET)
public String kundenLogin(ModelMap model) {
if(kundeComponent.getKunde() != null) {
List<Restaurant> restaurants = restaurantService.alleRestaurants();
model.addAttribute("restaurants", restaurants);
return "kundenseite";
}else {
return "redirect:/kunde/login";
}
}
#RequestMapping(value="/kundenseite", method= RequestMethod.POST)
public String kundenLoginAnswer(ModelMap model, #ModelAttribute Restaurant restaurant) {
System.out.println(restaurant.toString());
return "kundenseite";
And my jsp file
<%# include file="common/header.jspf" %>
<div class="jumbotron text-center">
<h1>MiMiMi Lieferservice</h1>
<p>Der schnellste Lieferservice von Passpick</p>
</div>
<div style="margin-right:auto; margin-left:auto; width: 33%">
<h2 style="text-align: center">Restaurant wählen</h2>
<div class="well">
<c:forEach items="${restaurants}" var="restaurant">
<form:form modelAttribute="${restaurant}" method="post">
<div style="margin-top: 8px" class=col-sm-4 >${restaurant.name}</div>
<div style="margin-top: 8px" class=col-sm-4 >${restaurant.restaurantTyp}</div>
<button type="submit">Bestellen</button>
</form:form>
<br style="clear:both;" />
</c:forEach>
</div>
</div>
</body>
</html>
If the user presses a button i want to return a restaurant.
But i don't know how to make that happen, my thought was to use a form but i cant get it to send a complete restaurant object back
If there is no solution for this i have to write the id with the button.
You need input hidden inside the form tab as below input hidden:
<input type="hidden" name="name" value="${restaurant.name}">
<input type="hidden" name="restaurantTyp" value="${restaurant.restaurantTyp}">

Passing Model Object as #RequestParameter to Spring Controller

I have a JSP page that displays list of employees found.
<c:forEach items="${employeeList}" var="employee">
<div class="formRow" style="background-color: red">
<div class="employeeResultColumnSmall">${employee.getEmpNo()}</div>
<div class="employeeResultColumnRegular">${employee.getFirstName()}</div>
<div class="employeeResultColumnRegular">${employee.getLastName()}</div>
<div class="employeeResultColumnSmall">${employee.getGender()}</div>
<div class="employeeResultColumnRegular">${employee.getDateOfBirth()}</div>
<div class="employeeResultColumnRegular">${employee.getHireDate()}</div>
<div class="employeeResultColumnRegular">${employee.getDept().getDeptName()}</div>
<div class="employeeResultColumnSmall">Update</div>
</div>
</c:forEach>
Controller
#RequestMapping(value = "/updateemployee", method = RequestMethod.GET)
public ModelAndView goUpdateEmployee(#RequestParam("employee") Employee employee){
System.out.println(employee);
return null;
}
I want to pass the employee bean to a controller whose update link is clicked. I tried doing it as shown above but not working.

JQuery to update a <c:forEach> in Spring MVC

I сreated a jsp page with the table. I would like to refresh table after click the button using Jquery.
But in result i see two views at the same time. How to avoid this problem ?
My Controller
#Controller
#RequestMapping("/")
public class HelloController {
private final Logger log = LoggerFactory.getLogger(getClass());
#Autowired
private UserServiceDao userServiceDao;
#RequestMapping(method = RequestMethod.GET)
public String printWelcome(ModelMap model) {
model.addAttribute("Message","first");
model.addAttribute("list",userServiceDao.findAll());
log.trace("NUMBER:::::::::::::::::::::"+userServiceDao.findAll().size());
return "main";
}
#RequestMapping("/table")
public ModelAndView renderTable(HttpServletRequest request) {
String name = request.getParameter("nameSearch");
log.trace("1: "+name);
List<User> people = userServiceDao.find(name);
log.trace("2: "+people.size());
return new ModelAndView("main", "list", people);
}
}
MY view with the Jquery script
<body>
<div class="sear">
<input class=" int datasearch" type="search" value="an" id="dataSearch">
<input class="int search" type="button" value="Search" id="search">
<input class="int create" type="button" id="err" value="Create user">
</div>
<h1>List of users: </h1>
<div class="table" >
<c:forEach var="item" items="${list}">
<div class="row" >
<div id="tabl" class="cell" style="width:300px;"><c:out value="${item.name}"/>></div>
<div class="cell" style="width:100px;" ><input class="delete" type="button" value="Delete user"></div>
<div class="cell"><input class="edit" type="button" value="Edit user"></div>
</div>
</c:forEach>
</div>
<script type="text/javascript">
$('#err').click(function(){
window.location.href='/registration';
})
$('#search').click(function(){
$(function() {
var myTableContainer = $("#tabl");
var renderTable = function(container) {
var data = $('#dataSearch').val();
var postReqData = {}; // Create an empty object
postReqData['nameSearch'] = data;
$.get("/table",postReqData, function(data) {
container.empty().html(data);
})
};
/* This is called on document ready */
renderTable(myTableContainer);
/* Use the same renderTable function when the refresh button is clicked */
$("#search").click(function() {
renderTable(myTableContainer);
});
})
})
Ok, this might be a bit too long for comments.
Your main problem is that both #RequestMapping(method = RequestMethod.GET) and #RequestMapping("/table") render the same view.
That is: the view containing all your search inputs, <c:forEach> table and javascript.
So when you do the search and when the ajax call returns, you replace contents of div#tabl with all those search inputs, <c:forEach> and javascript.
You end up with two pieces of everything nested in the wrong way.
My advice would be to do one RequestMapping that renders the basic jsp, and the other one that renders only the search results (or even returns json and render it as html in javascript).

Spring MVC and Error 400: SRVE0295E

I have problem with simple MVC application.
dayoff.html
<div id="dayoff_operations" class="big_box_1">
<form:form modelAttribute="dayOff" enctype="multipart/form-data" action="/dayoff.html" >
<div style="width: 50%; float: left; margin-top: 0px ">
<form:label path="forDate" ><spring:message code="dayoff.fordate.label"/></form:label>
<form:input path="ax_forDate" id="datepicker" style="width:65px" readonly="readonly"/>
</div>
<div style="width: 50%; float: right; margin-top: 0px ">
<form:label path="toDate" ><spring:message code="dayoff.todate.label"/></form:label>
<form:input path="ax_toDate" id="datepicker2" style="width:65px" readonly="readonly" />
</div>
<div style="float: left">
<form:select cssClass="more" path="dayofftype" items="${dayoffTypes.list}" itemLabel="label" itemValue="value" htmlEscape="false" cssErrorClass="errorsField"/>
<form:errors path="dayofftype" cssClass="errors"/>
</div>
<input type="submit" name="add" value="Add"/>
</form:form>
Here is my controller:
#Controller
#RequestMapping("/dayoff")
#SessionAttributes(types = {DayOff.class})
public class DaysOffController {
private Validator validator;
#Autowired
private ReloadableResourceBundleMessageSource messages;
#ModelAttribute("dayoffTypes")
public Map<String, Object> populateDayoffTypes(Locale locale) {
return Utils.createComboMap(DayoffType.values(), messages, locale);
}
#RequestMapping(method = RequestMethod.GET)
public String setupForm(Model model) {
model.addAttribute("dayOff", new DayOff());
model.addAttribute("cur_period",SessionManager.getCurrentPeriod());
return "dayoff";
}
#RequestMapping(method = RequestMethod.POST, params = "add")
public String addNewHoliday(#ModelAttribute DayOff dayOff, BindingResult result, ModelMap model) {
System.out.println("AAA");
return "/dayoff";
}
When I click Add button Error 400: SRVE0295E: Error reported: 400 appears, there is no information at server console.
I assume it is realted to the setupForm() method which is displaying the form and crushing it to future submits. Can you please guide me with this?
Error 400: SRVE0295E occurs also when MVC cannot fill #ModelAttribute Form with values from HTML form.
For example:
class Form has primitive attribute int someCount
your HTML form has <input> to assign value to this primitive attribute
user entered empty value (null) to this <input>
You should not use primitive types such as int, boolean, float and so on.
The return statements from setupForm and addNewHoliday are different. I presume you want to return the same view name from both. As you can see the form in order to submit it, I assume that the addNewHoliday return value of "/dayoff" should in fact be "dayoff"

Categories