Custom Attribute Validation: make field required based on selected option - javascript

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.

Related

How to pass a list from controller post action to a view without using Json?

I'm coding with ASP.NET Core. I have a form in a view that has several select inputs to insert orders. I want to change asp-items in select input of Products at run time, after changing select inputs of Properties of Products.
In other words, a select input populates with a new list, after selecting new value in other inputs.
I try to use ajax for bind new list to select. but I don't know how to send the output list to ajax without json result. Is there any way to send list to view?
View's Code:
<form id="InsertForm">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="ProductTitleId" class="control-label"></label>
<select asp-for="ProductTitleId" asp-items="#ViewBag.ProductTitles" class="form-control" id="txtProductTitleId" name="SearchItem">
<option value="0" disabled selected>Select an item...</option>
</select>
<span asp-validation-for="ProductTitleId" class="text-danger </span>
</div>
<div class="form-group">
<label asp-for="ProductTypeId" class="control-label"></label>
<select asp-for="ProductTypeId" asp-items="#ViewBag.ProductTypes" class="form-control" id="txtProductTypeId" name="SearchItem">
<option value="0" disabled selected>Select an item...</option>
</select>
<span asp-validation-for="ProductTypeId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="SizeId" class="control-label"></label>
<select asp-for="SizeId" asp-items="#ViewBag.Sizes" id="txtSizeId" class="form-control" name="SearchItem">
<option value="0" disabled selected>Select an item...</option>
</select>
<span asp-validation-for="SizeId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FinalProductId" class="control-label"></label>
<select asp-for="FinalProductId" asp-items="#ViewBag.FinalProducts" class="form-control" dir="rtl" id="txtFinalProductId">
<option value="0" disabled selected>Select an item...</option>
</select>
<span asp-validation-for="FinalProductId" class="text-danger"></span>
</div>
<div class="form-group">
<button type="submit" class="btn">Insert</button>
</div>
</form>
<script>
$(document).ready(function () {
$('[name = SearchItem]').change(function () {
var _url = '#Url.Action("FindFinalProductCode", "Order")';
$.ajax({
url: _url,
type: "Post",
data: {
ProductTitleId: $("#txtProductTitleId option:selected").val(),
ProductTypeId: $("#txtProductTypeId option:selected").val(),
SizeId: $("#txtSizeId option:selected").val(),
},
success: function (data) {
$("#txtFinalProductId").empty();
$("#txtFinalProductId").append('<option value="' + "0" + '">' + "Select an item..." + '</option>');
$("#txtFinalProductId").items(data); ///????
});
},
error: function (data) {
alert(data);
}
});
});
});
</script>
Controller's Code: OrderController.cs
[HttpPost]
public IActionResult FindFinalProductCode(FinalProductViewModel finalProductViewModel)
{
List<FinalProduct> finalProducts = FindFinalProduct(finalProductViewModel);
return OK(finalProducts);
}
ViewModel's Code: FinalProductViewModel.cs
public class FinalProductViewModel
{
[Display(Name = "Title")]
public int ProductTitleId { get; set; }
[Display(Name = "Type")]
public int ProductTypeId { get; set; }
[Display(Name = "Size")]
public int SizeId { get; set; }
}
I don't know how to re-populate asp-items with ajax at run time.
How to change my code to run correctly?

Populate external array in <select> using Spring Boot

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;

How to Interact between a view component's form and a controller in ASP.NET Core?

