I trying to use remote validation for the first time, but am encountering problems with the parameters passed inot the remote validation method.
My model is as follows:
public class PerinatalWomanView : IPerinatalWoman
{
[Required(ErrorMessage = "The woman's postcode is required")]
[Display(Name = "Woman's postcode")]
[Remote("PostcodeCheck", "Validation", "Validation")]
[RegularExpression("^[a-zA-Z]{1,2}[0-9][0-9A-Za-z]{0,1} [0-9][A-Za-z]{2}$", ErrorMessage = "A valid postcode is required")]
public string Postcode { get; set; }
The view snippet is:
<div class="editor-label control-label">
#Html.LabelFor(m => m.perinatalWomanView.Postcode)
</div>
div class="editor-field controls">
#Html.EditorFor(m => m.perinatalWomanView.Postcode)
#Html.ValidationMessageFor(m => m.perinatalWomanView.Postcode)
</div>
and the validation controller is:
public class ValidationController : Controller
{
//
// GET: /Validation/Validation/
[HttpGet]
public JsonResult PostcodeCheck(string Postcode)
{
// postcode has already been checked for correct format
// now look it up to see if it exists
string mbrraceCommonCodeEntitiesConnectionString = ConfigurationManager.ConnectionStrings["MbrraceCommonCodeEntities"].ConnectionString;
if (PostcodeChecks.CheckPostcodeExists(mbrraceCommonCodeEntitiesConnectionString, Postcode))
{ return Json(true, JsonRequestBehavior.AllowGet); }
return Json("This postcode was not found in the database", JsonRequestBehavior.AllowGet);
}
When the controller is called the value of Postcode is null. The actual call - from Firebug - is:
http://localhost:57881/Validation/Validation /PostcodeCheck?perinatalWomanView.Postcode=OX4+1SU
How do I read the postcode string parameter correctly becuase it is clearly not null?
HELP!
You could have a view model like this:
public class AddressViewModel
{
public string Postcode { get; set; }
}
and then use specify the Prefix by decorating the parameter with the [Bind] attribute:
[HttpGet]
public ActionResult PostcodeCheck(
[Bind(Prefix = "perinatalWomanView")]AddressViewModel model
)
{
// use model.Postcode here ...
}
or if you don't want to use the Bind attribute have the following models:
public class MyViewModel
{
public AddressViewModel PerinatalWomanView { get; set; }
}
public class AddressViewModel
{
public string Postcode { get; set; }
}
and then have your controller action take the view model:
[HttpGet]
public ActionResult PostcodeCheck(MyViewModel model)
{
// use model.PerinatalWomanView.Postcode here ...
}
Related
I am creating a filter view to find records. This example on SO helps, but does not mention how handle the (Filtered) View.
The err below is because, the actions returns a List<ProductViewModel>, and it Errors/complains that the View is using a SearchViewModel, I need to this POST the searchmodel/variables, butGET back the list/results model
The model item passed into the dictionary is of type
'System.Collections.Generic.List`1[ViewModels.ProductVM]', but this
dictionary requires a model item of type 'ViewModels.SearchModel'.
Issue/Question: Since there are two models, the SearchViewModel passed to the controller & the ProductViewModel returned as a result, which model should be strongly typed to the view? and How can I create the view to handle both SearchModel & ProductModel If I stronglyType ProductVM, then I loose the submitform from the SearchVM.
I create the SearchView as the mainview, & the _ResultsPartialView as a partialView, is this wrong?
public ActionResult Index(SearchModel searchModel)
{
var filteredProdVMList = _Repository.GetFilteredProducts(searchModel);
return View(filteredProdVMList);
}
public class ProductVM
{
public int Id { get; set; }
public int Price { get; set; }
public string Name { get; set; }
// implicit const... blah.. removed
}
public class SearchModel
{
public int? Id { get; set; }
public int? PriceFrom { get; set; }
public int? PriceTo { get; set; }
public string Name { get; set; }
}
You need to modify your SearchModel to include a collection property for the products
public class SearchModel
{
public int? PriceFrom { get; set; }
public int? PriceTo { get; set; }
....
public IEnumerable<ProductVM> Products { get; set; } // add
}
then you return just SearchModel to your view
public ActionResult Filter(SearchModel filter)
{
filter.Products = _repository.GetFilteredProducts(filter);
return View(filter);
}
and your view will be
#model SearchModel
....
#using (Html.BeginForm("Filter", "yourControllerName", FormMethod.Get))
{
#Html.LabelFor(m => m.PriceFrom)
#Html.EditorFor(m => m.PriceFrom)
#Html.ValidationMessageFor(m => m.PriceFrom)
... // other form controls for properties you want to filter the results on
<input type="submit" value="Filter" />
}
#Html.Partial("_ResultsPartialView", Model.Products)
I am trying to create an Item that has an ItemType coming from another table. I am unable to get back the actual Type object from the Create page. This is the code I have tried:
Models:
public class ItemType {
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Item> Item{ get; set; }
}
public class Item {
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ItemType ItemType { get; set; }
}
In the ItemController, this is my create code:
public ActionResult Create() {
var itemTypeRepo = new ItemTypeRepository(context);
ViewBag.ItemTypes = new SelectList(itemTypeRepo.GetAll(), "ID", "Name");
return View();
}
[HttpPost]
public ActionResult Create(Item item) {
if (ModelState.IsValid) {
context.Items.Add(item);
context.SaveChanges();
return RedirectToAction("Index");
}
return View(item);
}
In my Create.cshtml view I have tried:
<div class="editor-field">
#Html.DropDownList("ItemType", String.Empty)
#Html.ValidationMessageFor(model => model.ItemType)
</div>
This returns no value at all and throws an error "The value 'X' is invalid." Where X is the ID of the ItemType I selected.
And
<div class="editor-field">
#Html.DropDownListFor(x => x.ItemType.Id, (SelectList)ViewBag.ItemType)
#Html.ValidationMessageFor(model => model.ItemType)
</div>
This creates a stub ItemType object with the correct ID but does not insert it into the database since the object is not fully loaded. If I look at ModelState object, I find that there is an error that the Name field is missing from ItemType object.
I also attempted to solve the problem using the second .cshtml code and adding this code:
public ActionResult Create(Item item) {
item.ItemType = context.ItemTypes.Find(item.ItemType.Id);
if (ModelState.IsValid)
This does not change the value of ModelState.IsValid from false even through it should.
What do I need to do to get this to work?
You should add a property ItemTypeId to your Item entity so that it acts as a foreign key.
public class Item
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public int ItemTypeId { get; set; }
[ForeignKey("ItemTypeId")]
public virtual ItemType ItemType { get; set; }
}
You can then use that property for the dropdownlist:
<div class="editor-field">
#Html.DropDownListFor(x => x.ItemTypeId, (SelectList)ViewBag.ItemType)
#Html.ValidationMessageFor(model => model.ItemType)
</div>
I hope someone can help with this one. I have three Model classes like this:
public class Provider
{
public Guid ProviderId { get; set; }
public string Name { get; set; }
public Guid LocationId { get; set; }
public virtual Location Location { get; set; }
}
public class Location
{
public Guid LocationId { get; set; }
public string NameOrCode { get; set; }
public string Description { get; set; }
public string StreetNumber { get; set; }
public string StreetAddress1 { get; set; }
public string StreetAddress2 { get; set; }
public string City { get; set; }
public int? StateId { get; set; }
public string Zip { get; set; }
public string ContactPhone { get; set; }
public virtual State State { get; set; }
}
public class State
{
public int StateId { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
}
As you can see, a Provider has a Location (separate class for reuse elsewhere), and a Location has a State (which is null until selected).
My Controller looks like this for my Create methods:
public class ProviderController : BaseController
{
private SetupContext db = new SetupContext();
// other CRUD methods ...
//
// GET: /Provider/Create
public ActionResult Create()
{
Location location = new Location()
{
LocationId = Guid.NewGuid(),
NameOrCode = Resources.BillingLocation,
Description = Resources.BillingLocationDescription
};
Provider provider = new Provider()
{
ProviderId = Guid.NewGuid(),
LocationId = location.LocationId,
Location = location
};
ViewBag.StateId = new SelectList(db.States, "StateId", "Name", provider.Location.StateId);
return View(provider);
}
//
// POST: /Provider/Create
[HttpPost]
public ActionResult Create(Provider provider)
{
if (ModelState.IsValid)
{
db.Locations.Add(provider.Location);
db.Providers.Add(provider);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.StateId = new SelectList(db.States, "StateId", "Name", provider.Location.StateId);
return View(provider);
}
// other CRUD methods ...
}
Finally, my View looks like this:
<div class="editor-label">
#Html.LabelFor(model => model.Location.StateId, #Resources.Location_State_Display_Name)
</div>
<div class="editor-field">
#Html.DropDownList("StateId", #Resources.ChooseFromSelectPrompt)
#Html.ValidationMessageFor(model => model.Location.StateId)
</div>
My problem is that the state the user selects in the DropDownList never gets set on my Model on the Create POST. I have similar code in my Edit View and the state is populated correctly in that View (that is, the state associated with an existing Provider.Location shows selected in the DropDownList for the user to edit if desire), but in both the Create and the Edit Views the selection made by the user is never registered in my Model (specifically the Provider.Location.StateId) coming in from the POST.
Looking at the HTML produced I see this:
<div class="editor-label">
<label for="Location_StateId">State/Territory</label>
</div>
<div class="editor-field">
<select id="StateId" name="StateId"><option value="">[Choose]</option>
<option value="1">Alabama</option>
<option value="2">Alaska</option>
<!-- more options ... -->
</select>
<span class="field-validation-valid" data-valmsg-for="Location.StateId" data-valmsg-replace="true"></span>
</div>
I suspect I need to somehow convey the Location.StateId relationship instead of just StateId as I see above but I can't figure out the correct syntax to do that. I've tried changing my ViewBag dynamic property to Location_StateId like this:
ViewBag.Location_StateId = new SelectList(db.States, "StateId", "Name", provider.Location.StateId);
And the DropDownList in my View like this:
#Html.DropDownList("Location_StateId", #Resources.ChooseFromSelectPrompt)
I figured then perhaps that notation would work because the label beside my DropDownList was rendered as:
<div class="editor-label">
<label for="Location_StateId">State/Territory</label>
</div>
This attempt did not work. Can you help me out?
Thanks in advance.
#Html.DropDownList("Location.StateId", #Resources.ChooseFromSelectPrompt)
Also the following line doesn't do anything useful:
ViewBag.StateId = new SelectList(db.States, "StateId", "Name", provider.Location.StateId);
You are assigning a SelectList to something that is supposed to be a scalar property. You probably wanted to pass the collection as ViewBag:
ViewBag.States = new SelectList(db.States, "StateId", "Name", provider.Location.StateId);
and then in the view:
#Html.DropDownList("Location.StateId", (SelectList)ViewBag.States)
I have a class User and then another Type UserSpecial with some special user properties.
I pass it in razor to the partial method class to create the UserSpecial form which expects an object of type User Special but i get an error.
#model User
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
#Html.Partial("../UserSpecial/_CreateOrEdit", Model.UserSpecial)
<p class="submit clear">
<input type="submit" value="Register" />
</p>
</fieldset>
}
</div>
Error i get -
The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies.User_AC9DED50C9495788046D6BFA3B90DDFC6AD2884157CF23C91FCB3B7A55F70B18', but this dictionary requires a model item of type 'UserSpecial'.
What am i doing wrong here?
From my controller i just pass the current User Object that i have stored in the session state.
Controller -
public ActionResult Register()
{
return View(userRepository.Current);
}
Here Current is of type "User"
Model -
public partial class User
{
public User()
{
}
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Sex { get; set; }
public System.DateTime CreateDate { get; set; }
public string Email { get; set; }
public string HomeTown { get; set; }
public short UserType { get; set; }
public virtual UserSpecial UserSpecial { get; set; }
}
Model Declaration for _CreateOrEdit is
#model UserSpecial
No idea what userRepository.Current is but it seems that it doesn't correctly/eagerly load the UserSpecial property. Why don't you use view models? Why are you passing domain entity models to your views? That's bad practice. You should define view models that contain only the data that's required by your view and then in your controller action map between your domain models and the corresponding view model which will be passed to the view.
The solution for this issue is pretty simple:
You should just use a wrapper class (view model) as Darin suggested.
So for example:
(entity domain model):
public class MyEntityModel
{
public int Id { get; set; }
public String Name { get; set; }
}
=> put it in a ViewModel (just a stupid wrapper) should result in this
public class MyViewModel
{
public MyEntityModel MyEntityModel { get; set; }
}
Now, in the view, u should be able to access the "name" property by doing this
<div>
The entity object's name is "#model.MyEntityModel.Name"
</div>
(notice you should not use #model.Name!)
I have a class called
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Country Country { get; set; }
}
public class Country
{
public int Id { get; set; }
public string Type { get; set; }
}
My MVC View Page is Strongly typed to Person and there is a dropdownlist which show the list of countries.
In My Controller Index
public ActionResult Index()
{
LoadCountryList();
return View(Person);
}
private void LoadCountryList()
{
IEnumerable<CountryList> countryList = CountryListService.GetCountryList();
ViewData["CountryList"] = new SelectList(country, "Id", "Type", 0);
}
Code in the html
<%: Html.DropDownListFor(model => model.Country.Id, (IEnumerable<SelectListItem>)ViewData["CountryList"], "--Select--")%>
When the page is submitted Create method is called in the controller
public ActionResult Create(Person person)
{
// person.Country.Id has the value
// person.Country.Type is null
}
I am getting only the Country Id from the object person in the Create Method. The Country Id is loaded inside the Person Object under Country.
Is there any way I can get both the Id and Type of the country when passed from the Page to the Controller?
I know I am passing Html.DropDownListFor(model => model.Country.Id .... from here.
Is there any Solution so that I get Id and Type in the controller.
Thanks
Passing it through the person object is not the best way to do it. Instead, assign an ID to your dropdown list like this:
<%: Html.DropDownListFor(
model => model.Country.Id,
(IEnumerable<SelectListItem>)ViewData["CountryList"], "--Select--")
new { id = "CountryID" }
%>
and then put that in as a parameter to your Create method:
public ActionResult Create(Person person, int CountryID)
{
var country = CountryListService.GetCountryList().Where(x => x.id == CountryID);
person.Country = country;
...
}
ASP .NET MVC will look for a control that has the same ID name as the parameter in the method call and pass it through.