Thymeleaf dynamic form action does not work - spring

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!

Related

How can I send data from a form into the table in the database?

I have a form that adds a new property listing into the properties table in the db. I keep getting errors that inputs are null and also Laravel isn't grabbing the value inputted into the select HTML tag. I am putting data into the form, but it keeps telling me the fields are null.
Add property form:
<h1 class="admin-header">Add New Listing</h1>
#if($errors->any())
<h4>{{$errors->first()}}</h4>
#endif
<form method="POST" action="{{ route('admin.store_properties') }}" id="add_property_form" enctype="multipart/form-data">
#csrf
<div>
<label for="prop_title">Property Title</label>
<input type="text" id="prop_title" />
</div>
<div>
<label for="prop_desciption">Property Description</label>
<textarea name="prop_desciption" id="prop_desciption"></textarea>
</div>
<div>
<label for="prop_img">Property Image</label>
<input type="file" name="prop_img" id="prop_img" required />
</div>
<div>
<label for="prop_beds">Number of Bedrooms</label>
<input type="number" name="prop_beds" id="prop_beds" steps="1" min="1" />
</div>
<div>
<label for="prop_baths">Number of Bathrooms</label>
<input type="number" name="prop_baths" id="prop_baths" />
</div>
<div>
<label for="prop_ft">Sqaure Feet</label>
<input type="number" name="prop_ft" id="prop_ft" />
</div>
<div>
<label for="props_basement">Finished Basement?</label>
<select name="props_basement" id="props_basement">
<option value="" selected disabled>Select an option</option>
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
<div>
<label for="prop_tax">Property Tax</label>
<input type="number" name="prop_tax" id="prop_tax" />
</div>
<div>
<label for="props_heat">Heat Type</label>
<select name="props_heat" id="props_heat">
<option value="" selected disabled>Select an option</option>
<option value="gas">Gas</option>
<option value="oil">Oil</option>
<option value="electric">Electric</option>
</select>
</div>
<div>
<label for="props_waterheater">Finished Basement?</label>
<select name="props_waterheater" id="props_waterheater">
<option value="" selected disabled>Select an option</option>
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
<div>
<label for="prop_year">Year Built</label>
<input type="number" name="prop_year" id="prop_year" />
</div>
<button type="submit">Add New Listing</button>
</form>
Route:
Route::group(['prefix' => 'admin'], function() {
Route::get('/', function() {
return view('admin.dashboard');
})->middleware('auth');
Route::get('/properties', [PropertiesController::class, 'index'])->middleware('auth');
Route::get('/properties/create', [PropertiesController::class, 'create'])->middleware('auth');
Route::post('/properties/store-post', [PropertiesController::class, 'store'])->name('admin.store_properties')->middleware('auth');
});
Controller store() method:
public function store(Request $request)
{
// Create a new Property and store it in the properties DB
$prop = new Property;
$path;
if ($request->hasFile('prop_img')) {
// Get filename with extension
$filenameWithExt = $request->file('prop_img')->getClientOriginalName();
// Get just filename
$filename = pathinfo($filenameWithExt, PATHINFO_FILENAME);
// Get just extension
$extension = $request->file('prop_img')->getClientOriginalExtension();
// Filename to store
$filenameToStore = $filename . '_' . time() . '.' . $extension;
// Upload Image
$path = $request->file('prop_img')->storeAs('public/property_images', $filenameToStore);
} else {
// Filename to store
$filenameToStore = 'noimage.jpg';
}
$prop->property_title = $request->input('prop_title');
$prop->property_description = $request->input('prop_desc');
$prop->property_image = $path;
$prop->bedrooms = $request->input('prop_beds');
$prop->bathrooms = $request->input('prop_baths');
$prop->square_feet = $request->input('prop_ft');
$prop->finished_basement = $request->input('prop_basement');
$prop->prop_tax = $request->input('prop_tax');
$prop->heat_type = $request->input('prop_heat');
$prop->water_heater = $request->input('prop_waterheater');
$prop->year_built = $request->input('prop_year');
$prop->save();
return view('admin.add_property');
}
I can see a typo in your code
In blade file you used tag name 'props_basement' but in controller you are using 'prop_basement'
Try this to fix:
<select name="prop_basement" id="props_basement">
<option value="" selected disabled>Select an option</option>
<option value="yes">Yes</option>
<option value="no">No</option>
</select>

Spring Boot, Thymeleaf, Error during execution of processor

