Hi I am new to spring MVC, and unable to do form submission.
My Jsp Code
<form:form method="POST" action="save" commandName="report">
<div id="collapseOne" class="panel-collapse collapse in"
role="tabpanel" aria-labelledby="headingOne">
<div class="panel-body">
<div class="col-md-3 col-sm-12 col-xs-12 form-group" >
<label><spring:message code="label.report.report_type"/><span class="required">*</span></label>
<form:select id="reportTypeSelect" class="form-control" path="reportType">
<form:options items="${report.reportTypes}"></form:options>
</form:select>
<!-- <select
class="form-control" name="scheduleType">
<option><spring:message code="label.report.chose_type"/></option>
<option><spring:message code="label.report.adhoc"/></option>
<option><spring:message code="label.report.scheduled"/></option>
</select> -->
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">
<spring:message code="label.report.sql_query"/></label>
<div class="col-md-9 col-sm-9 col-xs-12">
<form:textarea class="resizable_textarea form-control"
placeholder="Write Sql Queries to exceute the records ..." name="query" path="reportQuery"></form:textarea>
</div>
</div>
<div class="col-md-3 col-sm-12 col-xs-12 form-group">
<label><spring:message code="label.report.query_name"/><span class="required">*</span></label>
<form:input type="text" placeholder="Query Name" name="reportQueryName" path="reportType" class="form-control"></form:input>
</div>
<div class="col-md-3 col-sm-12 col-xs-12 form-group">
<label><spring:message code="label.report.schedule_date"/><span class="required">*</span></label> <input
id="eventDate"
class="date-picker form-control col-sm-12 col-xs-12"
required="required" type="text">
</div>
<div class="col-md-6 col-sm-12 col-xs-12 form-group">
<label><spring:message code="label.report.emailid"/><span class="required">*</span></label> <form:input
type="text" placeholder="Maximum 4 Email Recepients" name="email" path="emails" class="form-control"></form:input>
</div>
<div class="clearfix"></div>
<div class="form-group">
<div class="button-right">
<!--<button type="submit" class="btn btn-primary">Save</button>-->
<button type="submit" class="btn btn-success"> <spring:message code="label.button.save"/>
</button>
</div>
</div>
</div>
</div>
</form:form>
My Controller
#Controller
public class ReportsViewController {
private static final Logger logger = LoggerFactory.getLogger(ReportsViewController.class);
#RequestMapping(value="/reports",method=RequestMethod.GET)
public String displayReports(ModelMap model) {
logger.info("Start of displayReports()...............");
ReportsViewBean report = new ReportsViewBean();
report.setReportTypes(getReportType());
model.addAttribute("report", report);
logger.info("End of displayReports()...............");
return "reportsView";
}
#RequestMapping(value="/reports/save",method=RequestMethod.POST)
public String updateReports(#ModelAttribute("query") String query) {
System.out.println("username" + query);
return "reportsView";
}
private List<String> getReportType() {
List<String> type = new ArrayList<String>();
type.add("Adhoc");
type.add("Schedule");
return type;
}
}
Your problem is here :
#RequestMapping(value="/reports/save",method=RequestMethod.POST)
public String updateReports(#ModelAttribute("query") String query)
This should be :
#RequestMapping(value="/reports/save",method=RequestMethod.POST)
public String updateReports(#ModelAttribute("report") ReportsViewBean report)
This is the only way to get your model after the POST and then you can retrieve the attribute's values of your model.
You don't add the code of your model but be sure that it has all attributes you put in each path attribute of your form.
Related
How do I move data from an Iactionresult to another action result? I have been trying to display the data from the form and view it another Iactionresult? I attempt to use Tempdata but it seems like there is an error. Could anyone help me with it?
This action displays an individual product details when I click on an particular Id.
[HttpGet]
public IActionResult Details(int id)
{
string sql = String.Format(#"SELECT * FROM WBProduct
WHERE Id = {0}", id);
List<Product> lstProduct = DBUtl.GetList<Product>(sql);
if (lstProduct.Count == 0)
{
TempData["Message"] = $"Product #{id} not found";
TempData["MsgType"] = "warning";
return RedirectToAction("Index");
}
else
{
Product cdd = lstProduct[0];
return View(cdd);
}
}
I would like to display the the details of the product in this IActionResult
[HttpPost]
public IActionResult Create()
{
return View("Create");
}
View for Details:
#model Product
<div>
<div class="form-group row">
<div class="offset-sm-2"><h2>#Model.ProductName</h2></div>
</div>
<div class="form-group row">
<div class="offset-sm-2 col-sm-5">
<img id="ImgPhoto" src="~/images/product/#Model.ProductImage" style="width:400px;" />
</div>
</div>
<div class="form-group row">
<label class="control-label col-sm-2" for="City">Weight: </label>
<div class="col-sm-5">
<input type="text" asp-for="ProductWeight" class="form-control" readonly />
</div>
</div>
<div class="form-group row">
<label class="control-label col-sm-2" for="Date">Stock :</label>
<div class="col-sm-5">
<input type="text" asp-for="ProductStock" class="form-control" readonly />
</div>
</div>
<div class="form-group row">
<label class="control-label col-sm-2" for="Cost">Price: </label>
<div class="col-sm-5">
<input type="text" asp-for="ProductPrice" asp-format="{0:C}" class="form-control" readonly />
</div>
</div>
<div class="form-group row">
<label class="control-label col-sm-2" for="Story">Description: </label>
<div class="col-sm-5">
<textarea asp-for="ProductDescription" rows="8" cols="20" class="form-control" readonly></textarea>
</div>
</div>
<div class="form-group row">
<a href="http://localhost:50528/Product/Create" class="btn btn-info" role="button" > Add to Cart </a>
</div>
</div>
Create View:
#model Product
<div class="form-group row">
<div class="offset-sm-2"><h2>#Model.ProductName</h2></div>
</div>
<div class="form-group row">
<label class="control-label col-sm-2" for="City">Weight: </label>
<div class="col-sm-5">
<input type="text" asp-for="ProductWeight" class="form-control" readonly />
</div>
</div>
<div class="form-group row">
<label class="control-label col-sm-2" for="Date">Stock :</label>
<div class="col-sm-5">
<input type="text" asp-for="ProductStock" class="form-control" readonly />
</div>
</div>
<div class="form-group row">
<label class="control-label col-sm-2" for="Cost">Price: </label>
<div class="col-sm-5">
<input type="text" asp-for="ProductPrice" asp-format="{0:C}" class="form-control" readonly />
</div>
</div>
<div class="form-group row">
<label class="control-label col-sm-2" for="Story">Description: </label>
<div class="col-sm-5">
<textarea asp-for="ProductDescription" rows="8" cols="20" class="form-control" readonly></textarea>
</div>
</div>
The error message that I got was:
This should be a GET action, not a POST one, then you should extract the info from the TempData and pass it as parameter to the view cshtml.
TempData["Product"] = JsonConvert.SerializeObject(lstProduct[0]);
return RedirectToAction("Create");
Now you can deserialize in the Create action and retrieve your Product
[HttpGet]
public IActionResult Create()
{
// If the caller has prepared a product we can show it.
if(TempData.ContainsKey("Product"))
{
Product p = JsonConvert.DeserializeObject<Product>(TempData["Product"]);
return View(p);
}
else
return View();
}
If you want to move data from one action to another action in the same controller
just call one action from another and put data as an input parameter of another action.
To send message to Index action, at first create a class for the message:
public class ErrorMsg
{
public string Message {get; set;}
public string MessageType {get; set;}
}
Change your action Index to this:
public IActionResult Index(ErrorMsg errorMsg)
{
// if action called from another controller action, details for exapmple,
//errorMsg will contain data from that action
// otherwise errMsg will be an empty default object with empty strings
//Check if error
if(!string.IsNullOrEmpty(errorMsg.Message) ...your error code
else ....your index code here
}
Change your action details code:
public IActionResult Details(int id)
{
string sql = String.Format(#"SELECT * FROM WBProduct
WHERE Id = {0}", id);
List<Product> lstProduct = DBUtl.GetList<Product>(sql);
if (lstProduct.Count == 0)
{
var errMsg = new ErrMessage {
Message = $"Product #{id} not found",
MessageType = "warning"
}
return Index(errMsg);
}
else
{
Product cdd= lstProduct.FirstOrDefault();
//Or you can try again var cdd = lstProduct[0]; if you like it more
return View("Details", cdd);
}
}
Change your create action to this:
public IActionResult Create(Product product)
{
// if action called from another controller action, "product" will contain data //from that action
// otherwise "product" will be posted from the view or it will be an empty model with the default value fields
if(product.Id ==0) ... call add ef code
else ... call update ef code
}
And you have to add <form tag to all your views, othewise if will not post back any data, and add Product.Id hidden field inside of form:
#model Product
#using (Html.BeginForm("Create", "Product", FormMethod.Post)
{
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div>
<input type="hidden" asp-for="#Model.Id" />
<div class="form-group row">
<div class="offset-sm-2"><h2>#Model.ProductName</h2></div>
</div>
<div class="form-group row">
<div class="offset-sm-2 col-sm-5">
<img id="ImgPhoto" src="~/images/product/#Model.ProductImage" style="width:400px;" />
</div>
</div>
<div class="form-group row">
<label class="control-label col-sm-2" for="City">Weight: </label>
<div class="col-sm-5">
<input type="text" asp-for="ProductWeight" class="form-control" readonly />
</div>
</div>
<div class="form-group row">
<label class="control-label col-sm-2" for="ProductStock">Stock :</label>
<div class="col-sm-5">
<input type="text" asp-for="ProductStock" class="form-control" readonly />
</div>
</div>
<div class="form-group row">
<label class="control-label col-sm-2" for="ProductPrice">Price: </label>
<div class="col-sm-5">
<input type="text" asp-for="ProductPrice" asp-format="{0:C}" class="form-control" readonly />
</div>
</div>
<div class="form-group row">
<label class="control-label col-sm-2" for="ProductDescription">Description: </label>
<div class="col-sm-5">
<textarea asp-for="ProductDescription" rows="8" cols="20" class="form-control" readonly></textarea>
</div>
</div>
<div class="form-group row">
<button class="btn btn-info btn-link" type="submit"> Add to Cart </button>
</div>
</div>
}
I have the following code which shows that I am using PagedList to display my search result in a paged order. The problem with it is that at the first result of the search it shows the number of pages related to the search result but once I click on the next page it keeps invoking the method of the page list in the HttpGet rather than keeping browsing the result that came from the the HttpPost method. How can I fix this
Controller:
public ActionResult SearchResult(int? page)
{
var result = from app in db.AllJobModel select app;
return View(result.ToList().ToPagedList(page ?? 1,5));
}
[HttpPost]
public ActionResult SearchResult(string searchTitle, string searchLocation, int? page)
{
setUpApi(searchTitle, searchLocation);
//setUpApi(searchTitle);
var result = db.AllJobModel.Where(a => a.JobTitle.Contains(searchTitle) && a.locationName.Contains(searchLocation));
return View(result.ToList().ToPagedList(page ?? 1, 5));
}
View :
#using (Html.BeginForm("SearchResult", "Home", FormMethod.Post))
{
<div class="job-listing-section content-area">
<div class="container">
<div class="row">
<div class="col-xl-4 col-lg-4 col-md-12">
<div class="sidebar-right">
<!-- Advanced search start -->
<div class="widget-4 advanced-search">
<form method="GET" class="informeson">
<div class="form-group">
<label>Keywords</label>
<input type="text" name="searchTitle" class="form-control selectpicker search-fields" placeholder="Search Keywords">
</div>
<div class="form-group">
<label>Location</label>
<input type="text" name="searchLocation" class="form-control selectpicker search-fields" placeholder="Location">
</div>
<br>
<a class="show-more-options" data-toggle="collapse" data-target="#options-content5">
<i class="fa fa-plus-circle"></i> Date Posted
</a>
<div id="options-content5" class="collapse">
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox15" type="checkbox">
<label for="checkbox15">
Last Hour
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox16" type="checkbox">
<label for="checkbox16">
Last 24 Hours
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox17" type="checkbox">
<label for="checkbox17">
Last 7 Days
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox18" type="checkbox">
<label for="checkbox18">
Last 30 Days
</label>
</div>
<br>
</div>
<a class="show-more-options" data-toggle="collapse" data-target="#options-content">
<i class="fa fa-plus-circle"></i> Offerd Salary
</a>
<div id="options-content" class="collapse">
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox2" type="checkbox">
<label for="checkbox2">
10k - 20k
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox3" type="checkbox">
<label for="checkbox3">
20k - 30k
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox4" type="checkbox">
<label for="checkbox4">
30k - 40k
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox1" type="checkbox">
<label for="checkbox1">
40k - 50k
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox7" type="checkbox">
<label for="checkbox7">
50k - 60k
</label>
</div>
<br>
</div>
<input type="submit" value="Update" class="btn btn-success" />
</form>
</div>
</div>
</div>
<div class="col-xl-8 col-lg-8 col-md-12">
<!-- Option bar start -->
<div class="option-bar d-none d-xl-block d-lg-block d-md-block d-sm-block">
<div class="row">
<div class="col-lg-6 col-md-7 col-sm-7">
<div class="sorting-options2">
<span class="sort">Sort by:</span>
<select class="selectpicker search-fields" name="default-order">
<option>Relevance</option>
<option>Newest</option>
<option>Oldest</option>
<option>Random</option>
</select>
</div>
</div>
<div class="col-lg-6 col-md-5 col-sm-5">
<div class="sorting-options">
<i class="fa fa-th-list"></i>
<i class="fa fa-th-large"></i>
</div>
</div>
</div>
</div>
#foreach (var item in Model)
{
<div class="job-box">
<div class="company-logo">
<img src="~/JobImageUploads/#Html.DisplayFor(modelItem => item.UniqueJobImageName)" alt="logo">
</div>
<div class="description">
<div class="float-left">
<h5 class="title">#item.JobTitle</h5>
<div class="candidate-listing-footer">
<ul>
<li><i class="flaticon-work"></i>#Html.DisplayFor(modelIem => item.maximumSalary)</li>
<li><i class="flaticon-time"></i>#Html.DisplayFor(modelIem => item.maximumSalary)</li>
<li><i class="flaticon-pin"></i>#Html.DisplayFor(modelIem => item.locationName)</li>
</ul>
<h6>Deadline: Jan 31, 2019</h6>
</div>
<div>
#item.JobDescription
</div>
</div>
<div class="div-right">
#Html.ActionLink("Details", "Details", new { id = item.Id }, new { #class = "apply-button" })
Details
<i class="flaticon-heart favourite"></i>
</div>
</div>
</div>
}
</div>
</div>
</div>
</div>
<div class="pagining">
#Html.PagedListPager(Model, page => Url.Action("SearchResult", new
{ page }))
</div>
}
One solution to preserve browsing results would be to pass searchTitle and searchLocation to your SearchResult GET method as well and keep them in the ViewBag to persist search results on paging.
This is because the PagedList helper uses a Url.Action which invokes the the SearchResults GET request.
EDIT: upon further testing, I would do away with the post method all together and change your form to use the GET method for everything. I have updated the code to reflect this approach.
public ActionResult SearchResult(int? page, string searchTitle = null, string searchLocation = null)
{
ViewBag.searchTitle = searchTitle;
ViewBag.searchLocation = searchLocation;
ViewBag.page = page;
var result = new List<Job>(); //replace with AllJobModel class
if(!string.IsNullOrEmpty(ViewBag.searchTitle) || !string.IsNullOrEmpty(ViewBag.searchTitle))
{
setUpApi(searchTitle, searchLocation);
//setUpApi(searchTitle);
result = db.AllJobModel.Where(a => a.JobTitle.Contains(searchTitle) && a.locationName.Contains(searchLocation));
}
else
{
result = from app in db.AllJobModel select app;
}
return View(result.ToList().ToPagedList(page ?? 1, 5));
}
and then in your view, set the values (if any) in the searchTitle and searchLocation text boxes. Also add them to the pagedList helper so the values persist on paging.
Edit: Also gonna need to add a hidden field to persist the page value on searches.
#using (Html.BeginForm("SearchResult", "Home", FormMethod.Get))
{
<input type="hidden" name="page" value="#ViewBag.page">
<div class="job-listing-section content-area">
<div class="container">
<div class="row">
<div class="col-xl-4 col-lg-4 col-md-12">
<div class="sidebar-right">
<!-- Advanced search start -->
<div class="widget-4 advanced-search">
<form method="GET" class="informeson">
<div class="form-group">
<label>Keywords</label>
<input type="text" name="searchTitle" class="form-control selectpicker search-fields" placeholder="Search Keywords" value="#ViewBag.searchTitle">
</div>
<div class="form-group">
<label>Location</label>
<input type="text" name="searchLocation" class="form-control selectpicker search-fields" placeholder="Location" value="#ViewBag.searchLocation">
</div>
<br>
<a class="show-more-options" data-toggle="collapse" data-target="#options-content5">
<i class="fa fa-plus-circle"></i> Date Posted
</a>
<div id="options-content5" class="collapse">
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox15" type="checkbox">
<label for="checkbox15">
Last Hour
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox16" type="checkbox">
<label for="checkbox16">
Last 24 Hours
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox17" type="checkbox">
<label for="checkbox17">
Last 7 Days
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox18" type="checkbox">
<label for="checkbox18">
Last 30 Days
</label>
</div>
<br>
</div>
<a class="show-more-options" data-toggle="collapse" data-target="#options-content">
<i class="fa fa-plus-circle"></i> Offerd Salary
</a>
<div id="options-content" class="collapse">
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox2" type="checkbox">
<label for="checkbox2">
10k - 20k
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox3" type="checkbox">
<label for="checkbox3">
20k - 30k
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox4" type="checkbox">
<label for="checkbox4">
30k - 40k
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox1" type="checkbox">
<label for="checkbox1">
40k - 50k
</label>
</div>
<div class="checkbox checkbox-theme checkbox-circle">
<input id="checkbox7" type="checkbox">
<label for="checkbox7">
50k - 60k
</label>
</div>
<br>
</div>
<input type="submit" value="Update" class="btn btn-success" />
</form>
</div>
</div>
</div>
<div class="col-xl-8 col-lg-8 col-md-12">
<!-- Option bar start -->
<div class="option-bar d-none d-xl-block d-lg-block d-md-block d-sm-block">
<div class="row">
<div class="col-lg-6 col-md-7 col-sm-7">
<div class="sorting-options2">
<span class="sort">Sort by:</span>
<select class="selectpicker search-fields" name="default-order">
<option>Relevance</option>
<option>Newest</option>
<option>Oldest</option>
<option>Random</option>
</select>
</div>
</div>
<div class="col-lg-6 col-md-5 col-sm-5">
<div class="sorting-options">
<i class="fa fa-th-list"></i>
<i class="fa fa-th-large"></i>
</div>
</div>
</div>
</div>
#foreach (var item in Model)
{
<div class="job-box">
<div class="company-logo">
<img src="~/JobImageUploads/#Html.DisplayFor(modelItem => item.UniqueJobImageName)" alt="logo">
</div>
<div class="description">
<div class="float-left">
<h5 class="title">#item.JobTitle</h5>
<div class="candidate-listing-footer">
<ul>
<li><i class="flaticon-work"></i>#Html.DisplayFor(modelIem => item.maximumSalary)</li>
<li><i class="flaticon-time"></i>#Html.DisplayFor(modelIem => item.maximumSalary)</li>
<li><i class="flaticon-pin"></i>#Html.DisplayFor(modelIem => item.locationName)</li>
</ul>
<h6>Deadline: Jan 31, 2019</h6>
</div>
<div>
#item.JobDescription
</div>
</div>
<div class="div-right">
#Html.ActionLink("Details", "Details", new { id = item.Id }, new { #class = "apply-button" })
Details
<i class="flaticon-heart favourite"></i>
</div>
</div>
</div>
}
</div>
</div>
</div>
</div>
<div class="pagining">
#Html.PagedListPager(Model, page => Url.Action("SearchResult", new
{ page, searchTitle = ViewBag.searchTitle, searchLocation = ViewBag.SearchLocation }))
</div>
}
I know this is a slight change to your original design, so please let me know if you'd like to discuss it further.
Hope this helps you!
I am in need of some advice. I am wanting to implement my own custom editor for a specific object type, Address. I started by reading the documentation for Tag Helpers on the .NET Core website and then read about View Components on the Core site and neither really made since for my exact scenario.
I have a model Address:
public class Address
{
public Guid Id { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string StateCode { get; set; }
public string PostalCode { get; set; }
}
I want to create either a custom editor template, tag helper, or view component that will allow me to do something like this (In my "Edit" View):
#model TestApplication.Models.Customer
<h2>Edit Customer</h2>
<form asp-action="Edit">
<div class="form-horizontal">
<h4>Edit Customer</h4>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Name" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
</div>
<address-editor asp-for="HomeAddress" />
<address-editor asp-for="WorkAddress" />
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</form>
I would like the HTML to be rendered like so:
Edit Customer
<form asp-action="Edit">
<div class="form-horizontal">
<h4>Edit Customer</h4>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Name" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input id="Name" name="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
</div>
<h4>Home Address</h4>
<input type="hidden" asp-for="HomeAddress_Id" />
<div class="form-group">
<label asp-for="HomeAddress_AddressLine1" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input id="HomeAddress_AddressLine1" name="HomeAddress_AddressLine1" class="form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="HomeAddress_AddressLine2" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input id="HomeAddress_AddressLine2" name="HomeAddress_AddressLine2" class="form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="HomeAddress_City" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input id="HomeAddress_City" name="HomeAddress_City" class="form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="HomeAddress_StateCode" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input id="HomeAddress_StateCode" name="HomeAddress_StateCode" class="form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="HomeAddress_PostalCode" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input id="HomeAddress_PostalCode" name="HomeAddress_PostalCode" class="form-control" />
</div>
</div>
<h4>Work Address</h4>
<input type="hidden" asp-for="WorkAddress_Id" />
<div class="form-group">
<label asp-for="WorkAddress_AddressLine1" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input id="WorkAddress_AddressLine1" name="WorkAddress_AddressLine1" class="form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="WorkAddress_AddressLine2" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input id="WorkAddress_AddressLine2" name="WorkAddress_AddressLine2" class="form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="WorkAddress_City" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input id="WorkAddress_City" name="WorkAddress_City" class="form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="WorkAddress_StateCode" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input id="WorkAddress_StateCode" name="WorkAddress_StateCode" class="form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="WorkAddress_PostalCode" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input id="WorkAddress_PostalCode" name="WorkAddress_PostalCode" class="form-control" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</form>
Am I on the right direction by looking into Editor Templates? If so, how do I prefix the control names with the Model.PropertyName (i.e. HomeAddress_)?
I believe my answer came about by researching view components a bit more. I could have gone the direction of a tag helper, view component, or editor template. I decided on view component and needed to know how to pass the entire model information into the view component, well, this question helped me get there. The issue I was having (or question) was that I needed to know about ModelExpression. That class contains everything that I need (name and model), so I was able to do like the following:
<vc:address-editor asp-for="#Model.HomeAddress"></vc:address-editor>
Then, in my AddressEditor ViewComponent, I simply used the two properties that I needed:
public IViewComponentResult Invoke(ModelExpression aspFor)
{
ViewBag.AspFor = aspFor.Name;
return View(aspFor.Model);
}
I'm facing a prblm with updating an object, because when i'm trying to display my object id on updateApp function i got 0 which mean its not the same object on editApp function
Controller
#RequestMapping(value = { "/edtApp-{id}" }, method = RequestMethod.GET)
public String editApp(#PathVariable int id, ModelMap model) {
PIL_P_APPLCTN application = appService.findById(id);
logger.info("=========>"+application.getId()+" "+application.getAPPLCTN_CD());
List<PRM_CONTEXTE> cntxt = cntxtService.findAllOBJECTS();
model.addAttribute("cntxt", cntxt);
model.addAttribute("application", application);
model.addAttribute("edit", true);
model.addAttribute("loggedinuser", getFullName());
return "formApp";
}
#RequestMapping(value = { "/edtApp-{id}" }, method = RequestMethod.POST)
public String updateApp(#Valid #ModelAttribute("application") PIL_P_APPLCTN application, BindingResult result, ModelMap model,
#PathVariable int id) {
logger.info("====**=====>"+application.getId()+" "+application.getAPPLCTN_CD());
logger.info("====**=====>"+application.getId()+" "+application.getAPPLCTN_DS());
logger.info("====**=====>"+application.getId()+" "+application.getAPPLCTN_ID());
logger.info("====**=====>"+application.getId()+" "+application.getDECLG_IDNTFNT_NU());
logger.info("====**=====>"+application.getId()+" "+application.getVersion());
logger.info("====**=====>"+application.getId()+" "+application.getActive());
List<PRM_CONTEXTE> cntxt = cntxtService.findAllOBJECTS();
if (result.hasErrors()) {
model.addAttribute("cntxt", cntxt);
return "formApp";
}
appService.updateOBJECT(application);
return "redirect:/appli";
}
EDIT1
<form:form method="POST" modelAttribute="application" class="form-horizontal form-label-left" >
<form:input type="hidden" path="id" id="id"/>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="active">ACTIVE</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<div class="">
<form:checkbox id="active" path="active" name="active" class="js-switch" />
</div>
<form:errors path="active" cssClass="alerttt"/>
</div>
</div>
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="APPLCTN_CD">APPLCTN CD </label>
<div class="col-md-6 col-sm-6 col-xs-12">
<form:input type="text" path="APPLCTN_CD" id="APPLCTN_CD" name="APPLCTN_CD" class="form-control col-md-7 col-xs-12"/>
</div>
<form:errors path="APPLCTN_CD" cssClass="alerttt" />
</div>
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="APPLCTN_ID">APPLCTN ID
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<form:input type="text" path="APPLCTN_ID" id="APPLCTN_ID" name="APPLCTN_ID" class="form-control col-md-7 col-xs-12"/>
</div>
<form:errors path="APPLCTN_ID" cssClass="alerttt"/>
</div>
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="APPLCTN_DS">APPLCTN DS
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<form:input type="text" path="APPLCTN_DS" id="APPLCTN_DS" name="APPLCTN_DS" class="form-control col-md-7 col-xs-12"/>
</div>
<form:errors path="APPLCTN_DS" cssClass="alerttt"/>
</div>
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="DECLG_IDNTFNT_NU">DECLG IDNTFNT NU
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<form:input type="text" path="DECLG_IDNTFNT_NU" id="DECLG_IDNTFNT_NU" name="DECLG_IDNTFNT_NU" class="form-control col-md-7 col-xs-12"/>
</div>
<form:errors path="DECLG_IDNTFNT_NU" cssClass="alerttt"/>
</div>
<c:if test="${edit}">
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="version">VERSION
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<form:input type="text" path="version" id="version" name="version" class="form-control col-md-7 col-xs-12"/>
</div>
<form:errors path="version" cssClass="alerttt"/>
</div>
</c:if>
<c:if test="${!edit}">
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="version">VERSION
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<form:input disabled="true" type="text" path="version" id="version" name="version" class="form-control col-md-7 col-xs-12"/>
</div>
<form:errors path="version" cssClass="alerttt"/>
</div>
</c:if>
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="CONTEXT">CONTEXT</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<form:select itemValue="id" path="CONTEXTE" itemLabel="CONTEXTE_CD" items="${cntxt}" class="select2_single form-control" tabindex="-1" />
</div>
<form:errors path="CONTEXTE" cssClass="alerttt"/>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-md-offset-3">
<c:choose>
<c:when test="${edit}">
<button type="button" class="btn btn-primary" onClick="location.href='<c:url value='/appli' />'">Annuler</button>
<input type="submit" class="btn btn-success" value="Modifier" />
</c:when>
<c:otherwise>
<button type="button" class="btn btn-primary" onClick="location.href='<c:url value='/appli' />'">Annuler</button>
<input type="submit" class="btn btn-success" value="Ajouter"/>
</c:otherwise>
</c:choose>
</div>
</div>
</form:form>
thanks for any advices..
The issue is fixed by changing the name of the pathVariable, because it was the same as the id and by adding setter for id in my Entity
#RequestMapping(value = { "/edtApp-{i}" }, method = RequestMethod.GET)
public String editApp(#PathVariable int i, ModelMap model) {
//....
}
#RequestMapping(value = { "/edtApp-{i}" }, method = RequestMethod.POST)
public String updateApp(#Valid #ModelAttribute("application") {
//....
}
I found a problem using Thymeleaf in a Spring Boot application.
Versions:
Spring Boot 1.3.4 and 1.3.3
My Entity:
#Entity
public class MyEntity {
#Id
#GeneratedValue
private Long id;
#Version
private int version;
#DateTimeFormat(pattern="dd/MM/yyyy")
private Calendar calendar;
#DateTimeFormat(pattern="dd/MM/yy")
private Date date;
#NumberFormat(pattern="#0.00000")
private Double aDouble;
}
My Controller:
#RequestMapping(value = "/{myEntity}/edit-form",
method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public String editForm(#PathVariable MyEntity myEntity, Model model) {
return "myEntity/edit";
}
My myEntity/edit.html template:
<form class="form-horizontal" method="POST"
data-th-object="${myEntity}"
data-th-action="#{/myEntity/{id}(id=*{id})}">
<input type="hidden" name="_method" value="PUT" />
<div class="form-group"
data-th-classappend="${#fields.hasErrors('calendar')}? 'has-error has-feedback'">
<label for="calendar" class="col-md-3 control-label">Calendar</label>
<div class="col-md-3">
<input type="text" class="form-control"
data-th-field="*{calendar}"/>
<span data-th-text="*{{calendar}}"></span>
</div>
</div>
<div class="form-group"
data-th-classappend="${#fields.hasErrors('date')}? 'has-error has-feedback'">
<label for="date" class="col-md-3 control-label">Date</label>
<div class="col-md-3">
<input type="text" class="form-control"
data-th-field="*{date}"/>
<span data-th-text="*{{date}}"></span>
</div>
</div>
<div class="form-group"
data-th-classappend="${#fields.hasErrors('aDouble')}? 'has-error has-feedback'">
<label for="date" class="col-md-3 control-label">aDouble</label>
<div class="col-md-3">
<input type="text" class="form-control"
data-th-field="*{{aDouble}}"/>
<span data-th-text="*{{aDouble}}"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<div class="pull-right">
<button type="submit" class="btn btn-primary">Update</button>
</div>
</div>
</div>
</form>
When I try to show this page I get:
<body>
<form class="form-horizontal" method="POST" action="/myEntity/1">
<input type="hidden" name="_method" value="PUT" />
<div class="form-group">
<label for="calendar" class="col-md-3 control-label">Calendar</label>
<div class="col-md-3">
<input type="text" class="form-control" id="calendar" name="calendar"
value="java.util.GregorianCalendar[time=1451602800000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Madrid",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=165,lastRule=java.util.SimpleTimeZone[id=Europe/Madrid,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2016,MONTH=0,WEEK_OF_YEAR=53,WEEK_OF_MONTH=0,DAY_OF_MONTH=1,DAY_OF_YEAR=1,DAY_OF_WEEK=6,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=3600000,DST_OFFSET=0]" />
<span>01/01/2016</span>
</div>
</div>
<div class="form-group">
<label for="date" class="col-md-3 control-label">Date</label>
<div class="col-md-3">
<input type="text" class="form-control" id="date" name="date"
value="2016-02-01 00:00:00.0" />
<span>01/02/16</span>
</div>
</div>
<div class="form-group">
<label for="date" class="col-md-3 control-label">aDouble</label>
<div class="col-md-3">
<input type="text" class="form-control" id="aDouble" name="aDouble"
value="0.1" />
<span>0.10000</span>
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<div class="pull-right">
<button type="submit" class="btn btn-primary">Update</button>
</div>
</div>
</div>
</form>
</body>
As you can see, the values of all fields aren't formatted as expected (see span which uses the same value through th-text attribute) using toString() method for all values.
Anybody can help me? Thank's in advance.
EDIT 1: I've create a new issue about it
Solved. The problem was in the requestMapping definition:
#RequestMapping(value = "/{myEntity}/edit-form", method = RequestMethod.GET,
produces = MediaType.TEXT_HTML_VALUE)
public String editForm(#PathVariable MyEntity myEntity, Model model) {
}
It requires a BindingResult in request context to get PropertyEditor which can transform object value to String. So, including BindingResult in request mapping definition all works as expected:
#RequestMapping(value = "/{myEntity}/edit-form", method = RequestMethod.GET,
produces = MediaType.TEXT_HTML_VALUE)
public String editForm(#ModelAttribute MyEntity myEntity, BindingResult result,
Model model) {
}
Note that object must be annotated with #ModelAttribute and BindingResult must be declared just after #ModelAttribute.
Thank you to everyone who tried to help me.
For date I'd use:
${#dates.format(date, 'dd/MMM/yyyy HH:mm')}
and for numbers:
${#numbers.formatDecimal(num,3,2,'COMMA')}
In documentation it's explained for numbers and dates.