I'm beginner in web designing with ASP.NET Core. I wrote a view component that has a form with some inputs related to a view model. One of these inputs is a file input (of the IFormFile datatype).
I want to submit this view model to an action of a controller (POST action), check the validity of model, return another view component if the model state is valid, and remain on this view component with this view model if model state is not valid.
This is my View Model: PricingViewModel.cs
public class PricingViewModel
{
[Display(Name = "Select a file")]
public IFormFile formFile { get; set; }
[Display(Name = "ColumnCode")]
[Required(ErrorMessage = "Enter {0} value, please")]
public string colCode { get; set; }
[Display(Name = "ColumnName")]
[Required(ErrorMessage = "Enter {0} value, please")]
public string colName { get; set; }
}
My View Component (controller): PricingComponent.cs
public class PricingComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(PricingViewModel pricing)
{
return await Task.FromResult((IViewComponentResult)View("PricingView", pricing));
}
}
My View Component (view): PricingView.cshtml
<form class="text-left" method="post" enctype="multipart/form-data">
<input name="IsValidPricing" type="hidden" value="#ViewBag.isValid" />
<div class="form-group text-left">
<label asp-for="colCode" class="control-label"></label>
<input asp-for="colCode" class="form-control" id="colCodeId"/>
<span asp-validation-for="colCode" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="colName" class="control-label"></label>
<input asp-for="colName" class="form-control" id="colNameId"/>
<span asp-validation-for="colName" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="formFile " class="control-label"></label>
<input type="file" accept=".xlsx, .csv" asp-for="formFile" id="MyInputFile"/>
</div>
<div class="form-group mt-4">
<input type="submit" asp-action="ShowPricing" asp-controller="Home" value="Show" id="ShowPricingBtn" />
</div>
</form>
My Home Controller: HomeController.cs
[HttpPost]
public IActionResult ShowPricing(PricingViewModel pricing)
{
if (ModelState.IsValid)
{
int temp;
if (!int.TryParse(pricing.colCode, out temp))
{
ViewBag.isValid = 0;
ModelState.AddModelError("colCode", "Invalid Data");
return ViewComponent("PricingComponent", new { pricing = pricing }); // 1
}
else if (!int.TryParse(pricing.colName, out temp))
{
ViewBag.isValid = 0;
ModelState.AddModelError("colName", "Invalid Data");
return ViewComponent("PricingComponent", new { pricing = pricing }); //2
}
else
{
ViewBag.isValid = 1;
// do something ...
return ViewComponent("ShowPricingExcelComponent"); //Call another view component
}
}
else
{
ViewBag.isValid = 0;
return ViewComponent("PricingComponent", new { pricing = pricing }); //3
}
}
Plan A
The above approach is my primary plan.
Problem
If I use options of submit input tag (asp-action, asp-controller) like above, the view model sends correctly, but I don't know how to handle the validity of the model and remain on this view component. In the above code, when the ShowPricing action runs, if the model state is valid, the code works correctly, but when model is invalid (1,2,3), the PricingView doesn't show the validation summery, and just loads with current view model.
Plan B
I used AJAX to send the viewModel to the action and instead of showing the validation summary, I send an alert to the user with AJAX. I changed PricingView as following:
My View Component (view): PricingView.cshtml
<form class="text-left" method="post" enctype="multipart/form-data">
<input name="IsValidPricing" type="hidden" value="#ViewBag.isValid" />
<div class="form-group text-left">
<label asp-for="colCode" class="control-label"></label>
<input asp-for="colCode" class="form-control" id="colCodeId"/>
<span asp-validation-for="colCode" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="colName" class="control-label"></label>
<input asp-for="colName" class="form-control" id="colNameId"/>
<span asp-validation-for="colName" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="fromFile " class="control-label"></label>
<input type="file" accept=".xlsx, .csv" asp-for="formFile" id="MyInputFile"/>
</div>
<script>
$(document).ready(function () {
$('#ShowPricingBtn').click(function () {
var _url = '#Url.Action("ShowPricing", "Home")';
var input = $("#MyInputFile").get(0).files[0];
$.ajax({
type: "POST",
url: _url,
data: {
formFile: input,
colCode: $("#colCode").val(),
colName: $("#colName").val(),
},
success: function (result)
{
var IsValid = $('body').find('[name="IsValidPricing"]').val();
if (IsValid)
{
$("#ShowExcelTable").html(result);
}
else {
alert("Invalid Data");
}
},
});
});
});
</script>
<div class="form-group mt-4">
<input type="submit" value="Show" id="ShowPricingBtn" />
</div>
</form>
Problem
In this code:
If the model state is not valid, the alert sends correctly, but
If the model state is valid, the formFile input doesn't send correctly to action and it's null in view model.
I don't know whether I should go with the original or the alternate approach these problems. Do you know where I'm going wrong?
Not sure how do you call view components,here are the working demos:
For PlanA
1.Create ViewComponents/PricingComponent.cs and ViewComponents/ShowPricingExcelComponent.cs.
public class PricingComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(PricingViewModel pricing)
{
return await Task.FromResult((IViewComponentResult)View("PricingView", pricing));
}
}
public class ShowPricingExcelComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(PricingViewModel pricing)
{
return await Task.FromResult((IViewComponentResult)View("ShowPricingExcel", pricing));
}
}
2.Create Views/Shared/Components/PricingComponent/PricingView.cshtml.
#model PricingViewModel
<form class="text-left" method="post" enctype="multipart/form-data">
<input name="IsValidPricing" type="hidden" value="#ViewBag.isValid" />
<div class="form-group text-left">
<label asp-for="colCode" class="control-label"></label>
<input asp-for="colCode" class="form-control" id="colCodeId" />
<span asp-validation-for="colCode" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="colName" class="control-label"></label>
<input asp-for="colName" class="form-control" id="colNameId" />
<span asp-validation-for="colName" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="formFile " class="control-label"></label>
<input type="file" accept=".xlsx, .csv" asp-for="formFile" id="MyInputFile" />
</div>
<div class="form-group mt-4">
<input type="submit" asp-action="ShowPricing" asp-controller="Home" value="Show" id="ShowPricingBtn" />
</div>
</form>
3.Create Views/Shared/Components/ShowPricingExcelComponent/ShowPricingExcel.cshtml.
<h1>Excel....</h1>
Project Structure:
4.Views/Home/Index.cshtml:
#await Component.InvokeAsync("PricingComponent")
5.HomeController:
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult ShowPricing(PricingViewModel pricing)
{
if (ModelState.IsValid)
{
int temp;
if (!int.TryParse(pricing.colCode, out temp))
{
ViewBag.isValid = 0;
ModelState.AddModelError("colCode", "Invalid Data");
return View("Index", pricing);
}
if (!int.TryParse(pricing.colName, out temp))
{
ViewBag.isValid = 0;
ModelState.AddModelError("colName", "Invalid Data");
return View("Index", pricing);
}
else
{
ViewBag.isValid = 1;
// do something ...
return ViewComponent("ShowPricingExcelComponent"); //Call another view component
}
}
else
{
ViewBag.isValid = 0;
return View("Index", pricing); //3
}
}
}
Result:
For PlanB
1.Create ViewComponents/PricingComponent.cs and ViewComponents/ShowPricingExcelComponent.cs.
2.Create Views/Shared/Components/PricingComponent/PricingView.cshtml.
Firstly,it should be type="button" otherwise it will call twice to the backend.Secondly,what you did in ajax is not correct,more detailed explation you could refer to this answer.At last,you could not judge the modelstate by get the value of IsValidPricing value in your sucess function.Because the value you get is always be the data you first render the page,you cannot get the changed ViewBag value when ajax post back.
#model PricingViewModel
<form class="text-left" method="post" enctype="multipart/form-data">
<input name="IsValidPricing" type="hidden" value="#ViewBag.isValid" />
<div class="form-group text-left">
<label asp-for="colCode" class="control-label"></label>
<input asp-for="colCode" class="form-control" id="colCodeId" />
<span asp-validation-for="colCode" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="colName" class="control-label"></label>
<input asp-for="colName" class="form-control" id="colNameId" />
<span asp-validation-for="colName" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="formFile " class="control-label"></label>
<input type="file" accept=".xlsx, .csv" asp-for="formFile" id="MyInputFile" />
</div>
<div class="form-group mt-4">
#*it should be type="button"*#
<input type="button" value="Show" id="ShowPricingBtn" />
</div>
</form>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script>
$(document).ready(function () {
$('#ShowPricingBtn').click(function () {
var _url = '#Url.Action("ShowPricing", "Home")';
var input = $("#MyInputFile").get(0).files[0];
var fdata = new FormData();
fdata.append("formFile", input);
$("form input[type='text']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
$.ajax({
type: "POST",
url: _url,
data: fdata,
contentType: false,
processData: false,
success: function (result)
{
console.log(result);
if (result==false)
{
alert("Invalid Data");
}
else {
$("#ShowExcelTable").html(result);
}
},
});
});
});
</script>
3.Create Views/Shared/Components/ShowPricingExcelComponent/ShowPricingExcel.cshtml.
<h1>Excel....</h1>
4.Views/Home/Index.cshtml:
#await Component.InvokeAsync("PricingComponent")
<div id="ShowExcelTable"></div>
5.HomeController:
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult ShowPricing(PricingViewModel pricing)
{
if (ModelState.IsValid)
{
int temp;
if (!int.TryParse(pricing.colCode, out temp)|| !int.TryParse(pricing.colName, out temp))
{
ViewBag.isValid = 0;
return Json(false);
}
else
{
ViewBag.isValid = 1;
// do something ...
return ViewComponent("ShowPricingExcelComponent"); //Call another view component
}
}
else
{
ViewBag.isValid = 0;
return Json(false);
}
}
}
Result:
I'm not able to reproduce your error. Your code, as presented, works as expected. A validation message is displayed.
To make it a working example, I've added a GET method first.
[HttpGet]
public IActionResult ShowPricing() => ViewComponent("PricingComponent", new { pricing = new PricingViewModel() });
Open the URL Home/ShowPricing
Fill out the form.
Send the form. And the validation message is displayed.

Get a value from one form and use it in another jsp

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();

Convert/map inputs of date (day, month, year) into java.time.LocalDate

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

Categories