I have this thymeleaf template and I cannot find a way to make it work. The thymeleaf template is coded to do a post form like this:
<form class="mx-auto" method="post" th:object="${provideForm}">
<div class="mb-3">
<label class="form-label">Paciente</label>
<select class="form-select" th:field="*{pet}" >
<option selected>Seleccione su Mascota</option>
<option th:each="i : ${p}" th:value="${i.index}" th:utext="${i}"></option>
</select>
</div>
<div class="mb-3">
<label class="form-label">Servicio</label>
<select class="form-select" aria-label="Default select example" th:field="*{service}" >
<option selected>Seleccione el Servicio</option>
<option th:each="i : ${s}" th:value="${i.index}" th:utext="${i}"></option>
</select>
</div>
<div class="mb-3">
<label class="form-label">Lugar</label>
<select class="form-select" aria-label="Default select example" th:field="*{veterinary}">
<option selected>Seleccione la Veterinaria</option>
<option th:each="i : ${v}" th:value="${i.index}" th:utext="${i}"></option>
</select>
</div>
<div class="mb-3">
<label class="form-label">Fecha</label>
<input type="date" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" th:field="*{date}">
</div>
<div class="mb-3">
<label class="form-label">Hora</label>
<select class="form-select" th:field="*{time}">
<option th:each="i : ${#numbers.sequence(0,6)}" th:value="${i}" th:text="'1' + ${i} + ':00:00'"></option>
</select>
</div>
<button type="submit" class="btn btn-primary">Agregar</button>
<button type="button" class="btn btn-outline-danger">Cancelar</button>
</form>
The spring boot is trying to pass the arrays like this:
#GetMapping(value="/appointmentsView")
public ModelAndView appointmentsView(){
if(!Objects.nonNull(authUser)){
return login();
}
updateInfo();
ModelAndView mv = new ModelAndView("appoitnmentsView");
List<String> displayPets = new ArrayList<String>();
for(Pet p : pets){
displayPets.add(p.getName());
}
mv.addObject("p", displayPets);
List<String> displayServices = new ArrayList<String>();
for(Services s : services){
displayServices.add(s.getService_name());
}
mv.addObject("s", displayServices);
List<String> displayVeterinaries = new ArrayList<String>();
for(Veterinary v : veterinaries){
displayVeterinaries.add(v.getVeterinary_name());
}
mv.addObject("v", displayVeterinaries);
return mv;
}
I am always getting a 500 error code:
org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringSelectFieldTagProcessor' (template: "appointmentsView" - line 38, col 47)
at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:117) ~[thymeleaf-3.0.12.RELEASE.jar:3.0.12.RELEASE]
at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95) ~[thymeleaf-3.0.12.RELEASE.jar:3.0.12.RELEASE]
The only way I could fix this problem is by moving the th:field that are on the select tags to the option tags. However, by doing that it always return null on the th:field

multimple select2 with laravel vue js not working

i want to make dynamic form .so for that i tried foreach loop .everything going fine without select options. For making classname or id name unique i want place a index value but cant not place index value.take a look below:
<div class="form-group m-form__group row " v-for="(pack,index) in packs">
<div class="col-lg-3">
<label>SKU: #{{ index }}</label>
<input v-model="pack.sku" type="text" name="name" class="form-control m-input" placeholder="SKU">
</div>
<div class="col-lg-3">
<label>Unit:</label>
<select class="form-control select2 #{{ index }}" name="unit" v-model="pack.unit" >
<option value="0">KG</option>
<option value="1">ML</option>
<option value="2">Liter</option>
</select>
</div>
<div class="col-lg-3">
<label>Size:</label>
<input v-model="pack.size" type="number" name="name" class="form-control m-input" placeholder="Size">
</div>
<div class="col-lg-3">
<label>Barcode:</label>
<input v-model="pack.barcode" type="number" name="barcode" class="form-control m-input" placeholder="Barcode">
</div>
</div>
you need to reload select2.
html markup:
<select class="form-control select2 #{{ index }}" name="unit" v-model="pack.unit" id="unit">
<option value="0">KG</option>
<option value="1">ML</option>
<option value="2">Liter</option>
</select>
Vuejs code:
...
components: {
},
mounted() {
setTimeOut(() => {
let unit = $('#unit'); // or document.querySelector('#unit');
unit.select2();
}, 100);
},

Request method 'POST' not supported

