Form's dropdown menu selected items are null - spring-boot

My problem is very strange. I have a small form which has two drop down menus to select items and create a new item with those two included. Here is the object's most basic values:
public class Rental {
private Integer id;
private Movie movie;
private Client client;
}
The problem is as follows. My HTML file has this form:
<h1>Add New Rental</h1>
<form action="#" th:action="#{/rentals/add}" th:object="${rental}" method="post" >
<div class="form-group col-md-8">
<label for="client" class="col-form-label">Client</label>
<select class="form-control" th:field="*{client}" id="client">
<option disabled selected="selected" value="0">Select Client</option>
<option th:each="clnt : ${listClients}" th:value="${clnt}" th:text="${clnt.name + ' ' + clnt.lastname}"></option>
</select>
</div>
<div class="form-group col-md-8">
<label for="movie" class="col-form-label">Movie</label>
<select class="form-control" th:field="*{movie}" id="movie">
<option disabled selected="selected" value="0">Select Movie</option>
<option th:each="mov : ${listMovies}" th:value="${mov}" th:text="${mov.title}"></option>
</select>
</div>
<div class="col-md-6">
<input type="submit" class="btn btn-primary" value=" Submit ">
</div>
</form>
And the controller that handles this page is as follows:
#RequestMapping(path = "/rentals", method = RequestMethod.GET)
public String listRentals(Model model) {
model.addAttribute("rental", new Rental());
model.addAttribute("listRentals", this.MCRService.getRentals());
model.addAttribute("listClients", this.MCRService.getClients());
model.addAttribute("listMovies", this.MCRService.getMovies());
return "rentals";
}
#RequestMapping(value = "/rentals/add", method = RequestMethod.POST)
public String addRental(#ModelAttribute("rentals") Rental rent) {
Client client = this.MCRService.getClient(rent.getClient().getId());
Movie movie = this.MCRService.getMovie(rent.getMovie().getId());
if (((client.getRentalCollection().size() + 1) * 10) <= client.getBalance()) {
client.addMovie(movie);
this.MCRService.updateClient(client);
this.MCRService.updateMovie(movie);
}
return "redirect:/rentals";
}
But when I run this, select both a client and a movie, and I press submit, the console throws a NullPointerException, and turns out that the client and the movie are both null, which is weird since I'm using the entire object in the selection. What am I doing wrong here? Is it some sort of problem with the th:value and th:field? Or is my code flawed? Any help is appreciated!

I've solved it in this way. The changes to the html were in addding selectpicker to the select's class and changing the client's and movie's option for each's value to the id.
<select class="form-control selectpicker" th:field="*{client}" id="client">
<option disabled selected="selected" value="0">Select Client</option>
<option th:each="clnt : ${listClients}" th:value="${clnt.id}" th:text="${clnt.name + ' ' + clnt.lastname}"></option>
<select class="form-control selectpicker" th:field="*{movie}" id="movie">
<option disabled selected="selected" value="0">Select Movie</option>
<option th:each="mov : ${listMovies}" th:value="${mov.id}" th:text="${mov.title}"></option>
The java wasnt modified greatly, but with those three changes, the whole thing works!

Related

Livewire - Dependant Dropdown select

