I have a registration view in my web app. However, account registration would be unsuccessful and my drop-down menu would be outlined in red.
Here is my drop down code:
<div class="editor-label">
#Html.LabelFor(model => model.CompanyId, "Company")
</div>
<div class="editor-field">
#Html.DropDownList("Companies", "<Select Company>")
</div>
Here is my associated code in the view model:
[Display(Name = "Company")]
public int? CompanyId { get; set; }
public IEnumerable<SelectListItem> Companies { get; set; }
Here is my associated code in the controller before I return the view:
ViewBag.Companies = new SelectList(db.Companies, "CompanyId", "CompanyName");
As I debug, I find that ModelState.IsValid returns false, and therefore re-returns the view (and re-sets ViewBag.Companies in my case).
How do I complete a successful registration? I do fill out each required field within parameters. It is not required to select company. When I do not select a company, ModelState.IsValid returns true and runs through the code. However, I would like the user to have the option to associate with his company.
Thanks.
Why would you need setting ViewBag.Companies, when you've got the better approach - having select list into the model? No need to use ugly ViewBag
You should have something like this
ViewModel
public class RegisterViewModel
{
[Display(Name = "Company")]
public int? CompanyId { get; set; }
public IEnumerable<SelectListItem> Companies { get; set; }
}
Controller
[HttpGet]
public ActionResult Register()
{
RegisterViewModel viewModel = new RegisterViewModel();
viewModel.Companies = new SelectList(db.Companies, "CompanyId", "CompanyName");
return View(viewModel);
}
And in the view
<div class="editor-label">
#Html.LabelFor(model => model.CompanyId, "Company")
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.CompanyId, Model.Companies, "<Select Company>")
</div>
This will bind your CompanyId on server correctly.
Your model state will always be invalid for your dropdowns if your selected variable type is not a string. Change CompanyId to string. You can still use IEnumerable Companies {get;set;}
DropDownList is kind of weird in ASP.Net MVC3. It will not bind properly to an enumerable of SelectListItem. You need to store the bound, selected choice to a primitive in the model and the list of all options in a separate field.
<div class="editor-label">
#Html.LabelFor(model => model.CompanyId, "Company")
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.CompanyId, new SelectList(Model.Companies))
</div>
Then, in your model, change the IEnumerable of SelectListItems to an IEnumerable of strings.
[Display(Name = "Company")]
public string CompanyId { get; set; }
public IEnumerable<string> Companies { get; set; }
Finally, in your controller,
ViewBag.Companies = db.Companies;
Just as a sidenote, I suggest making your IEnumerable an IList instead. A dropdown menu definitely cares about the order in which the data is presented, so your model should reflect that.
Related
I have the follow class which I'm trying to wire up to the radio buttons
public class ProductFilter
{
public bool Tubs { get; set; }
public bool Packs { get; set; }
}
And I use this on the view as so
<div class="row col-lg-12" id="filters">
<div class="col-lg-4 text-right">
#Html.RadioButtonFor(model => model.Filter.Tubs, true) Tubs
</div>
<div class="col-lg-4"></div>
<div class="col-lg-4 text-left">
#Html.RadioButtonFor(model => model.Filter.Packs, true) Packs
</div>
</div>
Now when the page loads, and I select say tubs it posts back to the controller and I'm able to filter, when the page reloads and I select packs it posts back but the values for the both are the same, I would expect tubs to be false because I have selected packs and vice versa, can some one point out what I'm doing wrong?
It appears you want to filter based on either a value of "Tubs" or "Packs", in which case you model is wrong. You need a property that posts back either of those strings, for example
public string Filter { get; set; }
public List<string> FilterList { get; set; }
and in the controller
model.FilterList = new List<string>() { "Tubs", "Packs" };
model.Filter = "Tubs"; // set default
and in the view
#foreach(var option in Model.FilterList)
{
<label>
#Html.DropDownListFor(m => m.Filter, option, new { id = option })
<span>#option</span>
</label>
}
which will generate 2 radio button with name="Filter" and values of value="Tubs" and value="Packs", and allow selection of only one.
Alternatively you could use an enum for the filter values.
I wanna Add new multi records to databese,
and I design View have multi form to filed data and insert it.
My View have:
--item 1
#Html.EditorFor(modelitem => item.Description)...
.
.
.
--item 2
#Html.EditorFor(modelitem => item.Description)...
I use
[HttpPost]
public ActionResult Edit(FormCollection c)
{
var desc = c.GetValue("item.Description");
}
I use it do get value, but I wanna separate value of desc.
I use .Split(','); but if desc has value :
"test value, test desc"
So I can't use it.
So Anyone tell me. how to loop item to insert it
You can also use -
Request.Form["Your property Name"]
WORKING CODE:
Model -
public class MyClass
{
public string MyName { get; set; }
}
View -
#using (Html.BeginForm("SubmitData","Post", FormMethod.Post))
{
<div class="form-horizontal">
<h4>MyClass</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.MyName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.MyName)
#Html.ValidationMessageFor(model => model.MyName)
</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>
</div>
}
On POST, you can access it like this -
[HttpPost]
public ActionResult SubmitData(MyClass c)
{
var name = Request.Form["MyName"];
return View();
}
We will have the input value in the name variable. Check below image.
Also in the above code I showed how to do model binding too. If you use variable 'c', that will also have value from UI. Check below image.
You could prefix the id's of the fields so that you can retrieve the two separate fields;
#Html.TextBoxFor(x => x.SomeProperty, new { #id = "item_1_description" });
And that would allow you to get that specific value from the FormCollection;
string description = c.GetValue("item_1_description");
However, it would be cleaner if you could take advantage of strongly-typing your views. In your position, I would create a ViewModel that represents both of your objects. Since I don't know what your data types are, I'll use the example of a Person, which looks like this;
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
To to add two people in one form, you would create a `ViewModel' that represents what the form would look like - a flattened version of two people;
public class MuliplePeopleViewModel
{
public string Person1Name { get; set; }
public string Person2Name { get; set; }
}
Which would generate a view with two textboxes;
#model MuliplePeopleViewModel
#Html.EditorFor(x => x.Person1Name);
#Html.EditorFor(x => x.Person2Name);
Now in your Controller you can replace your use of FormCollection with our new ViewModel, that will automatically bind the values of the TextBox's to the relevant properties;
[HttpPost]
public ActionResult Edit(MuliplePeopleViewModel viewModel)
{
string person1Name = viewModel.Person1Name;
}
Food for thought: I'm not entirely sure the DefaultModelBinder will bind an unflattened version of the ViewModel, such as;
public class MuliplePeopleViewModel
{
public Person Person1 { get; set; }
public Person Person2 { get; set; }
}
But perhaps you could try it!
EDIT
Following comments from the author, you could also create a ViewModel that contains an ICollection<Person>;
public class MuliplePeopleViewModel
{
public ICollection<Person> People { get; set; }
}
And in your view you can loop through the collection and display fields for each;
#model MuliplePeopleViewModel
#foreach (Person person in Model.People)
{
#Html.EditorFor(x => person.Name);
}
Now, the DefaultModelBinder should now give you a list of people to use in your action. However, if not, you may need to write a custom model binder.
More food for thought: You might be able to utilise EditorTemplates to simplify your view.
Let me know if I can help further.
Matt
Try this:
[HttpPost]
public ActionResult Edit(FormCollection c, string[] description)
{
}
So you will have the values in an array.
Overview:
I'm trying to use a ViewModel that has a property that is the model class that I'm trying to edit. I've seen the edit form work using the MVC scaffolding edit forms when editing a model directly, however I am trying to use a ViewModel that contains the model being edited. Everything works except for the saving of a field that's displayed in a DropDownList.
Explanation:
I've attempted to use the scaffolding features of MVC 3 to create an edit form for a model.
In the MVC Music Store tutorial, this is done for the Edit page of an Album, in the StoreManagerController.
Within that page, they have two drop downs for Genre and Artist. Each looks similar to this in the view:-
<div class="editor-label">
#Html.LabelFor(model => model.GenreId, "Genre")
</div>
<div class="editor-field">
#Html.DropDownList("GenreId", String.Empty)
#Html.ValidationMessageFor(model => model.GenreId)
</div>
As far as I can tell, these have their options filled out in the controller using the ViewBag.
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);
Working with the Model directly
In my code, I managed to do the same with an object that's being saved to the DB through Entity Framework.
Model
public class Season
{
public int SeasonId { get; set; }
public int ClubId { get; set; }
public Club Club { get; set; }
}
Code in Controller
ViewBag.ClubId = new SelectList(clubs, "ClubId", "Name", season.ClubId);
View
<div class="editor-label">
#Html.LabelFor(model => model.ClubId, "Club")
</div>
<div class="editor-field">
#Html.DropDownList("ClubId", String.Empty)
#Html.ValidationMessageFor(model => model.ClubId)
</div>
This works fine.
Working with the View Model
However now I have realised that the page needs more text displayed than what is available in the model I'm editing.
I was hoping to create a special View Model, with the edited model (season) and the extra text I want to display.
ViewModel
public class EditSeasonViewModel
{
public string PlayerName {get; set;}
public string SummaryText {get; set;}
public int PlayerId {get; set;}
public Season season {get; set;}
}
I did this, changed the controller to have the HttpGet and HttpPost methods use the new ViewModel, changed the View to accept the new ViewModel, and changed the all 'EditorFor' methods in the view to use model.season.MyProperty.
Code in Controller
ViewBag.ClubId = new SelectList(clubs, "ClubId", "Name", seasonVM.season.ClubId);
Code in View
<div class="editor-label">
#Html.LabelFor(model => model.season.ClubId, "Club")
</div>
<div class="editor-field">
#Html.DropDownList("ClubId", String.Empty)
#Html.ValidationMessageFor(model => model.season.ClubId)
</div>
When debugging the HttpPost method, all of the values for season properly exist, except for the ClubId value which should come from the DropDropList.
I haven't changed the DropDownList in the View at all from the way it was when we were using the Model directly.
Question:
My question is, what do I need to change to get the ClubId to be saved properly when using this new EditSeasonViewModel?
Also, how does the ViewBag.ClubId in the HttpGet method in the controller match to the DropDownList in the View, and then have it's value passed back to the HttpPost method?
It's your DropDownList declaration that's incorrect. Try this instead:
#Html.DropDownListFor(m => m.season.ClubId, ViewBag.ClubId)
But really, you should put that select list in your model:
public SelectList Clubs { get; set; }
Then populate it in your controller:
Model.Clubs = new SelectList(clubs, "ClubId", "Name", season.ClubId);
Then you can do:
#Html.DropDownListFor(m => m.season.ClubId, Model.Clubs)
Avoid using dynamic stuff like ViewBag/ViewData to transfer data from action methods to views. Switch to the strongly typed approach.
Update your Viewmodel to have 2 more properties. one to hold a collection of available clubs and one to hold the selected club.
public class EditSeasonViewModel
{
public List<SelectListItem> Clubs { set;get;}
public int SelectedClub { set;get;}
public string PlayerName {get; set;}
public string SummaryText {get; set;}
public int PlayerId {get; set;}
public Season season {get; set;}
public EditSeasonViewModel()
{
Clubs=new List<SelectListItem>();
}
}
Now in your GET action, Get the clubs and load it to the Clubs Property.
public ActionResult create(int id)
{
var vm=new EditSeasonViewModel();
vm.Clubs=GetListOfSelectListItemFromClubsFromSomeWhere();
return View(vm);
}
assuming GetListOfSelectListItemFromClubsFromSomeWhere is a method which returns a list of SelectListItem for your Clubs
public List<SelectListItem> GetListOfSelectListItemFromClubsFromSomeWhere()
{
// to do : return List<SelectListItem> with Value and Text(ClubId Id & Name)
}
and in your view, use the Html.DropDownListFor helper method
#model EditSeasonViewModel
#using(Html.Beginform())
{
#Html.DropdownlistFor(x=>x.SelectedClub,
new SelectList(Model.Clubs,"Value","Text"),"select")
<input type="submit" />
}
When this form is being posted, you will get the selected club's id in the SelectedClub property of your posted model.
[HttpPost]
public ACtionResult Create(EditSeasonViewModel model)
{
if(ModelState.IsValid)
{
int clubId= model.SelectedClub;
//to do : save and redirect (PRG pattern)
}
vm.Clubs=GetListOfSelectListItemFromClubsFromSomeWhere();
return View(model);
}
Please be sure that in your edit/creat action controller, the property is correctly binded:
public async Task<ActionResult> Edit([Bind(Include = "SeasonId,ClubId, otherproperties"]){
// code ...
}
I'm trying to query List from database which will be shown in dropdownlistfor in view, and chosen result will be post.
The problem is I'm using two models in view I tried more options
I'm lost with this, I don't know how to post it. Data are shown in listbox without problem. I'm getting this error when I try to post:
"There is no ViewData item of type 'IEnumerable' that
has the key 'Item2.idcity'." System.Exception
{System.InvalidOperationException}
CityModel
public class CityModel
{
public int idcity { get; set; }
[Required]
public string cityName { get; set; }
public IEnumerable<CityModel> citys { get; set; }
}
HospitalModel
public class HospitalShowModels
{
[Required]
public string hospitalName { get; set; }
[Required]
public string cityName { get; set; }
}
HospitalControler.Create()
public ActionResult Create()
{
ViewBag.cityModel = new SelectList(DataAccess.DAL.showCity(), "idcity", "cityName");
var tuple = new Tuple<DataAccess.HospitalShowModels, DataAccess.CityModel>(new DataAccess.HospitalShowModels(), new DataAccess.CityModel());
return View(tuple);
}
[HttpPost]
public ActionResult Create(DataAccess.HospitalShowModels model, DataAccess.CityModel model1)
{
if (ModelState.IsValid) {
DataAccess.DAL.insertHospital(model.hospitalName, model1.cityName);
}else{
ModelState.AddModelError("","Invalid options");
}
return View();
}
View.Create
#model Tuple<ProjektZaja.DataAccess.HospitalShowModels,ProjektZaja.DataAccess.CityModel>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Create Hospital</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Item1.hospitalName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item1.hospitalName)
#Html.ValidationMessageFor(model => model.Item1.hospitalName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Item1.cityName)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => Model.Item2.idcity,(IEnumerable<SelectListItem>)ViewBag.cityModel)
#Html.ValidationMessageFor(model1 => Model.Item2.idcity)
You can't strongly type a view to multiple models. You need to create a view model which will simply be a composite class containing each of the other two classes, and strongly type the view to that view model.
public class CreateViewModel
{
public CityModel CityModel {get; set;}
public HospitalShowModel HospitalShowModel {get; set;}
}
Then strongly type your view to the view model
# model Full.Path.To.CreateViewModel
And access the models properties appropriately
Model.CityModel.cityName //etcetera...
And bind it in the post method
[HttpPost]
public ActionResult Create(CreateViewModel viewModel)
{
//...
The model type in your view should match the model type in the post action. Therefore it should be a Tuple (though I personally wouldn't use that) or a new model type with 2 properties (one for city, one for hospital)
How do i get Entity Frameworks foreign keys to pick up when I generate the view with the add view dialog.
My Models are like
public class System
{
#region Properties
public int SystemId { get; set; }
public string SystemName { get; set; }
#endregion
}
public class Module
{
#region Properties
public int ModuleId { get; set; }
//[Required]
[Display(Name="Module Name")]
public string ModuleName { get; set; }
[Display(Name="Date Added")]
public DateTime DateAdded { get; set; }
//[ForeignKey("CurrentSystem")]
public int SystemId { get; set; }
//[ForeignKey()]
//[ForeignKey("SystemId")]
public System System { get; set; }
#endregion
}
When i click on the Controller, then Add View, the modal opens. I select all the details that is needed and then the following is generated ( I did not include the entire view).
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Module</legend>
<div class="editor-label">
#Html.LabelFor(model => model.ModuleName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ModuleName)
#Html.ValidationMessageFor(model => model.ModuleName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DateAdded)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DateAdded)
#Html.ValidationMessageFor(model => model.DateAdded)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.SystemId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SystemId)
#Html.ValidationMessageFor(model => model.SystemId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
I want the SystemId to be a dropdown and not a text field. How do i do this ?
Are you sure you created a class derived from dbContext with a property of type DBSet<System> and a property of type DBSet<module> ?
Provided you have, and you select a controller with the option "read and write actions with entity framework" and select both your class Module) and your context in the drop downs below that, MVC should generate the correct code view and controller code to display a combo for the system.
It worked for me in MVC4, at least. Remember to generate your project before trying to add a controller. I think MVc uses reflection so it needs an up-to-date assembly...
Use a view-model. MVC uses the data annotations to figure out how to display the properties. If you want your view to behave in a different manner than your model, you need to map your model to a view-model to handle the extra logic (ie a drop down where an int exists). Then generate your view from the view-model class.
The view-model adds a layer to deal with the seperations of concerns here. You want your view to be different than your model will allow so add a view model class that will take the model data and display it in a way that you want.