I have a spring-Boot application, and
I am trying to send an object using post method to the below controller:
#PostMapping("/suggestevent")
public String receiveSuggestedEvent(#ModelAttribute SuggestedEvent event) {
return "redirect:/suggestEvent";
}
but it complains with:
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'POST' not supported
So, what is wrong?
Update:
I have tried this and it also did not work
#RequestMapping(value = "/suggestevent", method = RequestMethod.POST)
The form contains some simple inputes, and a select, which works based on Thyemeleaf. Here is my form:
<form th:action="#{/suggestevent}" method="post">
<div class="form-group">
<label for="title">Title</label>
<input type="text"
class="form-control" id="title" placeholder="Event title"
th:value="${event.title}"
name="title" required="required"/>
</div>
<div class="form-group">
<label for="mainFouce">Main Focus</label>
<input type="text"
class="form-control" id="Focus" placeholder="Focus"
th:value="${event.mainFouce}"
name="Focus" required="required"/>
</div>
Event Type
<div class="form-group">
<select class="form-control" name="type" th:value="${event.type}">
<option value="volvo">Party</option>
<option value="saab">Workshop</option>
<option value="fiat">Friendship</option>
</select>
</div>
<div class="form-group">
<label for="city">Area</label>
<input type="text"
class="form-control" id="area"
th:value="${event.area}"
placeholder="Berlin, Estonia ,or even Asia" name="area"
required="required"/>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea name="description" class="form-control"
th:value="${event.description}"
required="required" form="usrform"
placeholder="What makes it an special event?"></textarea>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
The sent object is:
#Entity
#Data
public class SuggestedEvent {
#Id
#GeneratedValue
Long id;
String title;
String mainFouce;
EventType type;
String area;
String description;
}
The postman can successfully reach the controller, but the thyemeleaf complains!!!
What happens when you try to add an empty SuggestedEvent object inside the form and try to populate that object like so:
<form th:action="#{/suggestevent}" th:object="${event}" method="post">
<div class="form-group">
<label for="title">Title</label>
<input type="text"
class="form-control" id="title" placeholder="Event title"
th:value="*{title}"
name="title" required="required"/>
</div>
<div class="form-group">
<label for="mainFouce">Main Focus</label>
<input type="text"
class="form-control" id="Focus" placeholder="Focus"
th:value="*{mainFouce}"
name="Focus" required="required"/>
</div>
Event Type
<div class="form-group">
<select class="form-control" name="type" th:value="*{type}">
<option value="volvo">Party</option>
<option value="saab">Workshop</option>
<option value="fiat">Friendship</option>
</select>
</div>
<div class="form-group">
<label for="city">Area</label>
<input type="text"
class="form-control" id="area"
th:value="*{area}"
placeholder="Berlin, Estonia ,or even Asia" name="area"
required="required"/>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea name="description" class="form-control"
th:value="*{description}"
required="required" form="usrform"
placeholder="What makes it an special event?"></textarea>
</div>
<button class="btn btn-default">Submit</button>
</form>
And in the #GetMapping("/suggestEvent"):
#GetMapping("/suggestEvent")
public String getSuggestEventPage(Model model) {
model.addAttribute("event", new SuggestEvent());
return "suggestEventPage";
}
Check out the official Thymeleaf doc otherwise. This shouldn't really be a problem, since I am doing the exact same thing in my project.
http://www.thymeleaf.org/doc/articles/standarddialect5minutes.html
http://www.thymeleaf.org/doc/articles/springmvcaccessdata.html
http://www.thymeleaf.org/documentation.html

How to do server side validation in spring mvc using validator class