I have created a dependant dropdown with livewire like this:
class CreateAppointment extends Component
{
public $doctorCategories;
public $doctors;
public $selectedDoctorCategory = NULL;
public function mount(){
$this->doctorCategories = Doctor_Categories::all();
$this->doctors = collect();
}
public function updatedSelectedDoctorCategory($doctor_type_ID)
{
if(!is_null($doctor_type_ID)){
$this->doctors = Doctor_Categories::with('doctors')->find($doctor_type_ID);
}
}
}
And this is in my blade file:
<div class="form-group row">
<label for="doctor_categories" class="col-md-4 col-form-label text-md-right">Doctor Categories</label>
<div class="col-md-6">
<select wire:model="selectedDoctorCategory" class="form-control">
<option value="">Choose category</option>
#foreach($doctorCategories as $cat)
<option value="{{ $cat->id }}">{{ $cat->doctor_category }}</option>
#endforeach
</select>
</div>
</div>
#if (!is_null($selectedDoctorCategory))
<div class="form-group row">
<label for="doctor" class="col-md-4 col-form-label text-md-right">Doctor</label>
<div class="col-md-6">
<select class="form-control" name="doctor_id">
<option value="" selected>Choose Doctor</option>
#foreach($doctors->doctors as $doctor)
<option value="{{ $doctor->id }}">{{ $doctor->name }}</option>
#endforeach
</select>
</div>
</div>
#endif
</div>
It works well but when i select "Choose category" again it throws an error saying attempted to read property doctors on null.How can i avoid this?
The issue here is, that livewire does not apply the TrimStrings and ConvertEmptyStringsToNull middlewares on its requests. This is by design and is not a bug. It can be reintroduced (see the comments to the linked issue) but I advise caution doing so. With select it should work fine, but with input it can mess things up.
Instead of checking for is_null, check for empty and you should be fine.

Edit Form method Fill (package vform)

I request help me with this situation, I am trying to show a form to edit it but the idrol field returns an object, how can I access it to show me the user's role correctly
<div class="form-group row">
<label class="col-md-3 form-control-label" for="text-input">Asignar Rol</label>
<div class="col-md-9">
<select class="form-control" :class="{'is-invalid': form.errors.has('idrol')}"
v-model="form.idrol"
name="idrol">
<option value="0" disabled>Seleccione Rol</option>
<option v-for="role in arrayRoles" :key="role.id" :value="role.id" v-text="role.name">
</option>
</select>
<has-error :form="form" field="idrol"></has-error>
</div>
</div>
Without using the fill method, I can access the property as follows
this.idrol =data['roles'][0].id it shows the role,
but in this way I would not be taking advantage of the benefits of the vform package
Edit Method
editModal(user) {
console.log(user);
let me = this;
me.form.reset();
me.form.clear();
me.modal = 1;
me.tipoAccion = 2;
me.form.fill(user);
}
I appreciate your help

How do I pass the selected dropdown value to a controller in Thymeleaf?

How to transfer the selected value of the drop-down list (Thymeleaf) to the controller (Spring)? The list itself is formed normally, the problem is in the button.
Controller:
#RequestMapping(value="courier/notInTime", method = RequestMethod.POST)
public String deleteUser (#RequestParam String task) {
System.out.println(task);
return "redirect:/courier";
}
View:
<div class="taskList" th:object="${task}">
<select class="form-control" id="courierTasks" name="courierTasks">
<option value="">Select task for disable</option>
<option th:each="task : ${tasks}"
th:value="${task}"
th:text="${task}">
</option>
</select>
<form th:action="#{/courier/notInTime}" method="post">
<input type="hidden"/>
<button type="submit">Not in time</button>
</form>
</div>
You just change #RequestParam to #Valid in your controller then change your select name to "task" in Thymeleaf and it should be into the form wrapper.
#RequestMapping(value="courier/notInTime", method = RequestMethod.POST)
public String deleteUser (#Valid String task) {
System.out.println(task);
return "redirect:/courier";
}
<select class="form-control" id="courierTasks" name="task">
<option value="">Select task for disable</option>
<option th:each="task : ${tasks}"
th:value="${task}"
th:text="${task}">
</option>
</select>
You should add the select tag inside the form, so the form submits the task.
Try the following
<form th:action="#{/courier/notInTime}" method="post">
<div class="taskList" th:object="${task}">
<select class="form-control" id="courierTasks" name="courierTasks">
<option value="">Select task for disable</option>
<option th:each="task : ${tasks}"
th:value="${task}"
th:text="${task}">
</option>
</select>
<input type="hidden"/>
<button type="submit">Not in time</button>
</div>
</form>
Note that you can write a simple javascript function so the form submits the task even if its outside the form, however, I cannot see the reason not to add the select in the form at your case.
#Sopheak #Ioannis many thx.
Controller:
#RequestMapping(value="courier/notInTime", method = RequestMethod.POST)
public String deleteUser (#Valid String task) {
System.out.println(task);
return "redirect:/courier";
}
View:
<form th:action="#{/courier/notInTime}" method="post">
<select class="form-control" id="task" name="task">
<option value="">Select task for disable</option>
<option th:each="task : ${tasks}"
th:value="${task}"
th:text="${task}">
</option>
</select>
<button type="submit">Not in time</button>
</form>

