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

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).

Related

Thymeleaf - populate dropdown menu from object list

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'>

How to stay on the same page after form submit thymleaf and Spring boot?

Hello guys i have a question regarding what is mentioned in the title. Is it possible to stay on the same page and submit . I found something with javascript but it is not working for me because i m using thymleaf and spring boot. Or i just don't know how to adapt it to my case.
thymeleaf code:
<form th:action="#{/tweets/tweet}" th:object="${tweet}" method="post">
<div class="row">
<div class="col">
<input type="text" th:field="*{content}" class="form-control" placeholder="What's happening? Tell us!">
</div>
<div class="col">
<input class="form-control" type="submit" value="Submit" />
</div>
</div>
</form>
the controller class:
#Controller
#RequestMapping("tweets")
#Slf4j
public class TweetController {
private TweetService tweetService;
public TweetController(TweetService tweetService) {
this.tweetService = tweetService;
}
#PostMapping("/tweet")
#ResponseStatus(CREATED)
public Tweet tweet(#Valid #ModelAttribute("tweet") Tweet tweet, Principal
principal, BindingResult result) {
if(result.hasErrors()){
//do somethign
}
if (!tweet.getContent().equals(null) && !tweet.getContent().equals("") && !tweet.getContent().isEmpty()) {
tweetService.createTweet(tweet.getContent(), principal);
}
}
#GetMapping("/")
public String goToIndex(Model model){
model.addAttribute("tweet",new Tweet());
return "overview";
}
And i have server.context-path=/api
I have one more additional question to this topic. When i wanted to redirect it to another page i was getting a blank page. Not an error not an exception just a blank page. Any help ? I m new to this.
Yes, this is possible using ajax. I would recommend doing it using jQuery though. So, if you would like to submit your form and stay in the same page, you could do the following.
HTML
<form id="tweet-form" th:action="#{/tweets/tweet}" th:object="${tweet}" method="post">
<div class="row">
<div class="col">
<input type="text" th:field="*{content}" class="form-control" placeholder="What's happening? Tell us!">
</div>
<div class="col">
<input id="submit-form" class="form-control" type="button" value="Submit" />
</div>
</div>
</form>
Changes:
Added an id to the form.
Added an id to your input.
Change submit input's type for button.
jQuery
$('#submit-form').on('click', function() {
var form = $('#tweet-form');
$.ajax({
url: form.attr('action'),
data: form.serialize(),
type: post,
success: function(result) {
// Do something with the response.
// Might want to check for errors here.
}, error: function(error) {
// Here you can handle exceptions thrown by the server or your controller.
}
})
}
Controller
#PostMapping("/tweet")
#ResponseStatus(CREATED)
public Tweet tweet(#Valid #ModelAttribute("tweet") Tweet tweet, Principal
principal, BindingResult result) {
if(result.hasErrors()){
// Throw an exception or send a null Tweet.
}
if (!tweet.getContent().equals(null) && !tweet.getContent().equals("") && !tweet.getContent().isEmpty()) {
tweetService.createTweet(tweet.getContent(), principal);
}
// You are returning a Tweet, so you must return something.
return tweet;
}
Your controller pretty much stay the same. Just remember to return something.
Your example doesn't show what the tweet() method returns. It should return a Tweet object but doesn't have any return value. What are you attempting to do with that return value? If you're not handling it with Javascript someway, then get rid of #ResponseStatus(CREATED) and return a either a Model or a String pointing to your html file, like so:
#PostMapping("/tweet")
public String tweet(#Valid #ModelAttribute("tweet") Tweet tweet, Principal
principal, BindingResult result) {
if(result.hasErrors()){
//do somethign
}
if (!tweet.getContent().equals(null) && !tweet.getContent().equals("") && !tweet.getContent().isEmpty()) {
tweetService.createTweet(tweet.getContent(), principal);
}
return "redirect:/name-of-html-file";
}
reference
If you want thymeleaf to handle the tweet and the HttpStatus you could instead return something along the lines of
ModelAndView model = new ModelAndView("your-view");
model.addAttribute(tweet);
model.setStatus(HttpStatus.CREATED);
return model;

MVC Spring Controller, display dbData in HTML file

If I write a Spring MVC Controller, how can I display the DBData in my HTML file.
e.g. I have db.table called Setting and I want to display the IDs from that table in my HTML file as a Dropdown list.
#Controller
public class CustomChannelController {
private Setting setting;
private Diagram diagram;
private Channel channel;
#RequestMapping(value = "/customchannel", method = RequestMethod.GET, produces = "application/json; charset=utf-8")
public #ResponseBody Setting getId() {
return this.setting;
}
<table>
<tr>
<td>
<label class="col-md-12 control-label"> <%=language['UI.reportSetting.channel']%> : </label>
</td>
<td>
<select id="selectReportChannel" class="form-control">
<option value="0" ><%=setting[ID]%></option>
</select>
</td>
</tr>
</table>
Well it depends on how you retrieve data... do you use AJAX calls? Or do you need them when page is loaded?
Let's see the 2 scenarios
Note: in boths scenarios we assume you are returning a list of object like this:
public class Option{
private String value;
private String text;
//getter and setter
}
AJAX CALL: for this I assume we are using JQuery; in this case you will have in your JS or JSP file something like this:
$.ajax({
url : 'customchannel',
dataType : 'json',
contentType : 'application/json; charset=UTF-8',
type : 'GET',
success : function(items) {
$.each(items, function (i, item) {
$('#selectReportChannel').append($('<option>', {
value: item.value,
text : item.text
}));
});
},
error : function(data) {
}
});
<select id="selectReportChannel" class="form-control">
</select>
Page loaded In this case in your controller who will render the HTML page you can do something like this:
#Controller
public class CustomChannelController {
private Setting setting;
private Diagram diagram;
private Channel channel;
#RequestMapping(value = "/customchannel", method = RequestMethod.GET)
public ModelAndView getId(Model uiModel) {
uiModel.add("options", this.setting);
return new ModelAndView("yourPage", uiModel) ;
}
Then in the HTML page you can use JSTL in this way:
<table>
<tr>
<td>
<label class="col-md-12 control-label"> <%=language['UI.reportSetting.channel']%> : </label>
</td>
<td>
<select id="selectReportChannel" class="form-control">
<c:forEach items="${options}" var="option">
<option value="${option.value}">${option.text}</option>
</c:forEach>
</select>
</td>
</tr>
</table>
Ok, I have found a solution. First a need to create a Spring MVC Controller then a Service and link then the Controller to the Backbone model file.

Spring MVC, make a button, upon click, return a string value

I am still relatively new to springMVC, I currently have some code, that will take an input from a <form:input> on a jsp page, and create different lists depending on the input(providing I enter the correct String). I would like to transition this into a button instead, so I could have four buttons that will return a different String, for example "one", "two", "three" and "four". That way there is no typing needed from the user.
I see that there is a <form:button> available but I do not know how I could return the String value from this. Also I have looked into angularJS and seen that you can call a function onClick. But again, I don't know what the implementation would have to be to tie it into my Controller. I am just not really sure how I can implement this. Any help would be appreciated.
This is what I have being implemented at the moment :
<form:form commandName="input">
<label>Enter Value</label>
<form:input path="listType" class="inputbox" />
<br>
<input type="submit" class="button" value="Enter" />
</form:form>
This takes the input and stores it in an object :
#Controller
#SessionAttributes("input")
public class EventController {
#RequestMapping(value = "/event", method= RequestMethod.GET)
public String displayEvent (Model model) {
AccessInput userInput = new AccessInput();
model.addAttribute("input", userInput);
System.out.println("finished get method");
return "event";
}
#RequestMapping(value = "/event", method= RequestMethod.POST)
public String processEvent(#ModelAttribute("input")AccessInput userInput) {
System.out.println(userInput.getListType()); //just so I know what value it has
return "redirect:results.html";
}
This is the controller that creates my list based on the string that I pass through to the object
#RestController
#SessionAttributes("input")
public class ReportController {
#RequestMapping(value="/events")
public List<Appliance> getEvents(#ModelAttribute("input")AccessInput userInput) {
List<Appliance> events = new ArrayList<>();
events = ProcessChoice.ofList(userInput.getListType());
System.out.println(userInput.getListType());
return events;
}
}
Edit:
Just to note I have resolved this, I followed the example given by Vipin Dubey, I had to change my controller. I removed the POST method and added in a #RequestParam as a parameter, and redirected the buttons on the event.jsp to "results.html?input=one" then took this value and added it to my model to store it in the session.
#Controller
#SessionAttributes("URLparam")
public class ResultController {
#RequestMapping(value = "/results.html", method = RequestMethod.GET)
public String buttonSelect(Model model, #RequestParam("input")String input) {
model.addAttribute("URLparam", input);
System.out.println(input);
return "result";
}
}
You have two options :
1. Short and recommended way :
Use a link and style it as a button and you can directly call your controller
<a class="btn" href="/events?input=one">One</a>
<a class="btn" href="/events?input=two">two</a>
<a class="btn" href="/events?input=three">three</a>
<a class="btn" href="/events?input=four">four</a>
2. Use jQuery or JavaScript to submit the form based on clicked button using a hidden input field in your form
<!-- Buttons with classes -->
<div id="target">
<button class="one">One</button>
<button class="two">two</button>
<button class="three">three</button>
<button class="four">four</button>
</div>
<!-- Your form -->
<form:form commandName="input" id="myForm">
<input type="hidden" name="inputbox" id="inputbox" value=""/>
</form:form>
// You will have to do this for each of the button which is not a recommended way
$( ".one" ).click(function() {
$('input[name="inputbox"]').val("one");
//var a = $('input[name="inputbox"]').val();
//alert(a);
$( "#myForm" ).submit();
});

Autocomplete Textbox in JSP with Using an Array or List

I was trying to make autocomplete in different ways, but nothing works at all.
From here and here
Hope you help me guys. I have a project that uses Spring MVC + jsp + hibernate. I want to create a search textbox, which also will be work as a autocomplete for Last Names of clients.
When I open a clients page with help of my Controller I send, via a model, a list with clients and list with Last Names, the last one for autocomplete.
Here is my controller:
#Controller
#RequestMapping("/clients")
public class ClientsController {
#Autowired
public ClientsService clientsService;
#Autowired
private ServicesService servicesService;
#Autowired
private OrdersService ordersService;
#Autowired
private Order_serviceService order_serviceService;
#Autowired
private ObjectMapper objectMapper;
#RequestMapping(method = RequestMethod.GET)
public String listClients(Model model) {
List<Clients> allClients = clientsService.listClients(
new RequestAllClientsEvent()).getClients();
List<String> lastNamesList = new ArrayList<>();
for(int i = 0; i < allClients.size(); i++){
lastNamesList.add(allClients.get(i).getLast_name());
}
Collections.sort(lastNamesList);
String json = "";
try{
json = objectMapper.writeValueAsString(lastNamesList);
} catch(Exception e){}
model.addAttribute("clientsList", allClients);
model.addAttribute("lastNamesList", json);
return "clients";
}
Then in jsp page I want to add some how my lastNamesList to the script source:
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.js"> </script>
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"> </script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" />
<script>
$(function() {
$( "#query" ).autocomplete({
source: lastNamesList
});
});
</script>
</head>
my input textbox is:
<div class="ui-widget">
<input class="form-control" type="search" id="query" name="query" required>
</div>
I thought I could get something like that if I just write source: lastNamesList :
<script>
$(function() {
var availableTags = [
"ActionScript",
"AppleScript",
"Asp",
"BASIC",
"C",
"C++",
"Clojure",
"COBOL",
"ColdFusion",
"Erlang",
"Fortran",
"Groovy",
"Haskell",
"Java",
"JavaScript",
"Lisp",
"Perl",
"PHP",
"Python",
"Ruby",
"Scala",
"Scheme"
];
$( "#tags" ).autocomplete({
source: availableTags
});
});
</script>
Could you please help me to do this in right way. It would be great if I could be able to use list or array from my controller.
Thanks.
upd.changed my controller, added json conversion, but it didnt help. Looks like scripts dont work on my page...confused even more O_o
upd. here is my working code:
Controller:
#RequestMapping(value = "/searchlastname", method = RequestMethod.GET, headers = "Accept=*/*")
public
#ResponseBody
List<String> searchLastName(#RequestParam("term") String query) {
List<Clients> clientsList = clientsService.searchClient(new SearchClientEvent(query)).getClients();
List<String> lastnameList = new ArrayList<>();
System.out.println("Found clients size: " + clientsList.size());
for (Clients clients : clientsList) {
lastnameList.add(clients.getLast_name());
}
Collections.sort(lastnameList);
return lastnameList;
}
script:
$(document).ready(function () {
$("#lastNameAuto").autocomplete({
source: 'clients/searchlastname'
});
});
in jsp:
<form class="form-horizontal" role="form" action="<c:url value="/clients/search"/>" method="get">
<div class="input-group input-group-sm">
<span class="input-group-addon"><spring:message code="label.enterClientInfo"/></span>
<input class="form-control" type="search" id="lastNameAuto" name="query" required>
<span class="input-group-btn">
<button class="btn btn-default" type="submit">
<spring:message code="label.searchClient"/>
</button>
</span>
</div>
</form>
Hope it helps someone else! ;)
From your update ,
You should have a model class and do a explicit conversion to send the json object. either using gson library or you can go with the existing method by sending the list .
For a beginner i would advise to learn from the nice example here
Hope this helps !!

Categories