This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 4 years ago.
I am trying to post a list of objects from View to controller.
Below is my code:
View :
#using Models
#model IList<Add>
#{
ViewData["Title"] = "AddNewFields";
}
<form asp-controller="Trans" asp-action="InsertFields" method="post" class="form-horizontal card-body" role="form">
<td><input type="text" class="form-control" value="Field Size" asp-for="#Model[i].TypeFlag"/></td>
<td><input type="text" class="form-control" value="Field Value" asp-for="#Model[i].FieldValue"/></td>
<td><input type="text" class="form-control" value="Field Format" asp-for="#Model[i].FieldFormat"/></td>
</form>
I will be adding mo these text fields again on button click.
Model:
public class Add
{
public string TypeFlag { get; set; }
public string FieldValue { get; set; }
public string FieldFormat { get; set; }
}
Controller:
public string InsertFields(IList<Add> fields)
{
//some logic
}
When I run the application, I am getting the below error:
NullReferenceException: Object reference not set to an instance of an object.
AspNetCore.Views_Trans_Add.<ExecuteAsync>b__27_0() in AddNewFields.cshtml
#for (int i = 0; i < Model.Count; i++)
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.GetChildContentAsync(bool useCachedResult, HtmlEncoder encoder)
Microsoft.AspNetCore.Mvc.TagHelpers.RenderAtEndOfFormTagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output)
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.RunAsync(TagHelperExecutionContext executionContext)
Please help me...I am stuck here from 2 days..
2 issues:
Model is null
Action will not get values.
solution:
Your HTML should be this style
#{
var fields = (Model ?? Enumerable.Empty<Add>()).ToList(); //this variable must be same with the parameter in action.
}
<form asp-action="Test" method="post">
<table class="table">
<tbody>
<tr>
<td>
<div class="form-group">
<input type="submit" value="Submit" />
</div>
</td>
</tr>
#for (var i = 0; i < fields.Count; i++) //you must use for, not foreach
{
<tr>
<td>
<div class="form-group">
<input type="hidden" asp-for="#fields[i].Id" />
<input asp-for="#fields[i].Name" class="form-control" />
</div>
</td>
</tr>
}
</tbody>
</table>
</form>
your controller should be this:
[HttpPost]
public async Task<IActionResult> Test(IEnumerable<Add> fields)
//be aware: the parameter name "fields" must be same with your html
//the type should be "IEnumerable<Add>", more compatible with different versions of MVC
{
.....your logic
return Json(new { ... });
}
the generated html is this style:
<tr>
<td>
<div class="form-group">
<input type="hidden" id="fields_0__Id" name="fields[0].Id" value="14">
<input class="form-control" type="text" id="fields_0__Name" name="fields[0].Name" value="xxxxx">
</div>
</td>
</tr>
<tr>
<td>
<div class="form-group">
<input type="hidden" id="fields_1__Id" name="fields[1].Id" value="1">
<input class="form-control" type="text" id="fields_1__Name" name="fields[1].Name" value="xxxx">
</div>
</td>
</tr>
you will see the reason: the parameter fields is just a field of html form, they must match each other.
Related
I am new to Thymeleaf and tried all possible solutions and workaround from web. Desperately I need some help to figure out on what is wrong here.
Not able get cart object(thymeleaf) value updated from html to MVC controller. instead CartViewModel object's fields (userI and products) in cart and modelMap objects are coming as null. even it is not getting values which i passed to populate the table in previous call.
Any help is highly appreciated. Thanks for your valuable time in advance.
Controller debug status
Controller code:
#Controller
public class MyController {
#Autowired
IProductService productService;
#Autowired
IVendorService vendorService;
#RequestMapping(value = "/", method = {RequestMethod.GET})
public String getVendors(VendorViewModel vendorViewModel, final ModelMap modelMap) {
modelMap.addAttribute("vendors", vendorService.getVendors());
return "home";
}
#RequestMapping(value = "/inventory", method = {RequestMethod.POST})
public String getProductsForSelectedVendor(VendorViewModel vendorViewModel, final ModelMap modelMap) {
modelMap.addAttribute("vendors", vendorService.getVendors());
modelMap.addAttribute("cart", new CartViewModel("Nish", productService.getProductsByVendor(vendorViewModel.getId())));
return "home";
}
#RequestMapping(value = "/cart", method = {RequestMethod.POST})
public String saveCart(#ModelAttribute(name = "cart") CartViewModel cart, ModelMap modelMap, BindingResult bindingResult) {
**//not able get cart object value set in html via thymeleaf. **
return "cart";
}
}
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
#JsonIgnoreProperties(ignoreUnknown = true)
public class CartViewModel {
private String userId;
//private List<ProductSelected> products;
private List<ProductViewModel> products;
}
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
#JsonIgnoreProperties(ignoreUnknown = true)
public class ProductViewModel
{
public String id;
public int qty = 0;
public String handle;
public String title;
public String bodyHTML;
public String vendor;
public String type;
public String tags;
public String variantPrice;
public String imageSrc;
public String imageAltText;
}
<div class="container-main">
<form method="POST" enctype="multipart/form-data" th:object="${vendorViewModel}" th:action="#{/inventory}">
<div>
<div style="float:left;padding-left:10px;">
<label for="selectVendor" class="input-label-name">Select Vendor</label>
</div>
<div style="float:left;padding-left:10px;">
<select id="selectVendor" required="required" th:field="*{id}" style="width:90%">
<option value=""></option>
<option th:each="vendor, iSat : ${vendors}" th:value="${vendor.id}" th:with="test=${vendor.name}" th:text="${vendor.name}">
</option>
</select>
</div>
<div style="float:left;padding-left:10px;">
<input type="submit" value="Get Products" class="btn">
</div>
</div>
</form>
<form method="POST" action="#" role="form" enctype="multipart/form-data" th:action="#{/cart}" th:object="${cart}">
<!-- https://stackoverflow.com/questions/49462788/how-to-post-a-list-to-controller-in-thymeleaf-->
<div style="padding-top: 50px;">
<table id="productTable" class="tableBodyScroll">
<tr>
<th>Quantity</th>
<th>QtyPrice</th>
<th>Handle</th>
<th>Title</th>
<th>Type</th>
<th>Tags</th>
<th>Price</th>
<th>Image</th>
<!-- <th>IN STOCK</th>-->
</tr>
<tr th:id="${prod.id}" th:each="prod,iterStat : ${cart.products}" th:class="${iterStat.odd}? 'odd'">
<td><span class="table-add"><button th:id="'add_' + ${prod.id}" type="button" class="btn btn-rounded btn-sm my-0">+</button></span>
<span type="text" th:id="'count_' + ${prod.id}" th:field="*{products[__${iterStat.index}__].qty}">0</span>
<span class="table-remove"><button th:id="'remove_' + ${prod.id}" type="button" class="btn btn-danger btn-rounded btn-sm my-0">-</button></span>
</td>
<td><span th:id="'qtyPrice_' + ${prod.id}">0</span></td>
<td th:text="${prod.handle}"></td>
<td th:text="${prod.title}"></td>
<td th:text="${prod.type}"></td>
<td th:text="${prod.tags}"></td>
<td th:id="'price_' + ${prod.id}" th:text="${prod.variantPrice}"></td>
<td><img height="50px" width="100px" th:src="${prod.imageSrc}" th:title="${prod.title}" th:alt="${prod.imageAltText}" /></td>
<!-- <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>-->
</tr>
</table>
</div>
<div style="float:left;padding-left:10px;">
<input type="submit" value="Go to Cart" class="btn">
</div>
</form>
</div>
I actually did some work around to overcome my problem using ajax call. But later I came across this, seems to be a better fit for my scenario.
Hope it would help someone.
I can't figure out how to get selected checkboxes to become "true" and unselected checkboxes to become "false" bool values. Here is a sample of the code I am working on.
Note: My put function is getting a 200 response but the checkboxes just are not updating the bool.
Model
public class AccountFeatures
{ public bool? FormCopy { get; set; }
public bool? FormRename { get; set; }
public bool? FormTransfer { get; set; }
public bool? FormDelete { get; set; }
public bool? FormEdit { get; set; }
public bool? FormComplete { get; set; }
}
View
`$('.ui.form.accountfeatures').form({
on: 'blur',
inline: true,
onSuccess: function () {
$('#features').dimmer('show');
$.ajax({
method: 'PUT',
data: { FormRename: $("#FormRename").val() ? true : false,
FormTransfer: $("#FormTransfer").val() ? true : false,
FormDelete: $("#FormDelete").val() ? true : false,
FormEdit: $("#FormEdit").val() ? true : false,
FormComplete: $("#FormComplete").val() ? true : false}
HTML
<tr>
<td>Form Copy</td>
<td class="center aligned">
<input type="checkbox" name="FormCopy" id="FormCopy" value="False" checked="#Model.Account.Features.FormCopy">
</td>
</tr>
<tr>
<td>Form Rename</td>
<td class="center aligned">
<input type="checkbox" name="FormRename" id="FormRename" value="FormRename" checked="#Model.Account.Features.FormRename">
</td>
</tr>
<tr>
<td>Form Transfer</td>
<td class="center aligned">
<input type="checkbox" name="FormTransfer" id="FormTransfer" value="FormTransfer" checked="#Model.Account.Features.FormTransfer">
</td>
</tr>
<tr>
<td>Form Delete</td>
<td class="center aligned">
<input type="checkbox" name="FormDelete" id="FormDelete" value="FormDelete" checked="#Model.Account.Features.FormDelete">
</td>
</tr>
<tr>
<td>Form Edit</td>
<td class="center aligned">
<input type="checkbox" name="FormEdit" id="FormEdit" value="FormEdit" checked="#Model.Account.Features.FormEdit">
</td>
</tr>
<tr>
<td>Form Complete</td>
<td class="center aligned">
<input type="checkbox" name="FormComplete" id="FormComplete" value="FormComplete" checked="#Model.Account.Features.FormComplete">
</td>
</tr>
I typically use an EditorFor and it just works:
#Html.EditorFor(m => m.CheckBoxProperty)
However, I also typically only use bool, not bool? for my checkbox properties.
Something to note regarding the checked attribute - you usually either use just the attribute name, as in:
<input type="checkbox" name="FormComplete" id="FormComplete" value="FormComplete" checked />
Or you use checked="checked", as in:
<input type="checkbox" name="FormComplete" id="FormComplete" value="FormComplete" checked="checked" />
Any other way, like putting checked="true" or checked="false" doesn't produce the outcome that you would expect, or at the very least, is not consistent amongst all browsers. What these use cases usually result in are checked boxes, regardless of whether you wanted that, or not. Here's a quick mock up to demonstrate:
<input type="checkbox" value="test" name="test1" /> Test 1<br />
<input type="checkbox" value="test" name="test2" checked /> Test 2<br />
<input type="checkbox" value="test" name="test3" checked="checked" /> Test 3<br />
<input type="checkbox" value="test" name="test4" checked="true" /> Test 4<br />
<input type="checkbox" value="test" name="test5" checked="false" /> Test 5
And a screenshot of the output under Chrome 57:
Essentially, you want to use logic to determine whether to insert the checked attribute altogether, rather than inserting it and having the logic set it to true or false.
I have a controller in which I put both the get and post methods. Both methods work fine but when I introduce #ModelAttribute annotation to the POST method, it starts giving me Status 400 -- The request sent by the client was syntactically incorrect.
I do not know what I am doing wrong. The View looks like:
<form:form method="post" action="createIdeaPublic" commandName="idea">
<table class="form">
<tr>
<td align="right"><label for="title">Idea Title</label></td><td align="left"><form:input type="text" path="title" id="title"></form:input></td>
<td align="right"><label for="email">Your Email</label></td><td align="left"><form:input type="text" path="requestorEmail" id="requestorEmail" class="emails"></form:input></td>
</tr>
<tr>
<td align="right"><label for="partnerEmail">CI Contact Email</label></td><td align="left"><form:input type="text" path="cIInitialContact" id="cIInitialContact" class="emails"></form:input></td>
<td align="right"><label for="sponsorEmail">Sponsor Email</label></td><td align="left"><form:input type="text" path="sponsorEmail" id="sponsorEmail" class="emails"></form:input></td>
</tr>
<tr>
<td align="right"><label for="requestedDeliveryDate">Requested Delivery Date</label></td><td align="left"><form:input type="text" path="requestedDeliveryDate" id="requestedDeliveryDate" class="datepicker"></form:input></td>
<td align="right"><label>Classification</label></td><td align="left">
<label for="discretionary" class="radio">Discretionary</label>
<form:radiobutton path="stateDescription" id="discretionary" value="Discretionary"></form:radiobutton>
<label for="mandatory" class="radio">Mandatory</label>
<form:radiobutton path="stateDescription" id="mandatory" value="Mandatory"></form:radiobutton>
<label for="regulatory" class="radio">Regulatory</label>
<form:radiobutton path="stateDescription" id="regulatory" value="Regulatory"></form:radiobutton>
</td>
</tr>
<tr>
<td colspan="4" align="right"><input type="submit" class="ui ui-button ui-corner-all ui-widget" style="margin-top: .6em; margin-right: 1em;font-weight: bold;font-size: 1.2em; width: 150px;" value="Create Idea" /></td>
</tr>
</table>
</form:form>
I tried changing the commandName="idea" to modelAttribute="idea" but no benifit.
The Spring controller looks like
#Controller
#RequestMapping ("/createIdeaPublic")
public class CreateIdeaPublicController{
#RequestMapping(method = RequestMethod.GET)
public ModelAndView view(ModelMap model) {
model.addAttribute("areas",Utils.areas);
return new ModelAndView("createIdeaPublic", "idea", new Idea());
}
#RequestMapping(method = RequestMethod.POST)
public String submit(#ModelAttribute("idea")Idea idea, ModelMap model) {
// System.out.println(idea.getTitle());
System.out.println("Hello World");
return "redirect:createIdeaPublic";
}
}
But as soon as I remove the #ModelAttribute("idea")Idea idea, from the submit method, the form submission starts working.
I figured it out. It was issue with the date field. If I dont enter a value into the date field, I would get 400 page. So here is what I did in the Controller class. Copy as it is if you have this issue (Just change the date format accordingly).
#InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
dateFormat.setLenient(false);
// true passed to CustomDateEditor constructor means convert empty String to null
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
I'm creating a table.I want to get selected checkbox value.
<tr>
<td>
#item
<input type="hidden" value="#item" name="#item" class="chkbx" id="ControllerName" />
</td>
<td>
<input type="checkbox" id="Iscreate" value="#Create" class="chkbx" />
</td>
<td>
<input type="checkbox" id="IsDelete" value="#Delete" class="chkbx" />
</td>
<td>
<input type="checkbox" id="IsView" value="#View" class="chkbx" />
</td>
<td>
<input type="checkbox" id="IsEdit" value="#Edit" class="chkbx" />
</td>
<td>
<input type="checkbox" id="IsDownload" value="#Download" class="chkbx" />
</td>
</tr>
Jquery code I use
<script type="text/javascript">
$('input[type=checkbox]').change(function () {
var vales = $("#ControllerName").val();
var vals = $('input[class=chkbx]:checked').map(function () {
return $(this).val();
}).get().join(',');
$('#debug').val(vals);
});
</script>
Basically this code create a Value in hidden Field Like this
3-Create-Account,3-Delete-Account,3-View-Account,3-Edit-Account,3-Download-Account
But Actually i need this
3-Account-Create-Delete-Edit-Download-view,4-Account-Create-Delete-Edit-Download-view, 5-Account-Create-Delete-Edit-Download-view
I'm totally Confused :(
Make a view model with your wanted properties:
public class YouViewModelName()
{
public bool IsView {get; set;}
public bool IsDeleted{get; set;}
public bool IsCreated{get; set;}
public bool IsEdited{get; set;}
......... and so on
}
Then use this view model in your view:
#Html.CheckBoxFor(x => x.IsView)
#Html.CheckBoxFor(x => x.IsDeleted)
#Html.CheckBoxFor(x => x.IsCreated)
#Html.CheckBoxFor(x => x.IsEdited)
and so on...
When you post the form to your post action, you will get the values.
[HttpPost]
public ActionResult PostActionName(ViewModelName viewModel)
{
//use values here
}
My form code is not generating correct HTML. Here's my code.
Here's the form code:
#using (Html.BeginForm("SendEmail", "PropertyDetails", FormMethod.Post))
{
<fieldset>
<div class="left">
<label for="Name">Your Name</label>
<input type="text" required name="Name" />
<label for="Phone">Your Phone Number</label>
<input type="text" required name="Phone" />
<label for="Email">Your Email</label>
<input type="email" class="text" required name="Email" />
</div>
<div class="right">
<label for="Message">Your Message</label>
<textarea name="Message">
</textarea>
<input type="submit" name="submit" value="send" />
<div class="clear"></div>
</div>
<div class="clear"></div>
</fieldset>
}
Here's my Controller. I have a breakpoint on the first line of the SendMail message which isn't being hit:
public class PropertyDetailsController : Controller
{
[HttpPost]
public ActionResult SendEmail(EmailData email)
{
if (ModelState.IsValid) // BREAKPOINT ON THIS LINE ISN'T BEING HIT
{
etc.
Here's the class that should get populated with the form data and passed into the method (I'm not doing this myself. I assume it's happening automatically under the covers).
public class EmailData
{
private string _name;
private string _email;
private string _phone;
private string _message;
[Required]
[StringLength(50, MinimumLength = 1)]
public string Name
{
get { return _name; }
set { _name = value == null ? string.Empty : value.Trim(); }
}
[Required]
[RegularExpression(RegEx.Email, ErrorMessage = "Invalid e-mail address.")]
public string Email
{
get { return _email; }
set { _email = value == null ? string.Empty : value.Trim(); }
}
public string Phone
{
get { return _phone; }
set { _phone = value == null ? string.Empty : HtmlHelper.StripIllegalXmlChars(value.Trim()); }
}
[StringLength(500, MinimumLength = 1)]
public string Message
{
get { return _message; }
set { _message = value == null ? string.Empty : HtmlHelper.StripIllegalXmlChars(value.Trim()); }
}
}
Here's the HTML that's being generated:
<form action="" method="post">
<fieldset>
<div class="left">
<label for="Name">Your Name</label>
<input type="text" required name="Name" />
<label for="Phone">Your Phone Number</label>
<input type="text" required name="Phone" />
<label for="Email">Your Email</label>
<input type="email" class="text" required name="Email" />
</div>
<div class="right">
<label for="Message">Your Message</label>
<textarea name="Message">
</textarea>
<input type="submit" name="submit" value="send" />
<div class="clear"></div>
</div>
<div class="clear"></div>
</fieldset>
</form>
Any ideas why the action is empty?
Change your <form> declaration to this:
<% using (Html.BeginForm("SendEmail", "[Controller]")) { %>
<!-- Form data -->
<% } %>
Where [Controller] is the name of your Controller minus "Controller". In other words, if the controller name is HomeController, you would use "Home".
Try changing the form declaration within your view to this (using Razor syntax):
#using (this.Html.BeginForm("SendEmail", "[your controller name]", FormMethod.Post))
{
[form HTML]
}
The using statement will ensure that your form is closed correctly.
Also the HtmlHelper.BeginForm extension method is flexible enough that it generates the URI for the action based on the routes defined in your application's RouteCollection, such that if your routes change the form does not need to be updated; the change in URI is handled gracefully and automatically.
You need to add an action to your form
<form action="/SendEmail/" method="post">
But really this should be done using the MVC3 BeginForm helper.
You need to have your HTML rendered by a controller. So put your HTML in a View called "SendEmail" and write a controller action with an [HttpGet] attribute.
Call the Action "SendEmail" and in it just do return View().
Like this
[HttpGet]
public ActionResult SendEmail()
{
return View();
}
That will cause the BeginForm to render the action="" properly.
Then once that's working you are going to have a problem when you do post the data back because the input fields aren't bound to you model. You need to add #model yournamespace.EmailData to the very top of your View and then you need to change your inputs to bind to the model properties.
I've no idea how good this link is but it's the first one I found that looks like it might guide you through a similar process http://geekswithblogs.net/WinAZ/archive/2010/10/30/an-mvc-3-contact-form.aspx