.net MVC posting nested model to controller, data set is empty - asp.net-mvc

<form method="post">
<input type="text" name="ClientList[0].ItemList[0].ItemID">
<input type="text" name="ClientList[0].ItemList[0].Qty">
<input type="text" name="ClientList[0].ItemList[1].ItemID">
<input type="text" name="ClientList[0].ItemList[1].Qty">
<input type="text" name="ClientList[1].ItemList[0].ItemID">
<input type="text" name="ClientList[1].ItemList[0].Qty">
<input type="text" name="ClientList[1].ItemList[1].ItemID">
<input type="text" name="ClientList[1].ItemList[1].Qty">
<input type="submit" />
</form>
This is controller
[HttpPost]
public ActionResult Sale(List<ClientList> ClientList)
{
return View();
}
public class ClientList
{
public List<ItemList> ItemList = new List<ItemList>();
}
public class ItemList
{
public int ItemID { get; set; }
public string Qty { get; set; }
}
This is result
the second loop, items details are not submitting.

Your ItemList is a field, not a property, and the DefaultModelBinder cannot set its value.
Change it to
public class ClientList
{
public List<ItemList> ItemList { get; set; }
}
As a side note, the name attributes can be just
<input type="text" name="[0].ItemList[0].ItemID">
which allows you to name the parameter in the POST method to anything you want (except ItemList)

I used a bit different approach, with named list
[HttpPost]
public ActionResult Sale(List<ClientList> ClientList)
{
return View();
}

Related

MVC Core - strange view rendering issue

I am using MVC to display a simple form in a view:
ViewModel:
public class CreateSaleViewModel
{
public string OrderId { get; set; }
public decimal TotalAmount { get; set; }
public bool ShowInstoreConfirmDetails { get; set; }
}
Controller action:
[HttpGet]
public IActionResult CreateSale()
{
return View(new CreateSaleViewModel());
}
View:
#model CreateSaleViewModel
<form asp-controller="Sales" asp-action="CreateSale" method="post">
<input asp-for="OrderId" />
<input asp-for="TotalAmount" />
<button type="submit" name="CreateSale" id="CreateSale">
button
</button>
</form>
I then post to a new view, where the same details need to be entered. To do this I store the old values in hidden inputs and provide another form to re-enter the details.
ViewModel:
public class ConfirmDetailsViewModel
{
public string OrderId { get; set; }
public decimal TotalAmount { get; set; }
public string ConfirmOrderId { get; set; }
public decimal ConfirmTotalAmount { get; set; }
}
Controller:
[HttpPost("Confirmdetails")]
public IActionResult ConfirmDetails(CreateSaleViewModel model)
{
var viewModel = new ConfirmDetailsViewModel
{
ConfirmOrderId = model.OrderId,
ConfirmTotalAmount = model.TotalAmount,
OrderId = string.Empty,
TotalAmount = 0.0m
};
return View("ConfirmDetails", viewModel);
}
View:
#model ConfirmDetailsViewModel
<form asp-controller="Sales" asp-action="Summary" method="post">
<input type="hidden" value="#Model.ConfirmOrderId" id="OrderIdConfirm" />
<input type="hidden" value="#Model.ConfirmTotalAmount" id="TotalAmountConfirm" />
<input type="hidden" value="#Model.OrderId" id="banana" />
<input asp-for="OrderId" />
<input asp-for="TotalAmount" />
<button type="submit" name="CreateSale" id="CreateSale">
button
</button>
</form>
My problem is on the confirmdetails view orderId and TotalAmount retain the values that were posted from the previous page.
I have debugged the controller and can see the ConfirmOrderId and ConfirmTotalAmount properties have the correct values, and also OrderId and TotalAmount are empty strign and 0 respectively.
Even stranger is that
<input type="hidden" value="#Model.OrderId" id="banana" />
Has the correct value of "".
Does anyone know what is causing this issue?
MVC stores the posted back values in ModelState.
These values are used by default in #Html helpers - as a convenience. This allows the values of hidden form fields to be preserved through postbacks, even if they don't have properties in the view-model.
Unfortunately what is usually a convenience turns into a headache, if you try to modify the model's properties within the action. Helpers take their values from ModelState, ignoring the updated view-model.
To solve this, call ModelState.Clear()
removes all the posted back values from ModelState
the helpers will now use the values from the view-model.
Controller:
[HttpPost]
public IActionResult ConfirmDetails(CreateSaleViewModel model)
{
var viewModel = new ConfirmDetailsViewModel
{
ConfirmOrderId = model.OrderId,
...
};
ModelState.Clear(); // force asp-helpers to use the updated model's values
return View("ConfirmDetails", viewModel);
}