Thymeleaf dynamic form action does not work

I am loading the home.html page by setting the following model attributes:
#GetMapping("/")
private String getHomePage(Model model) {
model.addAttribute("allUsers", this.userService.findAll());
model.addAttribute("user", new User());
model.addAttribute("queryResult", "");
model.addAttribute("errors", new ArrayList<>());
return "home";
}
and here is my form for updating a user's data:
<form action="#" th:action="#{/user/{username}(username=${user.username})}" th:object="${user}" th:method="put">
<label for="username">Username</label>
<select th:field="*{username}" id="username">
<option th:each="singleUser : ${allUsers}" th:value="${singleUser.username}" th:text="${singleUser.username}"></option>
</select>
<label for="password">Password</label>
<input type="password" th:field="*{password}" id="password" >
<span th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></span>
<label for="status">Status</label>
<select th:field="*{status}" id="status">
<option th:value="'Activated'" th:text="Activated"></option>
<option th:value="'Deactivated'" th:text="Deactivated"></option>
</select>
<button type="submit">UPDATE DATA</button>
</form>
When I try to submit this form, it does not bind the username to the URL.
instead of having /user/whateverUsername I have only /user.
I need to bind the value of this select element:
<select th:field="*{username}" id="username">
<option th:each="singleUser : ${allUsers}" th:value="${singleUser.username}" th:text="${singleUser.username}"></option>
</select>
How can I solve this problem?
Thank you very much!

Spring how to use select with Thymeleaf [duplicate]

I want to create a drop down menu that allows a client to search users by a field specified in the drop down menu. For example, search by state, search by city, etc.
This is what I have so far:
<p>Search options:</p>
<form action="#" th:action="#{/get/{value}" method="get">
<select>
<option th:value="AllUsers">Search all users</option>
<option th:value="ByUsername">Search by user name</option>
<option th:value="ByFirstname">Search by first name</option>
<option th:value="ByLastname">Search by last name</option>
<option th:value="ByAddress">Search by address</option>
<option th:value="ByCity">Search by city</option>
<option th:value="ByState">Search by state</option>
<option th:value="ByZipCode">Search by zip code</option>
<option th:value="ByPhoneNumber">Search by phone number</option>
<option th:value="ByEmail">Search by email</option>
</select>
<input type="text" th:field="value" name="searchField"/>
<input type="submit" value="Search" name="searchButton"/>
</form>
I'm just not sure how to connect the action and the value tag of the currently selected item in the drop down list to specify the URI. If a user selects, search by state, and he enters in "Maryland", how do I specify the corresponding URI tag?
This would be my method in Spring that executes the action:
#RequestMapping(value = "/get/ByState", method = RequestMethod.GET)
public String getByState() {
// ...
}
#RequestMapping(value = "/get/ByCity", method = RequestMethod.GET)
public String getByCity() {
// ...
}
Because the accepted answer is not using Thymeleaf and this question is top in Google I'm adding my solution here.
In my situation statues is a list of Enum values. Model attribute is populated as usually you do in Spring:
mav.addObject("statuses", EnumSet.allOf(Status.class));
Group has a filed of type Status (the enum).
<div class="form-group row">
<select class="form-control" id="status" name="status">
<option th:each="stat : ${statuses}"
th:value="${stat}"
th:text="${stat}"
th:selected="${stat.equals(group.status)}"/>
</select>
</div>
This automatically populates the list and selects value that is selected in my Group instance:
You have just the required answer in this link:
http://fruzenshtein.com/spring-mvc-form-select-tag/

Resources