Hi am new to spring mvc i have to do sever side validation using separate validator class. i have two model with one to many relation i have to register them before register them i am new server side validation in spring mvc to use spring form and all
<form id="studentEnrollmentForm" method="post" class="form-horizontal" action="saveStudentByAdmin">
<div class="form-group">
<label class="col-xs-2 control-label">Student Full Name</label>
<div class="group">
<div class="col-xs-3">
<input type="text" class="form-control" name="studentFirstName" id="fn" placeholder="First name" />
</div>
</div>
<div class="col-xs-3">
<input type="text" class="form-control" name="studentMiddleName" placeholder="Middle name" />
</div>
<div class="col-xs-3">
<input type="text" class="form-control" name="studentLastName" placeholder="Last name" />
</div>
</div>
<div class="form-group">
<label class="col-xs-2 control-label">Parents Full Name</label>
<div class="col-xs-3">
<input type="text" class="form-control" name="parentFirstName" placeholder="First name" />
</div>
<div class="col-xs-3">
<input type="text" class="form-control" name="parentMiddleName" placeholder="Middle name" />
</div>
<div class="col-xs-3">
<input type="text" class="form-control" name="parentLastName" placeholder="Last name" />
</div>
</div>
<div class="form-group">
<label class="col-xs-2 control-label">Date-of-birth</label>
<div class="col-xs-3 ">
<div class="input-group input-append date" id="studentDOB">
<input type="Text" class="form-control" name="studentDOB" /> <span
class="input-group-addon add-on"><span
class="glyphicon glyphicon-calendar"></span></span>
</div>
</div>
<label class="col-xs-3 control-label">Gender</label>
<div class="col-xs-3">
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-default">
<input type="radio" name="studentGender" value="male" />Male</label>
<label class="btn btn-default">
<input type="radio" name="studentGender" value="female" />Female</label>
</div>
</div>
</div>
<div class="form-group">
<label class="col-xs-2 control-label">Phone</label>
<div class="col-xs-3">
<input type="text" class="form-control" name="parentPhoneNumber" placeholder="Phone number" />
</div>
<label class="col-xs-3 control-label">Email</label>
<div class="col-xs-3">
<input type="text" class="form-control" name="parentEmail" placeholder="Email" />
</div>
</div>
<div class="form-group">
<label class="col-xs-2 control-label">Permanent Address</label>
<div class="col-xs-3">
<textarea class="form-control" rows="3" name="studentPermanentAddress" /></textarea>
</div>
<label class="col-xs-3 control-label">Present Address</label>
<div class="col-xs-3">
<textarea class="form-control" rows="3" name="studentPresentAddress" /></textarea>
</div>
</div>
<div class="form-group">
<label class="col-xs-2 control-label">Class to join</label>
<div class="col-xs-3">
<!-- <input type="text" class="form-control" name="className" placeholder="Enter Class" /> -->
<select name="className" class="form-control">
<option value="">Select class </option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-xs-1 ">
<button type="submit" class="btn btn-primary ">Submit</button>
</div>
<div class="col-xs-1 ">
<button type="reset" class="btn btn-default" id="rstbutton">Refresh</button>
</div>
</div>
</form>
Controller
#Controller
#RequestMapping("/")
public class AdminRegistrationController {
#Autowired
private IAdminRegistrationService adminRegistrationService;
#RequestMapping(value = "/register", method = RequestMethod.GET)
public String viewRegistrationPage(Model model) {
StudentDTO studentDTO = new StudentDTO();
ParentDTO pdto=new ParentDTO();
model.addAttribute("teacherDTO", studentDTO);
model.addAttribute("teacherDTO", pdto);
return "StudentEnrollmentByAdmin";
}
#RequestMapping(value = "/saveStudentByAdmin", method = RequestMethod.POST)
public String saveTeacherByAdmin(#ModelAttribute StudentDTO sdto,#ModelAttribute ParentDTO pdto) {
System.out.println(sdto.getStudentFirstName());
System.out.println(pdto.getParentFirstName());
return "redirect:/register"; // this line redirecting to above method to avoid same data insertion again when i press f5
//return "TeacherEnrollmentByAdmin"; To know duplication insertion comment above line and above method current this line
//when you get response page(after insertion of data) press f5 and see in data base
}
}
My Example validator class
#Component
public class StudentRegistrationFromAdminValidator implements Validator{
public boolean supports(Class<?> clazz) {
return StudentDTO.class.isAssignableFrom(clazz);
//return ParentDTO.class.isAssignableFrom(clazz);
}
public void validate(Object target, Errors errors) {
StudentDTO student = (StudentDTO)target;
ParentDTO parent = (ParentDTO)target;
String studentFirstName = student.getStudentFirstName();
String parentFirstName=parent.getParentFirstName();
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "studentFirstName", "student.studentFirstName.empty");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "parentFirstName", "parent.parentFirstName.empty");
if(studentFirstName.equals("pradee")){
errors.rejectValue("studentFirstName", "student.studentFirstName.invalid");
}
if(parentFirstName.equals("pradee")){
errors.rejectValue("parentFirstName", "parent.parentFirstName.invalid");
}
}
}
In StudentDTO and ParentDTO classes, you can give various validator annotations from javax.validation.constraints package and org.hibernate.validator.constraints package(if using hibernate).
public class StudentDTO {
#Size(min=6, max=12)
private String firstName;
#Size(min=6, max=12)
private String lastName;
//getter setter
}
Then add javax.validation.Valid annotation and
org.springframework.validation.BindingResult interface in controller method as follows.
#RequestMapping(value = "/saveStudentByAdmin", method = RequestMethod.POST)
public String saveTeacherByAdmin(#Valid #ModelAttribute StudentDTO sdto,#ModelAttribute ParentDTO pdto,
BindingResult bindingResult) {
if(bindingResult.hasErrors()) {
System.out.println(bindingResult.getAllErrors().get(0).getDefaultMessage());
}
}

Resources