get information from form to controller and save it in database

I have this code in my html.And i want to post this information from form to controler and save in data base.
<form method="POST" class="contactme form-group">
<input type="text" placeholder="Name" class="form-control inputcontact">
<input type="text" placeholder="Surename" class="form-control inputcontact">
<input type="email" placeholder="E-mail" class="form-control inputcontact">
<input type="tel" pattern="[0-9]{5,10}" class="form-control inputcontact" placeholder="tel. number"><br>
<input type="submit" class="btn btn-default buttonsend" value="Оставить заявку">
</form>
And i have this model:
public int Id { get; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Email { get; set; }
public string Phonenumber { get; set; }
The MVC concept is quite straight forward for achieving what you need. It's usual to have a model that contains properties for the data that you need to display a "View" and also for the content entered by the user so the data can be bound to the model when posted. If you've not got any controller code yet then I would recommend the below approach.
First, write a controller to handle the displaying of your view and the posting of the views form content.
public class YourController : Controller
{
[HttpGet]
public ActionResult YourViewName()
{
var myViewModel = new YourViewModel();
//Populate model data from services etc...
return View("YourViewName", myViewModel);
}
}
I find it easier to wrap my views data objects that it needs in a class.
public class YourViewModel
{
public string Property1 { get; set; }
public int Property2 { get; set; }
\\etc...
}
Then in your view, wrap your controls in a Form and use Html helper controls to display and bind to the data in the model.
#using (Html.BeginForm("ActionName", "YourController ", FormMethod.Post, new { id = "FormName"}))
{
#Html.TextBoxFor(x => x.YourModel.Property1, null, new { #class = "SomeCssClass"})
\\Repeat for all properties that need displaying or for user input.
}
You will also need a submit button on the form to post the form to your specified controller.
<button id="btnSubmitForm" type="Submit" class="SomeCssClass">Submit</button>
Then in your controller you create a method to receive the posted form (Model)
[HttpPost]
public ActionResult ActionName(YourViewModel postedContent)
{
//Handle saving etc.. here.
var x = postContent.Property1;
//Do something with data
//Re populate model and show updated view.
var myViewModel = new YourViewModel();
return View("YourViewName", myViewModel);
}
Thant should help you on your way. A lot of this is down to preference and opinions though.
You have to tell it which Controller and which Action in the controller to look for like below:
using (Html.BeginForm("YourActionMethodHere", "YourControllerHere", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
<input type="text" placeholder="Name" class="form-control inputcontact">
<input type="text" placeholder="Surename" class="form-control inputcontact">
<input type="email" placeholder="E-mail" class="form-control inputcontact">
<input type="tel" pattern="[0-9]{5,10}" class="form-control inputcontact" placeholder="tel. number"><br>
<input type="submit" class="btn btn-default buttonsend" value="Оставить заявку">
}
This link should also help

Blog Comments MVC simple Creating new comments

I have problems getting my blog create comments working it works fine when I edit in the db putting the relation id in but I cannot get it when I use the form.
Error is here: Blogposts = id
public ActionResult BlogPost(int Id)
{
var _getSpecificBlogPost = db.Blogposts.Where(m => m.Id == Id).ToList();
return View(_getSpecificBlogPost);
}
[HttpPost]
public ActionResult BlogComment_Create(string name, string bodytext, string id )
{
BlogComment model = new BlogComment { Name = name, BodyText = bodytext, Blogposts = id};
db.BlogComments.Add(model);
db.SaveChanges();
return Redirect(Request.UrlReferrer.PathAndQuery);
}
In BlogComment I have: public virtual Blogpost Blogposts { get; set; }
In BlogPosts I have: public virtual ICollection<BlogComment> BlogComments { get; set; }
<form method="post" id="form-variant-create" action="#Url.Action("BlogComment_Create", "Blog")" role="form">
<div class="form-group">
<input type="text" name="name" class="form-control" placeholder="Name" />
<br />
<textarea name="bodytext" class="form-control" rows="3" placeholder="Message"></textarea>
<input type="text" class="hidden" name="id" value="#foreach(var item in Model){#item.Id}" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
BlogPosts is from BlogPost type. you need to create a property for your BlogPostId as ForeignKey.
public virtual int BlogPostId{get;set;}
Insert this line into your CommentModel. and then reffer to this instead of BlogPosts.
and edit your BlogPosts Property too.
[ForeignKey("BlogPostId")]
public virtual Blogpost Blogposts { get; set; }

Input type checkbox with MVC razor

Why is the value of my checkbox not passed to my ViewModel?
My View (I omitted input tags not relevant for this post):
#model Pro.WebUI.ViewModels.UserViewModel
#using (Html.BeginForm("ManageUsers", "Administration", FormMethod.Post,
new { id = "request-form", #class = "form-horizontal" }))
{
<div class="form-group">
<label for="inputAuthorize" class="col-lg-2 control-label">Authorize</label>
<div class="col-lg-8">
<input type="checkbox" id="Authorized" name="Authorized" value="#Model.Authorized" />
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<br /><br />
<button type="submit" class="btn btn-primary">Submit Request</button>
</div>
</div>
}
My ViewModel:
public class UserViewModel
{
[Key]
public string UserID { get; private set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool Authorized { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Notes { get; set; }
}
My Controller:
[HttpPost]
public ActionResult ManageUsers(UserViewModel model)
{
if (ModelState.IsValid)
{
ProcurementUser obj = new ProcurementUser();
obj.UserName = model.Email;
obj.FirstName = model.FirstName;
obj.LastName = model.LastName;
obj.Email = model.Email;
obj.Phone = model.Phone;
obj.Authorized = model.Authorized;
UserRepository.SaveUser(obj);
//success message
}
return View(model);
}
I did not include all input tags but when I step through the code without the checkbox, all values are passed. I looked at other checkbox questions on SOF but they mostly use the #Html.Checkbox or #Html.CheckboxFor. I would like to just use input type="checkbox"
If we need to use <input> filed instead of #Html.CheckboxFor, we can use "checked=\"checked\"" syntax as in this code:
<input type="checkbox" id="Authorized" name="Authorized" value="true" #(Model.Authorized ? "checked=\"checked\"" : "") />
As has been hinted at in the comments the issue you're having is that you're not really creating your checkbox correctly:
Assuming your model has Authorized = true your mark-up would be:
<input type="checkbox" id="Authorized" name="Authorized" value="true" />
Similarly the false state would result in:
<input type="checkbox" id="Authorized" name="Authorized" value="false" />
But these aren't "checked" checkboxes - they're still "unchecked", and need the checked attribute setting:
<input type="checkbox" id="Authorized" name="Authorized" value="true" checked />
As Stephen points out - an unchecked checkbox will not send any data back to the server so that you don't get confused about which options where selected.
Finally, as has also been noted, your <label> element is for an non-existent field looking for inputAuthorize instead of Authorized.
All of these issues would be taken care of for you if you were to use the #Html.CheckboxFor and #Html.LabelFor helper classes.

Model binding two or more collections

Has anyone had any luck model binding two or more collections using the code posted by Phil Haack here: Model Binding To A List?
As an example, I have the below code.
public class Book {
public string Name { get; set; }
}
public class Author {
public string Name { get; set; }
}
public ActionResult Index(List<Book> books, List<Author> authors) {
// Will never model bind two collections.
}
The HTML that I have is:
<input type="hidden" name="books.index" value="1" />
<input type="text" name="books[1].Name" />
<input type="hidden" name="books.index" value="2" />
<input type="text" name="books[2].Name" />
<input type="hidden" name="authors.index" value="1" />
<input type="text" name="authors[1].Name" />
<input type="hidden" name="authors.index" value="1" />
<input type="text" name="authors[1].Name" />
The exception that I get is:
The parameters dictionary contains an invalid entry for parameter 'authors' for method 'System.Web.Mvc.ActionResult Index(System.Collections.Generic.List1[Book], System.Collections.Generic.List1[Author])' in 'HomeController'. The dictionary contains a value of type 'System.Collections.Generic.List1[Book]', but the parameter requires a value of type 'System.Collections.Generic.List1[Author]'. Parameter name: parameters
Am I doing something wrong or is this not supported by ASP.NET MVC?
Your problem is somewhere else, I was unable to reproduce. The following works fine for me:
Model:
public class Book
{
public string Name { get; set; }
}
public class Author
{
public string Name { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(List<Book> books, List<Author> authors)
{
return View();
}
}
View:
<% using (Html.BeginForm()) { %>
<input type="text" name="books[0].Name" value="book 1" />
<input type="text" name="books[1].Name" value="book 2" />
<input type="text" name="authors[0].Name" value="author 1" />
<input type="text" name="authors[1].Name" value="author 2" />
<input type="submit" value="OK" />
<% } %>
It successfully binds values back in the POST action.
UPDATE:
I confirm that this is a bug in ASP.NET MVC 3 RC2 which will be fixed in the RTM. As a workaround you could put the following in your Application_Start:
ModelMetadataProviders.Current = new DataAnnotationsModelMetadataProvider();

Resources