I have an asp.NET mvc 3 with razor website. I have a web page that is displaying a list of data from a database in a form such as:
<input type="text" name="blah1" value="blah" />
<input type="text" name="blah2" value="blahblah" />
<input type="text" name="blah3" value="blahblah" />
Each row above is assoicated with a primary key. When the user hits submit and posts back the FormCollection to the controller.. how do I go about getting the primary keys of each blah? Do I add a hidden field for each row that contains the primary key of that row? If so, how do I know which blah it is associated with as the FormCollection is just a dictionary?
I would recommend you using a view model:
public class MyViewModel
{
public string Id { get; set; }
public string Text { get; set; }
}
and then in your controller action you would send a list of those models to the view:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new[]
{
new MyViewModel { Id = "1", Text = "blah" },
new MyViewModel { Id = "2", Text = "blahblah" },
new MyViewModel { Id = "3", Text = "blahblah" },
};
return View(model);
}
[HttpPost]
public ActionResult Index(IEnumerable<MyViewModel> model)
{
// Here you will get a collection of id and text for each item
...
}
}
and the view you could use hidden fields for the id and a textbox for the value:
#model IEnumerable<MyViewModel>
#using (Html.BeginForm())
{
#Html.EditorForModel()
<input type="submit" value="OK" />
}
and the corresponding editor template (~/Views/Shared/EditorTemplates/MyViewModel.cshtml):
#model MyViewModel
#Html.HiddenFor(x => x.Id)
#Html.TextBoxFor(x => x.Text)
Related
Actually I'm the beginner in the MVC. And simple question:
For example I have ViewModel for the page of Category:
public class CategoryViewModel
{
public int ProductId {get;set;}
public int CategoryId {get;set;}
public string ProductName {get;set;}
public string CategoryName {get;set;}
}
In the controller I just pass CategoryId and CategoryName to the view:
public ActionResult Index()
{
CategoryViewModel categoryViewModel = new CategoryViewModel();
categoryViewModel.CategoryId = catId; \\Get from DB
categoryViewModel.CategoryName = catName; \\Get from DB
return View("Category", categoryViewModel);
}
Then on the View I need to add Product to this Category:
<form action=#Url.Action("AddProduct", "Category") method="POST" enctype = "multipart/form-data">
<textarea name ="ProductName"></textarea>
<input type="submit" value="Add"/>
</form>
And in the controller for AddProduct:
[HttPost]
public ActionResult AddPost(CategoryViewModel categoryViewModel)
{
var productName = categoryViewModel.ProductName;
var categoryId = ?
ProductRepository.AddProductToCategory(productName, categoryId);
return new EmptyResult();
}
Question: How to get the CategoryId? Or maybe there is another approach?
Change your view to include a control for the CategoryId property
#model CategoryViewModel
#using(Html.BeginForm("AddProduct", "Category"))
{
#Html.HiddenFor(m => m.CategoryId)
#Html.TextAreaFor(m => m.ProductName)
<input type="submit" value="Add" />
}
Note, always use strongly types html helpers to generate your html.
Thx for Stephen Muecke
Also you can pass id from (form self) and another properties you want, but you must definition in input action method.
#model CategoryViewModel
#using (Html.BeginForm("AddProduct", "Category", new { id = Model.CategoryId }, FormMethod.Post, new { }))
{
#Html.TextAreaFor(m => m.ProductName)
<input type="submit" value="Add" />
}
Action method :
[HttPost]
public ActionResult AddPost(CategoryViewModel categoryViewModel,int id)
{
var productName = categoryViewModel.ProductName;
var categoryId = id
ProductRepository.AddProductToCategory(productName, categoryId);
return new EmptyResult();
}
i hope this help you.
How can I prepare a model for Dropdownlist static values (not retrieved from database) like enum or list in MVC Model so that it could be used many times in a project? I would appreciate if you can give a good article? Thanks.
As always you could start with a view model:
public class MyViewModel
{
public string SelectedValue { get; set; }
public IEnumerable<SelectListItem> Values
{
get
{
return new[]
{
new SelectListItem { Value = "1", Text = "Item 1" },
new SelectListItem { Value = "2", Text = "Item 2" },
new SelectListItem { Value = "3", Text = "Item 3" },
};
}
}
}
then a controller:
public ActionResult Index()
{
var model = new MyViewModel();
return View(model);
}
and finally a view:
#model MyViewModel
#Html.DropDownListFor(x => x.SelectedValue, Model.Values)
For enums you could use some of the many posts out there illustrating custom helpers. Here's one blog post illustrating such helper: http://blogs.msdn.com/b/stuartleeks/archive/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums.aspx
Finally I have found the solution by describing the parameters as hidden input. I am not sure if there is a more elegant method in order to pass the parameters from View to Controller. Thank you so much for your good sample. I also marked as helpful all of your replies. Here is my final code for those who might encounter a similar problem:
ApplicantViewModel:
public class ApplicantViewModel
{
public IEnumerable<Applicant> Applicants { get; set; }
//Codes for Dropdownlist values
public string SelectedValue { get; set; }
public IEnumerable<SelectListItem> Values
{
get
{
return new[]
{
new SelectListItem { Value = "pdf", Text = "Pdf" },
new SelectListItem { Value = "excel", Text = "Excel" },
new SelectListItem { Value = "word", Text = "Word" }
};
}
}
}
ApplicantController:
public ViewResult Reporting()
{
var model = new ApplicantViewModel();
return View(model);
}
public ActionResult RenderReport(string SelectedValue, string name, string fileName, string dataSource, string table, string filter)
{
//Codes for rendering report
...
}
Reporting.cshtml:
#model MyProject.Models.ApplicantViewModel
#using (Html.BeginForm("RenderReport", "Applicant", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
<div>
#Html.DropDownListFor(model => model.SelectedValue, Model.Values, "-- select an option --")
<input type="hidden" name="name" value="Report1"/>
<input type="hidden" name="fileName" value="image rapor"/>
<input type="hidden" name="dataSource" value="ApplicantDataset"/>
<input type="hidden" name="table" value="ApplicantsView"/>
<input type="hidden" name="filter" value="David"/>
<input type="submit" value="submit" />
</div>
}
Im pretty new to MVC. Im trying to populate a drop downlist with currencies retrieved from database. What am I doing wrong?
#model IEnumerable<DSABankSolution.Models.ExchangeRates>
#{
ViewBag.Title = "Exchange Rates";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<br /> <br />
<input type="text" size="5" value="1" />
#Html.DropDownList("currency", Model.Select(p => new SelectListItem{ Text = p.Name, Value = p.ID}))
to
#Html.DropDownList("currency", Model.Select(p => new SelectListItem { Text = p.Name, Value = p.ID }));
<br /> <br /> <input type="submit" name="Convert" />
ExchangeRate Model:
public class ExchangeRates
{
public string ID { get; set; }
public string Name { get; set; }
}
ExchangeRate Controller:
public ActionResult Index()
{
IEnumerable<CommonLayer.Currency> currency = CurrencyRepository.Instance.getAllCurrencies().ToList();
//ViewBag.CurrencyID = new SelectList(currency, "ID");
//ViewBag.Currency = new SelectList(currency, "Name");
return View(currency);
}
Currency Repository:
public List<CommonLayer.Currency> getAllCurrencies()
{
var query = from curr
in this.Entity.Currencies
select curr;
return query.ToList();
}
Error I am getting:
The model item passed into the dictionary is of type
'System.Collections.Generic.List1[CommonLayer.Currency]', but this
dictionary requires a model item of type
'System.Collections.Generic.IEnumerable1[DSABankSolution.Models.ExchangeRates]'.
Thanks!
The error says it all. You are returning a collection of Currency as shown by this code
IEnumerable<CommonLayer.Currency> currency
and yet your view expect as a collection of ExchangeRates
#model IEnumerable<DSABankSolution.Models.ExchangeRates>
so you either change the declaration in your view to
#model IEnumerable<CommonLayer.Currency>
or return a list of ExchangeRates from your controller method
Your view expects a strongly typed model of type
IEnumerable<DSABankSolution.Models.ExchangeRates>
However,you are passing
IEnumerable<CommonLayer.Currency>
back to view.
I have the following models:
class A
{
// ...some properties
public B InnerField { get; set; }
}
and
class B
{
public int Id { get; set; }
// ..other properties
}
and a page that has a model Class A and inside the page I have a partial view bound to Class B inside a form.
The value of the Id (in the partial view) is set correctly to the model's Id value (different from 0) but when I submit the page the model has the Id value 0. The Id value is not modified in the component or elsewhere.
Page
...other parts of main page
<%using (Html.BeginForm("ModifyHotel", "Hotel",
FormMethod.Post, new { enctype = "multipart/form-data"}))
{%>
<% Html.RenderPartial("~/Views/Shared/ModifyBaseItem.ascx",
new ModifyItemRequestBaseView() { ItemId = Model.Item.Id });%>
<%}%>
...other parts of main page
Partial View
...other parts of partial view
<br/>
Add Photo: <%:Html.FileBoxFor(x => x.PhotoFile, null)%>
<br/>
Add Video: <%:Html.FileBoxFor(x => x.VideoFile, null)%>
<br/>
<input type="submit" value="Submit changes" />
...other parts of partial view
What can I do to keep the value of the inner model when the post is made?
Thanks,
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
A model = new A() { InnerField = new B() { Id = 5 }};
return View(model);
}
[HttpPost]
public ActionResult Index(B model)
{
//on postback the model should have the value 5 here
return View();
}
}
View:
#model MvcApplication11.Models.A
#using (Html.BeginForm())
{
#Html.Partial("_IndexForm", Model.InnerField)
<input type="submit" />
}
Partial:
#model MvcApplication11.Models.B
#Html.EditorFor(m => m.Id)
Having trouble creating a list of radio buttons that are grouped together, in MVC 3 specifically, but this also applies to MVC 2.
The problem arises when radio buttons are generated using Html helpers and the model is part of an array.
Here is the cut down version of my code.
public class CollectionOfStuff {
public MVCModel[] Things { get; set }
}
/*This model is larger and represents a Person*/
public class MVCModel {
[UIHint("Hidden")]
public string Id { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
/*Assigned to new CollectionOfStuff property Things*/
var items = new[] {
new MVCModel() { Id="0" Name = "Name here" }, new MVCModel() { Id="1" Name = "Name there" }
}
My parent view
#model CollectionOfStuff
#for (int i = 0; i < Model.Things.Length; i++) {
#Html.EditorFor(m => m.Things[i]);
}
My view rendering individual MVCModel objects
#Model MVCModel
#{
var attr = new {
Checked = Model.IsSelected ? "checked=checked" : ""
};
}
#Html.RadioButtonFor(model => model, Model.Id, attr)
Produces this output:
<input type="radio" value="0" name="MVCModel[0]" id="MVCModel_0_" data-val-required="You need to choose" data-val="true" />
<input type="radio" value="1" name="MVCModel[1]" id="MVCModel_1_" data-val-required="You need to choose" data-val="true" />
The radio buttons are not grouped, however it has the obvious advantage of writing out the meta data for validation.
The other way is by calling:
#Html.RadioButton(name: "GroupName", value: Model.Id, isChecked: Model.IsSelected)
Produces:
<input type="radio" value="0" name="MVCModel[0].GroupName" id="MVCModel_0__GroupName">
<input type="radio" value="1" name="MVCModel[1].GroupName" id="MVCModel_1__GroupName">
Again, this doesn't produce the desired result. It's also missing the validation meta data.
Another other option is creating a custom template, but the problem with this approach is that all the meta data required for validation is not present.
Any ideas on how I can create grouped radio buttons or obtain meta data so I can create a template myself?
You haven't shown how does your view model look like but you could group them by some property. So let's take an example:
public class MyViewModel
{
[Required]
public string SomeProperty { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
View:
#model AppName.Models.MyViewModel
#using (Html.BeginForm())
{
<div>A: #Html.RadioButtonFor(x => x.SomeProperty, "a")</div>
<div>B: #Html.RadioButtonFor(x => x.SomeProperty, "b")</div>
#Html.ValidationMessageFor(x => x.SomeProperty)
<input type="submit" value="OK" />
}
Now if you want to preselect some radio simply set the property of the view model to the corresponding value of the radio instead of writing some ugly C# code in your views:
public ActionResult Index()
{
var model = new MyViewModel
{
SomeProperty = "a" // select the first radio
};
return View(model);
}
Obviously this technique works with any simple property type (not only strings) and with any number of radio buttons that could be associated to this property.