This is what we have in the interface:
I pasted the parts of the code what I thought that are relevant, but maybe something more is required.
How it works
When the button is pushed, the userController.js save method is invoked. In the controller there is a $resource and the $save method is "connected" with the create method in UserController.java, and there is persisted.
The problem
In the interface I have three inputs (dd, mm, yy) and what I want to persist is a User with a java.time.LocalDate. How and where should I do the map/transformation of these three inputs to convert then in a LocalDate? Because obviously, the way the User is defined in the .js and the way is defined in .java are differents.
In the frontend
user.html
<div class="form-group">
<label class="col-sm-2 control-label">Date of Birth</label>
<div class="col-sm-10">
<div class="form-inline">
<div class="form-group">
<label class="sr-only" for="txt_day">Enter Day</label>
<div class="col-sm-2">
<input type="text" id="txt_day" ng-model="user.birthdate.day" class="form-control" placeholder="DD" required maxlength="2"
data-validation-required-message="Day is required">
</div>
</div>
<div class="form-group">
<label class="sr-only" for="txt_month">Enter Month</label>
<div class="col-sm-2">
<input type="text" id="txt_month" ng-model="user.birthdate.month" class="form-control" placeholder="MM" required
maxlength="2" data-validation-required-message="Month is required">
</div>
</div>
<div class="form-group">
<label class="sr-only" for="txt_year">Enter Year</label>
<div class="col-sm-2 ">
<input type="text" id="txt_year" ng-model="user.birthdate.year" class="form-control" placeholder="YY" required
maxlength="4" data-validation-required-message="Year is required">
</div>
</div>
</div>
</div>
</div>
userController.js
$scope.user = new UserService();
$scope.save = function() {
$scope.user.$save(function() {
$location.path('/');
});
};
UserService.js
return $resource('rest/user/:action', {},....
In the backend
UserController.java
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public User create(User user) {
LOGGER.info("create(): " + user);
return this.userDao.save(user);;
}
Entity
#Column(nullable = false)
#Convert(converter = LocalDatePersistenceConverter.class)
private LocalDate birthDate;
Well, honestly I see that your application is exposing your domain entities to outside through rest service. I wouldn't suggest to do in order to ensure separation of concern principle. This issue you are now having is because of that. If adding a services/dto layers is a bit cucumber in your application, one workaround could be:
#Entity
public class User{
#Column(nullable = false)
#Convert(converter = LocalDatePersistenceConverter.class)
private LocalDate birthDate;
#Transient
private birthDay
#Transient
private birthMonth
#Transient
private birth birthYear
..
#PrePersist
protected void prePersist()
{
birthDate = new LocalDate(birthDay, birthMonth, birthYear)
}
}
So your entity gets populated from your javascript component and the jpa provider makes the tweaking creating a jodatime object.
Hope this works
Related
I have an app where students can register and login and having a field called city.
I'm trying to make a dropdown of cities so the student can pick which city he wants from there. It's a long list so I made a function in StudentService which will return array of strings and I'm trying to send it to the form using model.attribute but it's not working.
I tried using ajax and JQuery with external json file of the cities and it still didn't work even after I looked several questions here. If you have any idea how it is best to handle it please let me know.
here is the code so far and what I tried:
Service:
public class StudentService implements StudentInterfaceService {
// regular function of get, create, delete, update
public String [] getCities() {
String [] cities = { "lots of cities here };
return cities;
}
}
Controller:
public class RegistrationController {
#Autowired
private StudentService studentService;
public RegistrationController(StudentService studentService){
super();
this.studentService = studentService;
}
#ModelAttribute("student")
public StudentRegistration studentInfo() {
return new StudentRegistration();
}
#GetMapping
public String showRegistrationForm(Model model) {
String [] cities = studentService.getCities();
model.addAttribute("cities", cities);
return "registration";
}
#PostMapping
public String registerStudent(#ModelAttribute("student") StudentRegistration studentInfo) {
studentService.saveStudent(studentInfo);
return "redirect:/registration?success";
}
}
Html:
<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="ISO-8859-1">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<!-- success message -->
<div th:if="${param.success}">
<div class="alert alert-info">You've successfully registered
to our awesome app!</div>
</div>
<h1>Registration</h1>
<form th:action="#{/registration}" method="post" th:object="${student}">
<div class="form-group">
<label class="control-label" for="username"> Username </label>
<input id="username" class="form-control" th:field="*{username}"
required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="studentName"> Student Name </label> <input
id="studentName" class="form-control" th:field="*{studentName}"
required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="password"> Password </label> <input
id="password" class="form-control" type="password"
th:field="*{password}" required autofocus="autofocus" />
</div>
<div class="form-group">
<select th:field="*{city}" th:each="city: ${cities}">
<option th:value="city" th:text="city"></option>
</select>
</div>
<div class="form-group">
<label class="control-label" for="phoneNum"> Phone Number </label> <input
id="phoneNum" class="form-control" th:field="*{phoneNum}" required
autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label"> Gender: </label>
<select th:field="*{gender}">
<option th:value="'Male'" th:text="Male"></option>
<option th:value="'Female'" th:text="Female"></option>
</select>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">Register</button>
<span>Already registered? <a href="/" th:href="#{/login}">Login
here</a></span>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
I also tried using ajax in this way and it didn't work:
<script>
$.ajax({
url:'/cities',
type:'GET',
dataType: 'json',
success: function( json ) {
$.each(json, function(i, value) {
$('#cities').append($('<option>').text(value).attr('value', value.value));
});
}
});
</script>
EDIT:
Student model have these fields:
private String username;
private String studentName;
private String password;
private String city;
private String phoneNum;
private String gender;
am sending an put request based on these files.
Venue.ts file
export class Venue {
id: number;
venueName: string;
cityName: string;
emailContact: string;
fighter1: string;
fighter2: string;
dateOfFight: Date;
active: boolean;
}
My Angular Component files:
create-venue.component.html
<h3>Create Event</h3>
<div [hidden]="submitted" style="width: 400px;">
<form (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="name">Venue Name</label>
<input type="text" class="form-control" id="venueName" required [(ngModel)]="venue.venueName" name="venueName">
</div>
<div class="form-group">
<label for="name">City Name</label>
<input type="text" class="form-control" id="cityName" required [(ngModel)]="venue.cityName" name="cityName">
</div>
<div class="form-group">
<label for="name">Email Contact</label>
<input type="text" class="form-control" id="emailContact" required [(ngModel)]="venue.emailContact" name="emailContact">
</div>
<div class="form-group">
<label for="name">Fighter 1 Contact</label>
<input type="text" class="form-control" id="fighter1" required [(ngModel)]="venue.fighter1" name="fighter1">
</div>
<div class="form-group">
<label for="name">Fighter 2 Contact</label>
<input type="text" class="form-control" id="fighter2" required [(ngModel)]="venue.fighter2" name="fighter2">
</div>
<div class="form-group">
<label for="name">Choose a time for your Event:</label>
<input type="datetime-local" class="form-control" id="dateOfFight" min="2021-01-01T00:00" max="2023-06-14T00:00" required [(ngModel)]="venue.dateOfFight" name="dateOfFight">
</div>
<button type="submit" class="btn btn-success">Submit</button>
</form>
</div>
<div [hidden]="!submitted">
<h4>You submitted successfully!</h4>
<!-- <button class="btn btn-success" (click)="newVenue()">Add</button> -->
</div>
create-venue.component.ts
import { VenueService } from '../venue.service';
import { Venue} from '../venue';
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
#Component({
selector: 'app-create-venue',
templateUrl: './create-venue.component.html',
styleUrls: ['./create-venue.component.css']
})
export class CreateVenueComponent implements OnInit {
venue: Venue = new Venue();
submitted = false;
constructor(private venueService: VenueService,
private router: Router) {}
ngOnInit() {
}
newVenue(): void {
this.submitted = false;
this.venue = new Venue();
}
save() {
this.venueService.createVenue(this.venue)
.subscribe(data => console.log(data), error => console.log(error));
this.venue = new Venue();
this.gotoList();
}
onSubmit() {
this.submitted = true;
this.save();
}
gotoList() {
this.router.navigate(['/venues']);
}
}
My current sent data in chrome:
I am quite new to javascript and angular, maybe this was answered before but I have no idea how to get the input data into the Venue object...
Edit:
This is my header tab:
I
using a string instead of Date type for the dateOfFight property will let you post to the backend without issue.
You can then generate the date with new Date(datestring) on your server if needed. On the front end you can look into date pipes which will help you format the string accordingly.
You also seem to not be capturing any values in your date input. Notice venue.dateOfFight is not even there. Perhaps try logging out your data before posting
You can use a string instead of date type dateOfFight: string;, and before saving, trasform it into a date format with Moment js.
moment(Date.now()).format('YYYY-MM-DD').toString()
I'm trying to make a field required, if a specific option is selected from a select.
What I have so far:
ViewModel:
public enum RequestType
{
PaidLeaveOfAbsence = 1,
WorkFromHome = 2,
SickLeave = 3,
BriefLeaveOfAbsence = 4
}
public class RequestFormViewModel
{
public RequestType SelectedRequestType { get; set; }
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }
[RequieredIf("SelectedRequestType")]
public string Comment { get; set; }
}
CustomAttribute:
public class RequieredIfAttribute : ValidationAttribute, IClientModelValidator
{
private readonly string _otherProperty;
public RequieredIfAttribute(string otherProperty)
{
_otherProperty = otherProperty;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
string comment = (string)value;
RequestType selectedRequestType = (RequestType)validationContext.ObjectType.GetProperty(_otherProperty).GetValue(validationContext.ObjectInstance, null);
if (string.IsNullOrEmpty(comment) && selectedRequestType == RequestType.BriefLeaveOfAbsence)
{
return new ValidationResult("Comment is requiered.");
}
return ValidationResult.Success;
}
public void AddValidation(ClientModelValidationContext context)
{
MergeAttribute(context.Attributes, "data-val", "true");
MergeAttribute(context.Attributes, "data-val-required-if", "Comment is requiered.");
MergeAttribute(context.Attributes, "data-val-other", "#" + _otherProperty);
}
private static bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
{
if (attributes.ContainsKey(key))
{
return false;
}
attributes.Add(key, value);
return true;
}
}
HTML:
<div class="row">
<div class="col-0 col-md-2"></div>
<div class="col-12 col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="SelectedRequestType" class="control-label"></label>
<select asp-for="SelectedRequestType" asp-items="Html.GetEnumSelectList<RequestType>()" class="form-control">
<option selected="selected" value="">Select a request</option>
</select>
<span asp-validation-for="SelectedRequestType" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FromDate" class="control-label"></label>
<input asp-for="FromDate" class="form-control" type="text" value="" id="fromDate" autocomplete="off" />
<span asp-validation-for="FromDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ToDate" class="control-label"></label>
<input asp-for="ToDate" class="form-control" type="text" value="" id="toDate" autocomplete="off" />
<span asp-validation-for="ToDate" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
<div class="col-12 col-md-4">
<div class="form-group">
<label asp-for="Comment" class="control-label">Comment</label>
<textarea asp-for="Comment" class="form-control" id="comment" rows="3"></textarea>
<span asp-validation-for="Comment" class="text-danger"></span>
</div>
</div>
<div class="col-0 col-md-2"></div>
Generated HTML:
<select class="form-control" data-val="true" id="SelectedRequestType" name="SelectedRequestType">
<option selected="selected" value="">Select a request</option>
<option value="1">PaidLeaveOfAbsence</option>
<option value="2">WorkFromHom</option>
<option value="3">SickLeave</option>
<option value="4">BriefLeaveOfAbsence</option>
</select>
...
<div class="form-group">
<label class="control-label" for="Comment">Comment</label>
<textarea class="form-control" id="comment" rows="3" data-val="true" data-val-other="#SelectedRequestType" data-val-required-if="Comment is required." name="Comment"></textarea>
<span class="text-danger field-validation-valid" data-valmsg-for="Comment" data-valmsg-replace="true"></span>
</div>
The server side validation works fine. I'm stuck on adding client side validation, so far I have this:
validator.js
jQuery.validator.addMethod("required-if",
function (value, element, param) {
var otherProp = $($(element).data('val-other'));
console.log(otherProp);
if (!value.trim() && otherProp.val() == 4) {
return false;
}
return true;
}
)
jQuery.validator.unobtrusive.adapters.add("required-if", ["other"],
function (options) {
console.log(options);
options.rules["required-if"] = "#" + options.params.other;
options.messages["required-if"] = options.message;
});
I've put some console.log()s but they are never executed. (I did preserve the log in chrome).
Most of the google searches are from the ASP.NET MVC that implement IClientValidatable interface and are not very useful. I'm using ASP.NET Core 2.2.0.
I did read the microsoft docs and the link they provided on custom adapters for unusual validators.
Questions:
How can I achieve the expected behavior this way? What am I doing wrong and how can I fix it?
What are my other options? Should I just make a separate client side validation with the jQuery Validation Plugin? I don't like the idea of 2 separate places for validation.
Can someone explain to me why the console.log()s inside the javascript functions are never executed? I have custom validators for FromDate and ToDate and they are executed there. The only difference is that I use
jQuery.validator.unobtrusive.adapters.addBool instead of jQuery.validator.unobtrusive.adapters.add.
You can have your FormViewModel extend IValidatableObject. Once you do that implement Validate method. There you can have custom validation based on values in your Model. Something like:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(SelectedRequestType == RequestType.PaidLeaveOfAbsence)
{
// Check if field is not null and return
yield return new ValidationResult(
"SomeField should be present.",
new[] { "SomeField" });
}
}
You can make above syntax more elegant with use of pattern matching
You can find more about model validation at this link
The comment section was outside the form, so the validation would never happen.
The answer was found in the link from my original post.
Important note: jQuery Validate requires your input elements to be
inside of a <form> element in order to be validated.
I want to retrieve 2 input field values from one of the 2 forms in my jsp file and use that value in my second form. So I used javascript to get the values from the first form and display it in a hidden input field in the second form so that I could use those values, but it is giving me a number format exception so I'm guessing the values from the first form is not correctly getting passed to the second form. Here is my code:
jsp file:
<script>
function getNumOfDays(){
var numOfDays = document.getElementById("numOfDays").value;
document.getElementById("hiddenNumDays").value = numOfDays;
}
function getTotalMiles(){
var totalMiles = document.getElementById("totalMile").value;
document.getElementById("hiddenTotalMiles").value = totalMiles;
}
function getTotalDue(){
var HtotalDue = document.getElementById("totalDue").value;
document.getElementById("hiddentTotalDue").value = HtotalDue;
}
</script>
First Form
<form class="form-horizontal" name="selectVehicleForm" action="SelectVehicle">
<div class="form-group">
<label class="col-md-5 control-label">Number of Days Renting:</label>
<div class="col-md-3">
<input class="form-control" type="text" id="numOfDays" name="numOfDays" disabled>
</div>
</div>
<div class="form-group">
<label class="col-md-5 control-label">Total Miles:</label>
<div class="col-md-3">
<input class="form-control" type="text" name="totalMile" id="totalMile" placeholder="approximate">
</div>
</div>
<div class="form-group">
<label class="col-md-5 control-label">Total Amount Due: $</label>
<div class="col-md-3">
<input class="form-control" type="text" name="totalDue" id="totalDue" disabled>
</div>
</div>
</form>
Second Form
<input type="text" name="hiddenNumDays" id="hiddenNumDays" disabled>
<input type="hidden" name="hiddenTotalMiles" id="hiddenTotalMiles" disabled>
<input type="hidden" name="hiddentTotalDue" id="hiddentTotalDue" disabled>
Serlvet:
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
Payment paymentInfo = new Payment();
paymentInfo.setId(10);
paymentInfo.setFirstName(request.getParameter("firstName"));
paymentInfo.setLastName(request.getParameter("lastName"));
paymentInfo.setAddress(request.getParameter("address"));
paymentInfo.setAptSuit(request.getParameter("aptNum"));
paymentInfo.setCity(request.getParameter("city"));
paymentInfo.setState(request.getParameter("state"));
paymentInfo.setZipcode(request.getParameter("zipCode"));
paymentInfo.setPhoneNum(request.getParameter("phoneNum"));
paymentInfo.setEmail(request.getParameter("email"));
paymentInfo.setCreditCardType(request.getParameter("card"));
paymentInfo.setCreditCardNum(Integer.parseInt(request.getParameter("cardNumber")));
paymentInfo.setExpirationDate(request.getParameter("expMonth"));
paymentInfo.setCvCode(Integer.parseInt(request.getParameter("cvCode")));
paymentInfo.setNumOfDays(Integer.parseInt(request.getParameter("hiddenNumDays")));
paymentInfo.setTotalDue(request.getParameter("hiddenTotalDue"));
int result = RentService.insertPaymentDB(paymentInfo);
if(result > 0)
{
int vehicleID = Integer.parseInt(request.getParameter("id"));
InventoryService.updateVehicleAvailabilty(vehicleID);
response.sendRedirect("RentCar");
}
else
{
response.sendRedirect("failure.jsp");
}
}
why don't you put the value you take from either of the two forms in session like this
request.getsession.setAttribute("name", value);
then you can access it
String value=session.getAttribute("name").toString();
I have two entities Environnment and ServeurApplicatif that have a oneToMany relationship. I have a dynamic form with a button to add a new form each time a user wants to associate a ServeurApplicatif to on Environnement entity.When submitting the expected result is the persistence of both the environnement Entity and the ServeurApplicatif entities associated with it.
However in my case i get a 400 http error : your request is synthatically incorrect, whenever i try to submit the form.
here is the javascript code that adds the child entity related form dynamically :
<script type="text/javascript">
$(document).ready(function() {
var index = ${fn:length(env.serveurApplicatifs)};
console.log("index value :"+index);
$("#addServ").off("click").on("click",function() {
$(this).before(function() {
var html = '<div id="serveurApplicatifs'+index+'.wrapper" style="display: none;">';
html += '<input type="hidden" id="serveurApplicatifs'+index+'.idserv" name="serveurApplicatifs['+index+'].idserv" ></input>';
html += '<p><strong>Serveur Applicatif 1 : </strong></p>';
html += '<div class="form-group"><label for="serveurApplicatifs'+index+'.port">Port :</label><input class ="form-control" type="text" id="serveurApplicatifs'+index+'.port" name="serveurApplicatifs['+index+'].port" ></input></div>';
html += '<div class="form-group"><label for="serveurApplicatifs'+index+'.compte">Compte :</label><input class ="form-control" type="text" id="serveurApplicatifs'+index+'.compte" name="serveurApplicatifs['+index+'].compte" ></input></div>';
html += '<div class="form-group"><label for="serveurApplicatifs'+index+'.pwd">Mot de passe :</label><input class ="form-control" type="text" id="serveurApplicatifs'+index+'.pwd" name="serveurApplicatifs['+index+'].pwd" ></input></div>';
html += '<div class="form-group"><label for="serveurApplicatifs'+index+'.adresse">Adresse :</label><input class ="form-control" type="text" id="serveurApplicatifs'+index+'.adresse" name="serveurApplicatifs['+index+'].adresse" ></input></div>';
html += 'Supprimer';
html += "</div>";
return html;
});
$("#serveurApplicatifs"+index+"\\.wrapper").show();
index++;
return false;
});
$("a.serveurApplicatifs.remove").off("click").on("click",function() {
var index2remove = $(this).data("index");
$("#serveurApplicatifs"+index2remove+"\\.wrapper").hide();
$("#serveurApplicatifs"+index2remove+"\\.remove").val("1");
return false;
})
the Spring form tags in the jsp :
<c:url value="/envs/save" var="saveUrl"/>
<form:form action="${ saveUrl }" method="POST" modelAttribute="env">
<div class="form-group">
<form:input type="hidden" class="form-control" id="idEnv" placeholder="id" path="idEnv"></form:input><span id="star">*</span>
</div>
<!-- ------------- -->
<div class="form-group">
<label for="nom">Nom</label>
<form:input type="text" class="form-control" id="nom" placeholder="Nom" path="nom"></form:input><span>*</span>
<form:errors path="nom" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="plateforme">Platforme</label>
<form:input type="text" class="form-control" id="plateform" placeholder="Plateforme" path="platforme"></form:input>
<form:errors path="platforme" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="typologie">Typologie</label>
<form:input type="text" class="form-control" id="typologie" placeholder="Typologie" path="typologie"></form:input>
<form:errors path="typologie" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="bd">Base de donnée</label>
<form:input type="text" class="form-control" id="bd" placeholder="Bdd" path="bd"></form:input>
<form:errors path="bd" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="version">Version</label>
<form:input type="text" class="form-control" id="version" placeholder="Version" path="version"></form:input>
<form:errors path="version" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="machine_bd">Serveur de base de données</label>
<form:input type="text" class="form-control" id="machine_bd" placeholder="Machine Bdd" path="machineBd"></form:input>
<form:errors path="machineBd" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="port_bd">Port Base de données</label>
<form:input type="text" class="form-control" id="port_bd" placeholder="Port bdd" path="portBd"></form:input>
<form:errors path="portBd" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="version_bd">Version de base de données</label>
<form:input type="text" class="form-control" id="version_bd" placeholder="Version bdd" path="versionBd"></form:input>
<form:errors path="versionBd" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="type_bd">Type de base de données</label>
<form:input type="text" class="form-control" id="type_bd" placeholder="Type bdd" path="typeBd"></form:input>
<form:errors path="typeBd" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="depart">Environnement de départ</label>
<form:radiobutton value ="1" id="depart" path="depart" label="Oui"></form:radiobutton>
<form:radiobutton value ="0" id="depart" path="depart" label="Non"></form:radiobutton>
<form:errors path="depart" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="repert">Repert</label>
<form:input type="text" class="form-control" id="repert" placeholder="Repert" path="repert"></form:input>
<form:errors path="repert" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="port_ftp">Port FTP</label>
<form:input type="text" class="form-control" id="port_ftp" placeholder="Port FTP" path="portFtp"></form:input>
<form:errors path="portFtp" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="exclu">Exclu</label>
<form:radiobutton value ="1" id="exclu" path="exclu" label="Oui"></form:radiobutton>
<form:radiobutton value ="0" id="exclu" path="exclu" label="Non"></form:radiobutton>
<form:errors path="exclu" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="envsPrec">Précedent</label>
<form:select class="form-control" id="envsPrec" path="environnements2" items="${ envsPrecSuiv }" itemLabel="nom" itemValue="idEnv"/>
<form:errors path="environnements2" cssClass="error"></form:errors>
</div>
<div class="form-group">
<label for="envsSuiv">Suivant</label>
<form:select class="form-control" id="envsSuiv" path="environnements1" items="${ envsPrecSuiv }" itemLabel="nom" itemValue="idEnv"/>
<form:errors path="environnements1" cssClass="error"></form:errors>
</div>
<c:forEach varStatus="loop" var="serveurApplicatifs" items="${ env.serveurApplicatifs }">
<c:choose>
<c:when test="${env.serveurApplicatifs[loop.index].remove eq 1 }">
<div id="serveurApplicatifs${loop.index }.wrapper" style="display: none;">
</c:when>
<c:otherwise>
<div id="serveurApplicatifs${ loop.index }.wrapper">
</c:otherwise>
</c:choose>
<div class="form-group">
<form:input type="hidden" class="form-control" id="idApp" path="env.serveurApplicatifs[${loop.index}].idserv"></form:input>
</div>
<div class="form-group">
<label for="portApp">Port serveur applicatif</label>
<form:input type="text" class="form-control" id="portApp" placeholder="Port" path="env.serveurApplicatifs[${loop.index}].port"></form:input>
</div>
<div class="form-group">
<label for="compteApp">Compte serveur applicatif</label>
<form:input type="text" class="form-control" id="compteApp" placeholder="Compte" path="env.serveurApplicatifs[${loop.index}].compte"></form:input>
</div>
<div class="form-group">
<label for="pwdApp">Mot de passe serveur applicatif</label>
<form:input type="text" class="form-control" id="pwdApp" placeholder="Mot de passe" path="env.serveurApplicatifs[${loop.index}].pwd"></form:input>
</div>
<div class="form-group">
<label for="adresseApp">Adresse serveur applicatif</label>
<form:input type="text" class="form-control" id="adresseApp" placeholder="Adresse" path="env.serveurApplicatifs[${loop.index}].adresse"></form:input>
</div>
<c:choose>
<c:when test="${serveurApplicatifs[loop.index].remove eq 1}"><c:set var="hiddenValue" value="1"></c:set></c:when>
<c:otherwise><c:set var="hiddenValue" value="0"></c:set> </c:otherwise>
</c:choose>
<form:hidden path="serveurApplicatifs[${loop.index}].remove" value="${hiddenValue}"/>
Supprimer
</div>
</c:forEach>
<button type="button" class="btn btn-default" id="addServ">Ajouter Un Serveur d'application</button>
<button type="submit" class="btn btn-default" value="Save">Submit</button>
</form:form>
The Environnement entity class :
#Entity
#NamedQuery(name="Environnement.findAll", query="SELECT e FROM Environnement e")
public class Environnement implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id_env")
private int idEnv;
private String bd;
private int depart;
private int exclu;
#Column(name="machine_bd")
private String machineBd;
#Column(name="mdp_bdd")
private String mdpBdd;
private String nom;
private String platforme;
#Column(name="port_bd")
private int portBd;
#Column(name="port_ftp")
private int portFtp;
private String repert;
#Column(name="type_bd")
private String typeBd;
private String typologie;
#Column(name="utilisateur_bdd")
private String utilisateurBdd;
private String version;
#Column(name="version_bd")
private String versionBd;
//bi-directional many-to-many association to Composant
#ManyToMany
#JoinTable(
name="env_comp"
, joinColumns={
#JoinColumn(name="id_env")
}
, inverseJoinColumns={
#JoinColumn(name="id_comp")
}
)
private List<Composant> composants;
//bi-directional many-to-many association to Environnement
#LazyCollection(LazyCollectionOption.FALSE)
#ManyToMany
#JoinTable(
name="lien_environnement"
, joinColumns={
#JoinColumn(name="id_env_suiv")
}
, inverseJoinColumns={
#JoinColumn(name="id_env_prec")
}
)
private List<Environnement> environnements1;
//bi-directional many-to-many association to Environnement
#LazyCollection(LazyCollectionOption.FALSE)
#ManyToMany
#JoinTable(
name="lien_environnement"
, joinColumns={
#JoinColumn(name="id_env_prec")
}
, inverseJoinColumns={
#JoinColumn(name="id_env_suiv")
}
)
private List<Environnement> environnements2;
//bi-directional many-to-one association to ServeurApplicatif
#LazyCollection(LazyCollectionOption.FALSE)
#OneToMany(mappedBy="environnement")
private List<ServeurApplicatif> serveurApplicatifs;
the ServeurApplicatif entity class :
#Entity
#Table(name="serveur_applicatif")
#NamedQuery(name="ServeurApplicatif.findAll", query="SELECT s FROM ServeurApplicatif s")
public class ServeurApplicatif implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int idserv;
private String adresse;
private String compte;
private int port;
private String pwd;
#Transient
private Integer remove;
//bi-directional many-to-one association to Environnement
#ManyToOne
#JoinColumn(name="id_env")
private Environnement environnement;
Controller Method used to persist the entities :
#RequestMapping(value="/envs/save",method=RequestMethod.POST)
public ModelAndView saveEnvironnement(#ModelAttribute(value="env")Environnement env) {
//Environnement envFinal = this.envService.validate(env);
this.envService.gererServeur(env);
/*for (ServeurApplicatif servApp : env.getServeurApplicatifs()) {
}*/
envService.saveOrUpdate(env);
for (ServeurApplicatif servApp : env.getServeurApplicatifs()) {
servAppService.saveOrUpdate(servApp);
}
return new ModelAndView("redirect:/envs");
}
gererServeur method in EnvironnementService classe :
#Override
public List<ServeurApplicatif> gererServeur(Environnement env) {
// TODO Auto-generated method stub
List<ServeurApplicatif> serveurRemoved = new ArrayList<ServeurApplicatif>();
if(env.getServeurApplicatifs() != null) {
for (Iterator<ServeurApplicatif> iterator = serveurRemoved.iterator(); iterator
.hasNext();) {
ServeurApplicatif serveurApplicatif = iterator.next();
if(serveurApplicatif.getRemove() == 1) {
serveurRemoved.add(serveurApplicatif);
iterator.remove();
}
else {
serveurApplicatif.setEnvironnement(env);
}
}
}
return serveurRemoved;
}
Note that i'm using the solution shown here to manage the dynamic form :
Spring 3 MVC: one-to-many within a dynamic form (add/remove on create/update)
Edit :
i tried declaring the line var index = ${fn:length(env.serveurApplicatifs)}; outside of the document ready function but it didn't help, the console.log returns 0 when loading the form but gets incremented each time i clic the button to add a new form for ServeurApplicatif,the form data sent to the server is as follows :
idEnv:0
nom:
platforme:
typologie:
bd:
version:
machineBd:
portBd:0
versionBd:
typeBd:
depart:0
repert:
portFtp:0
exclu:0
_environnements2:1
_environnements1:1
serveurApplicatifs[0].idserv:
serveurApplicatifs[0].port:14523
serveurApplicatifs[0].compte:test
serveurApplicatifs[0].pwd:test
serveurApplicatifs[0].adresse:test
serveurApplicatifs[1].idserv:
serveurApplicatifs[1].port:14523
serveurApplicatifs[1].compte:test
serveurApplicatifs[1].pwd:test
serveurApplicatifs[1].adresse:test
_csrf:2d856fad-16f3-4ae4-a254-47922a695c17
you will notice that the idserv doesn't get automatically populated unlike idenv. both of these IDs are auto-increment fields in the DB, the other blank fields are nullable so the problem isn't there.
Thanks in advance.
I found what was wrong.
Basically the idserv wasn't getting the default value of 0 so that
spring can handle the request to the server and hibernate can insert the ServeurApplicatif entity alongside the Environnment entity when saveOrUpdate is invoked, so i added a value="0" to the javascript code responsible for creating form inputs for ServeurApplicatifs on the fly and now it works as expected.