If I had a Java class called for instance Buffet and one of its fields was something like:
#ManyToOne
private Chef chef
and I had to create a new Buffet object in an html form using Thymeleaf, how would I be able to refer to this chef field? At the moment my html looks like this:
<form th:action="#{/newBuffet}" method="POST" th:object="${buffet}">
<div>
<div>
<span><input type="text" th:field="*{name}" placeholder="name"/></span>
</div>
<div>
<span><input type="text" th:field="*{chef}" placeholder="chef"/></span>
</div>
<div>
<span><button type="submit">Invio<i class="material-icons">done</i></button></span>
</div>
</div>
</form>
and my controller like this:
#RequestMapping(value = "/newBuffet", method = RequestMethod.GET)
public String formBuffet (Model model) {
model.addAttribute("buffet", new Buffet());
return "newBuffet.html";
}
#RequestMapping(value = "/newBuffet", method = RequestMethod.POST)
public String addBuffet (#ModelAttribute("buffet") Buffet b, Model model) {
this.buffetService.save(b);
model.addAttribute("buffets", this.buffetService.listBuffets());
return "buffets.html";
}
the error it gives is, of course, because of the way Thymeleaf's input takes only strings whilst my input is an instance of my class Chef.
Related
I am trying to pass an array of ints from my HTML back to my controller.
My flow is as follows:
I am retrieving data from an API and converting it to an Entity. All works fine.
However, I pass this to my HTML (Thymeleaf) and display some of the values to the User.
They then select one of the options and this is passed back to my Controller.
It is at this stage I lose the data I need.
In my Entity, I get the following data which I pass to the View (Example Below):
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "MOVIE_ID")
private long movieId;
#JsonProperty("title")
#Column(name = "TITLE")
private String title;
#JsonProperty("overview")
#Column(name = "OVERVIEW", length = 2000)
private String overview;
#JsonProperty("popularity")
#Column(name = "POPULARITY")
private float popularity;
#JsonProperty("release_date")
#Column(name = "RELEASE_DATE")
private String releaseDate;
#JsonProperty("genre_ids")
private int[] genreIds;
Then in my view, I display some values and hide the ids I dont need to display so that I can pass them back to my controller:
<form action = "#" th:action="#{/saveMovie}" method="post" th:object="${movie}">
<tr>
<td th:text="${movie.title}"></td>
<td th:text="${movie.releaseDate}"></td>
<td th:text="${movie.overview}"></td>
<input type="hidden" id="title" name="title" th:value="*{title}"/>
<input type="hidden" id="overview" name="overview" th:value="*{overview}"/>
<input type="hidden" id="popularity" name="popularity" th:value="*{popularity}"/>
<input type="hidden" id="releaseDate" name="releaseDate" th:value="*{releaseDate}"/>
<input type="hidden" id="genreIds" name="genreIds" th:value="*{genreIds}"/>
<td>
<div class="col-auto">
<button class="btn btn-primary" type="submit">Add</button>
</div>
</td>
</tr>
</form>
Controller to handle the call:
#PostMapping("/saveMovie") public String saveMovie(#ModelAttribute(value = "movie") Movie movie)
UPDATE***
Adding the GET/POST controllers that currently interact with this page:
#GetMapping("/searchMovie")
public String searchMovie(final Model model){
List<Movie> returnedMovies = new ArrayList<>();
model.addAttribute("movies", returnedMovies);
return "Search";
}
#PostMapping("/searchMovie")
public String searchMovieInTMDB(#RequestParam(value = "movieName", required = true) String movieName,
Model model){
List<Movie> returnedMovies = service.searchMovies(movieName);
model.addAttribute("movies", returnedMovies);
return "Search";
}
#PostMapping("/saveMovie")
public String saveMovie(#ModelAttribute(value = "movie") Movie movie){
service.storeMovie(movie);
return "WORK_IN_PROGRESS";
}
However, when I pass the values back to the controller I get the conversion error:
[Failed to convert property value of type 'java.lang.String' to required type 'int[]' for property 'genreIds']
I have changed it to String[] to test this works and error goes away but then I am presented with another problem in that it is converted to :
String Value Image
The only way I have found to pass the object back is by using the input tag and hiding them.
It converts the float fine, but can't handle the array of ints.
Is there a better way to pass objects back and forth between the controller using Thymeleaf or is there another attribute I can use to pass the array back and forth?
Thanks in advance
Conor
<form action="#" th:action="#{/saveMovie}" method="post"
th:object="${movie}">
<tr>
<td th:text="${movie.title}"></td>
<td th:text="${movie.releaseDate}"></td>
<td th:text="${movie.overview}"></td>
<input type="hidden" id="title" name="title" th:value="*{title}" />
<input type="hidden" id="overview" name="overview"
th:value="*{overview}" />
<input type="hidden" id="popularity" name="popularity"
th:value="*{popularity}" />
<input type="hidden" id="releaseDate" name="releaseDate"
th:value="*{releaseDate}" />
<input type="hidden" name="genreIds" th:field="*{genreIds}" />
<td>
<div class="col-auto">
<button class="btn btn-primary" type="submit">Add</button>
</div>
</td>
</tr>
</form>
#PostMapping("/saveMovie")
public String saveMovie(#ModelAttribute Movie movie) {
System.err.println(movie);
return "redirect:/movies";
}
#GetMapping("/movies")
public String getBooks(Model model) {
Movie movie = new Movie();
movie.setGenreIds(new int[] {4,5,6,7,8});
model.addAttribute("movie", movie);
return "movie";
}
Maybe You should send numbers as List to the controller.
#PostMapping("/saveMovie")
public String saveMovie(#RequestBody List<Movie> movies){
movieService.function_name(movies);
return "movies";
}
Another way to do this is using AJAX call to the controller. Just need to collect numbers as list in javascript and through ajax you should send array as json to controller. In controller you will parse them
How to return List of Objects to Backend Service? For E.g. there are list of customer getting displayed in UI, out of which only those customers which users selects (checks in checkbox) should be returned to the backend (Controller class). But i am not able to returned the selected object back.
My code:
public class CustomerType {
private String customerName;
private String customerMsg;
private Boolean selected;
// setter
// getter
}
public class Customers {
private ArrayList<CustomerType> customerType;
// setter
// getter
}
#GetMapping(value = "/")
public String index(ModelMap modelMap) {
ArrayList<CustomerType> customerType = new ArrayList<>();
customerType.add(new CustomerType("1", "c1", null));
customerType.add(new CustomerType("2", "c2", null));
customerType.add(new CustomerType("3", "c3", null));
Customers customers = new Customers();
customers.setCustomerTypes(customerType);
modelMap.put("customers", customers);
return "index";
}
#PostMapping(value = "/save")
public String save(#ModelAttribute Customers customers, BindingResult errors, Model model) {
...
...
return "hello";
}
========== index.html ==========
...
<form id = "form" class="col-xs-12 col-sm-4" role="form"
th:action="#{/save}" method="post" th:object="${customers}">
<div class="checkbox" th:each="customerType : ${customers.customerType}" >
<input type="checkbox" id="custType" name="custType"
th:text="${customerType.customerName}" th:value="${customerType.customerMsg}" th:checked="${customerType.selected}"></input>
</div>
<div>
<p>
<button type="submit" class="btn btn-default">Submit</button>
</p>
</div>
</form>
I am able to display lists of Customers on UI e.g there are three customer c1, c2, c3 out of which if user selects c1 and c3 so after clicking on submit button those should get mapped to #ModelAttribute Customers Object in save method and that object should contain list of two Objects c1 and c3, but instead of getting 2 Objects I am receiving Null.
I am not able to get where i am going wrong.
While sending your form back to controller, be sure that transmited data reflect desired object structure. You have to provide checkboxes that correspond the checked field of the CustomerType objects and additional hidden inputs which correspond others fields of mentioned class.
Please update your form to looks like:
<form id = "form" class="col-xs-12 col-sm-4" role="form" th:action="#{/save}" method="post" th:object="${customers}">
<div class="checkbox" th:each="customerType, iterator : ${customers.customerType}" >
<input type="hidden" th:field=*{customerType[__${iterator.index}__].customerName} />
<input type="hidden" th:field=*{customerType[__${iterator.index}__].customerMsg} />
<input type="checkbox" th:field="*{customerType[__${iterator.index}__].selected}" th:text="${customerType.customerName}" ></input>
</div>
<div>
<p>
<button type="submit" class="btn btn-default">Submit</button>
</p>
</div>
</form>
With this you'll receive the Customers object containing list of all passed CustomerType objects, with selected fields evaluated to true for checked records.
The name of the input fields in the form should match the property name in the CustomerType class i.e they should be customerName and customerMsg for the Spring to be able to create and populate the corresponding CustomerType object.
I have a Springboot & Thymeleaf project that is generating the same "names" on my person inputs.
The controller looks like:
#GetMapping("/newEpisode")
public String episodeForm(Model model) {
model.addAttribute("episode", new Episode());
List<Country> countries = countryRepository.findAll();
Set<String> roles = new HashSet<>();
roles.add("Admin");
model.addAttribute("primaryPerson1",new EpisodePerson());
model.addAttribute("primaryPerson2",new EpisodePerson());
model.addAttribute("roles", roles);
model.addAttribute("countries", countries);
return "episode";
}
Some of my HTML looks like:
<input type="text" class="form-control person surname" style="text-transform: uppercase" data-property="surname" placeholder="SURNAME" th:field="${primaryPerson1.person.surname}"/>
But the generated name in the HTML for this tag is not unique:
<input type="text" class="form-control person surname" style="text-transform: uppercase" data-property="surname" id="surname1" placeholder="SURNAME" name="person.surname" value="">
Why are all the person tags in the html sharing the same name for example I have two :
name="person.surname"
You've misused the th:field attribute.
Its aim is to bind your input with a property in the form-backing bean. So you should either create separate forms for each object and use it in following manner:
<!-- Irrelevant attributes omitted -->
<form th:object="${primaryPerson1}">
<input th:field="*{person.surname}"/>
</form>
...or create a form-backing bean, which would combine both of your objects, e.g.:
public class EpisodeFormBean {
private List<EpisodePerson> episodePersons;
//getter and setter omitted
}
...then add it to a model in your episodeForm method...
EpisodeFormBean episodeFormBean = new EpisodeFormBean();
episodeFormBean.setEpisodePersons(Arrays.asList(new EpisodePerson(), new EpisodePerson()));
model.addAttribute("episodeFormBean", episodeFormBean);
...and use it in your template as follow:
<!-- Irrelevant attributes omitted -->
<form th:object="${episodeFormBean}">
<input th:field="*{episodePersons[0].person.surname}"/>
<input th:field="*{episodePersons[1].person.surname}"/>
</form>
In the second solution generated names would be unique. I think it's more suitable for your needs.
You should check out Tutorial: Thymeleaf + Spring as there it is well explained. Especially you should notice a phrase:
Values for th:field attributes must be selection expressions (*{...}),
which makes sense given the fact that they will be evaluated on the
form-backing bean and not on the context variables (or model
attributes in Spring MVC jargon).
I've been looking for something that might help me to solve this without success. What I need is just to call a Spring Controller by pressing a Button element, and pass from it a RequestParam("statusId" in this specific case). Is there a way to do this without using JavaScript?
I have the next html:
<div class="tablero col-lg-4 col-md-4 col-sm-6">
<div class="inner-content">
<div class="rate">
<div class="number">
<span>${package}</span>
<span class="text">REFERRALS</span>
</div>
</div>
<div class="description">
<h3>
<i class="fa fa-shopping-bag"></i>
PACKAGE
</h3>
<label>Paquete</label>
<button class="btn-primary" onclick="location.href='listReferred.htm' id="package">GO TO LIST</button><!--The parameter should be send from this button-->
</div>
</div>
</div>
And the Spring MVC Controller:
#SuppressWarnings("unchecked")
#RequestMapping(value="/listReferred", method=RequestMethod.GET)
public String getListReferredPage(#RequestParam int statusId, Model model) {
RestTemplate restTemplate = new RestTemplate();
String url = URL_REFERREDTYPE_JSON+statusId;
List<SearchProspectTO> searchProspectToList = restTemplate.getForObject(url, List.class, statusId);
model.addAttribute("searchProspectToList", searchProspectToList);
return "portalInternoReferidos";
}
Surround at least the button element with a form, like this:
<form action="listReferred" method="get">
<button...
</form>
Add a name and value attribute to the button:
<button name="yourButton" value="[provide status id here]">GO TO LIST</button>
Alter #RequestParam int statusId to #RequestParam(value="yourButton") int statusId.
This will work except for older IE browsers - below Version 10 I think. These versions will return 'GO TO LIST' instead of the value.
As workaround you could use a hidden input, that has to be placed inside the form section as well.
I need a help about ZK framework. This is my situation.
I have a html page:
<form id="frm1" action="http://localhost:8080/spuWebApp" METHOD="POST">
<input type="hidden" id="codigoUnicoCliente" name="codigoUnicoCliente" value="00000050055255">
<input type="button" onclick="myFunction()" value="Invar Spu POST URL">
</form>
Then, after submitting the form, my zk project recieves the data in bridge.zul.
<?init class="com.ibm.ibk.spu.view.BridgeChecker"?>
This class contains the following
public class BridgeChecker extends BaseWindow implements Initiator{
#Override
public void doInit(Page arg0, Map<String, Object> arg1) throws Exception {
Bridge bridge = new Bridge();
logger.debug("ANTIGUA MANERA");
logger.debug(Executions.getCurrent().getParameterMap());
logger.debug(Executions.getCurrent().getArg());
logger.debug(Executions.getCurrent().getAttributes());
bridge.setClienteCodigoUnicoFromURL(Executions.getCurrent().getParameter("codigoUnicoCliente"));
But I cant read the value.
I am racking my brain a lot. But I couldnt succeed in find out how to read the values. Someone who can help me to read the form-data. I'd appreciate it a lot.
Thanks in advanced.
it work with Executions.getCurrent().getParameter("codigoUnicoCliente") but I do not know what myFunction() do, so I replace it with this code:
<form id="frm1" action="test.zul" METHOD="POST">
<input type="hidden" id="codigoUnicoCliente" name="codigoUnicoCliente" value="00000050055255">
<input type="submit" value="Invar Spu POST URL">
</form>
Then, I use following in test.zul
<window apply="org.zkoss.bind.BindComposer" viewModel="#id('vm') #init('test.vm.TestViewModel')">
and then in TestViewModel
#Init
public void init(#ContextParam(ContextType.SESSION) Session session) {
System.out.println(Executions.getCurrent().getParameter("codigoUnicoCliente"));
}
and work like charm :)