I have a generic list method that returns a CategoryID and CategoryName.
I have spent enough time researching and cant seem to put it together. I very new at MVC.
Here is my DropdownList Method in a repository. I get back the data... So far so good.
public List<DropdownList> GetDDl()
{
return catDDL;
}
Here is my CONTROLLER CODE(attempt at it)
IEnumerable<SelectListItem> liCat =
userRepository.Getddl().Select(c => new SelectListItem
{
Value = c.DropDownID.ToString(),
Text = c.DropDownText
}
ViewBag.catItems = new SelecList(liCat,"Value","Text");
Here is my VIEW
#Html.Dropdownlist("catItems","Select Category)
Try to avoid dynamic stuff like ViewBag and ViewData. Use strongly typed views.
ViewModel is just a POCO class which we will use to transfer data between your view and the action method. It will be specific to the view.
ex : if you want to create a view which creates a product. So create a viewmodel like this
public class Product
{
public string Name { set;get;}
public IEnumerable<SelectListItem> Categories{ get; set; }
public string SelectedCategoryId { get; set; }
//Other Properties as needed
}
now in your GET action method, you create an object of this view model and initialize the values and send to the view.
public ActionResult Create()
{
var vm=new Product();
vm.Categories=userRepository.Getddl().
Select(c => new SelectListItem
{
Value = c.DropDownID.ToString(),
Text = c.DropDownText
});
return View(vm);
}
Now make your view strongly typed to our Product class and use the Html.DropDownListFor helper method.
#model PersonsProduct
#using (Html.BeginForm())
{
#Html.DropDownListFor(x => x.SelectedCategoryId,
new SelectList(Model.Categories,"Value","Text"), "Select")
<input type="submit" value="save" />
}
Now in your HttpPost , you can get the form values like this
[HttpPost]
public ActionResult Create(Product model)
{
if(ModelState.IsValid)
{
//check model.SelectedCategoryId
//save and redirect
}
//to do :reload the dropdown again.
return view(model);
}
Should just be:
Controller:
IEnumerable<SelectListItem> liCat = userRepository.Getddl().Select(c => new SelectListItem
{
Value = c.DropDownID.ToString(),
Text = c.DropDownText
}
ViewBag.catItems = liCat
View:
#Html.Dropdownlist("catItems", ViewBag.catItems)
Related
I have a form that wanna to select category and tag from drop down list and bind it to a post , this is my ViewModel:
public class PostViewModel
{
public IList<Category> Category { get; set; }
public IList<Tag> Tag { get; set; }
}
and this is my get action :
public ActionResult Add()
{
ViewBag.CategoryList = new SelectList(_categoryRepository.GetAllCategory());
ViewBag.TagList = new SelectList(_tagRepository.GetAllTag());
return View();
}
now how can I get the Id dropdownlst to send it to the Post action?? :
<div>
#Html.LabelFor(post => post.Category)
#Html.DropDownListFor ????
#Html.ValidationMessageFor(post => post.Category)
</div>
I tried this one it it didn't work
<div>
#Html.LabelFor(post => post.Category)
#Html.DropDownListFor(post => post.Category, ViewBag.CategoryList as SelectList, "--- Select Category ---")
#Html.ValidationMessageFor(post => post.Category)
</div>
please give me a solution about this ,thanks
Try to avoid dynamic stuff like ViewBag and ViewData. Use strongly typed views.
ViewModel is just a POCO class which we will use to transfer data between your view and the action method. It will be specific to the view.
You have a viewmodel but you are not using it properly. Add 2 more properties to your viewmodel for getting the selected item from the dropdown. Also i changed the name of your proprties to pluralized for (Categories ,Tags) because they are for storing a collection.
public class PostViewModel
{
public List<SelectListItem> Categories{ get; set; }
public List<SelectListItem> Tags { get; set; }
public int SelectedCategory { set;get;}
public int SelectedTag { set;get;}
}
Now in your GET Action method, create an object of your view model and set the collection properties and then send that object to your view using View method.
public ActionResult Add()
{
var vm=new PostViewModel();
vm.Categories= GetAllCategories();
vm.Tags= GetAllTags();
return View(vm);
}
Assuming GetAllCategories and GetAllTags are 2 methods which returns a collection of SelectListItem for categories and tags.
public List<SelectListItem> GetAllCategories()
{
List<SelectListItem> categoryList=new List<SelectListItem>();
categoryList.Add(new SelectListItem { Text = "Sample", Value = "1" });
// TO DO : Read from your dB and fill here instead of hardcoding
return categoryList;
}
and in your view,
#model PostViewModel
#using(Html.BeginForm())
{
#Html.DropDownListFor(x => x.SelectedCategory,
new SelectList(Model.Categories,"Value","Text"), "Select")
#Html.DropDownListFor(x => x.SelectedTag,
new SelectList(Model.Tags,"Value","Text"), "Select")
<input type="submit" value="save" />
}
And in your HttpPost action method, you can get the selected items in the 2 properties we added
[HttpPost]
public ActionResult Add(PostViewModel model)
{
if(ModelState.IsValid)
{
//check model.SelectedCategory and model.SelectedTag
//save and redirect
}
//to do :reload the dropdown again.
return View(model);
}
you were close:
public class PostViewModel
{
public int CategoryId { get; set; } // <-- Altered
public int TagId { get; set; } // <-- Altered
}
<div>
#Html.LabelFor(post => post.Category)
#Html.DropDownListFor(post => post.CategoryId,
ViewBag.CategoryList as IEnumerable<SelectListItem>,
"--- Select Category ---")
#Html.ValidationMessageFor(post => post.Category)
</div>
I want to add another dropdownlist. The below code works for one dropdown, but how would I add one for Categories?
public ActionResult Create()
{
var ddl = new Users();
ddl.DropDowns = userRepository.Getddl("Departments").Select(c => new SelectListItem
{
Value = c.DropdownID.ToString(),
Text = c.DropdownText
});
ViewData["ListofProfiles"] = new SelectList(ListofProfiles, "Value", "Text");
return View(ddl);
}
Try to avoid the ViewData approach.Switch to Strongly typed way of doing this. Add another property to your View Model to carry one more dropdown items
public class User
{
public int SelectedCountry { set;get;}
public int SelectedProfile { set;get;}
public List<SelectListItem> Countries {set;get;}
public List<SelectListItem> Profiles {set;get;}
public User()
{
Countries =new List<SelectListItem>();
Profiles =new List<SelectListItem>();
}
}
Now set the collection in your GET action
public ActionResult Create()
{
var vm=new User();
vm.Countries=GetCountryItems();
vm.Profiles=GetProfileItems();
return View(vm);
}
Where GetCountryItems and GetProfileItems are 2 methods which returns a list of SelectListItem objects for countries and Profiles from db.
Do not make your controllers FAT. Just keep it simple and clean. Move away your code which fetch data from repository to a different layer. Easy to read and maintain :)
And in your strongly typed view,
#mode User
#using(Html.BeginForm())
{
#Html.DropDownListFor(m => m.SelectedCountry,
new SelectList(Model.Countries, "Value", "Text"), "Select")
#Html.DropDownListFor(m => m.SelectedProfile,
new SelectList(Model.Profiles, "Value", "Text"), "Select")
<input type="submit" />
}
Edit: I've changed my question and code to clarify my question better
I've got this (strongly typed view) that does use the values provided in the controller for that specific model
I want to add something to a Model from another model, after posting back from my httpPost action nothing happens...
Thanks in advance!
--------------------------------------other code to clarify my question a bit more----
public class Address
{
public int Id { get; set;}
public String Name { get; set;}
}
public class OtherAddress
{
public int Id { get; set;}
public String Name { get; set;}
public String City { get; set;}
}
public class MasterModel
{
public Address Address { get; set;}
public List<OtherAddress> OtherAddressess { get; set;}
}
public ActionResult Create()
{
MasterModel Model = new MasterModel();
Model.Person = new Person();
Model.Address = new Address();
Model.OtherAdressess = new List<OtherAddress>();
DBContext _db = new DBContext();
Model.OtherAdressess = _db.OtherAddressess.Where(a=> a.City == "Amsterdam");
return View(Model);
}
in the view
#model Project.Models.MasterModel
List<SelectListItems> items = new List<SelectListItems>();
foreach(var a in Model.OtherAddressess)
{
SelectListItem item = new SelectListItem();
item.Value = a.Id.toString();
item.Text = a.Street;
}
#using (#Html.BeginForm())
{
<div>
<select name="otheraddress">
foreach(var i in Items)
{
<option value=#i.Value>#i.Text</option>
}
</select>
<input type="submit" name="select" value="Select Address"/>
</div>
<div>
#Html.EditorFor(model => Model.Address.Name)
<div>
<p>
<input type="submit" value="Submit"/>
</p>
}
in post
[HttpPost]
public ActionResult Create(MasterModel Model)
{
String otherAddressSelected = Request.Params["select"];
if(!String.IsNullOrEmpty(otherAddressSelected))
{
int id = int.Parse(Request.Params["otheraddress"]);
DBContext _db = new DBContext();
OtherAddress oa = _db.OtherAddress.Single(oa=> oa.Id == id);
Model.Address.Name = oa.Name;
return View(Model);
}
//other stuff here
}
If you want to change the value of your model in a [HttpPost] controller you have to remove the modelstate for the instance/attribute that you want to change. For example:
[HttpPost]
public ActionResult Index(SomeModel model)
{
ModelState.Remove("Name");
model.Name = "some new name";
return View(model);
}
Got the answer from this example
I would create action method called details that would accept person id as parameter:
public ActionResult Details(int id)
{
// Get person and display
}
Your Create action method is for creating Person type objects, and not displaying their details. So logically what you are doing doesn't seem right to me.
There should be action method to display view for creating a person and equivalent HTTP action method for persisting it into the database.
I would then re-direct to an action method for displaying Person type object information.
return RedirectToAction("Details", new { id = Person.Id });
The input helpers in asp.net mvc will use the post values if they can find any before looking at the model.
In this situation here I think the problem is that you are trying to do more then one thing in the Create POST action. A action (as with any method in the application) should only do one thing. In your case I would do something like this (if I understand the work flow correctly that is):
//Action: SelectAddress
public ActionResult SelectAddress() {
var addresses = _db.OtherAddressess.Where(a=> a.City == "Amsterdam");
return View(new SelectAddressViewModel(addresses));
}
//View SelectAddress
....
<ul>
#foreach(var address in Model.Addresses) {
<li>
<a href="#Url.Action("Create", "Product", new { addressId = address.Id })">
#Model.Name
</a>
</li>
}
</ul>
....
//Action Create
public ActionResult Create(int addressId) {
var address = _db.OtherAddress.Single(oa=> oa.Id == addressId);
var Model = new MasterModel();
Model.Person = new Person();
Model.Address = new Address {
Name = address.Name
}
return View(Model);
}
An article view model
public class ArticleViewModel : ViewModelBase
{
[Required(ErrorMessage = "Required")]
public string Title { get; set; }
[Required(ErrorMessage = "Choose the language")]
public BELocale Locale { get; set; }
}
public class BELocale : BEEntityBase
{
public string OriginalName { get; set; }
public string FriendlyName { get; set; }
public string TwoLetterISOName { get; set; }
}
A view "AddLocaleForArticle"
#model Models.ArticleViewModel
#using (Html.BeginForm("VefifyAddingLocaleForArticle", "Administration"))
{
#Html.TextBoxFor(m => m.Title, new { disabled = "disabled" })
#Html.DropDownListFor(m => m.Locale,
new SelectList(ViewBag.AvalaibleLocales, "ID", "OriginalName"), "Select a language"
)
#Html.ValidationMessageFor(m => m.Locale)
<input type="submit" value="Save" />
}
An action
public ActionResult VefifyAddingLocaleForPhoto(ArticleViewModel article)
{
//article.Locale == null for some reason.
//but article.Title isn't null, it contains the data
return RedirectToAction("AddingLocaleForPhotoSuccess", "adminka");
}
Why article.Locale is equal null and how to fix it?
When the form is submitted a dropdown list sends only the selected value to the controller. So you cannot expect it to populate an entire complex object such as BELocale using a dropdownlist. The best you could is to populate its ID property and fetch the remaining of the object from your data store using this id.
So you will have to modify your dropdownlist helper so that it is bound to the id property of the locale as first argument:
#Html.DropDownListFor(
m => m.Locale.ID,
new SelectList(ViewBag.AvalaibleLocales, "ID", "OriginalName"),
"Select a language"
)
Now inside the corresponding controller action you will get the id:
public ActionResult VefifyAddingLocaleForPhoto(ArticleViewModel article)
{
// article.Locale.ID will contain the selected locale id
// so you can use this information to fetch the corresponding BELocale object
...
}
You may fill dropdown like this in your view model
public List<KeyValuePair<int, String>> locale
{
get
{
return _localerepo.Findlocals().Select(x => new KeyValuePair<int, string>(x.ID, x.OriginalName)).ToList();
}
}
In your view use this
<%:Html.DropDownListFor(x => x.ID, new SelectList(Model.locale, "key", "value"), "--Select locale--")%>
<%= Html.ValidationMessageFor(model => model.ID)%>
I have a property in my model very simple one:
Now this dropDown doesn't work right
#Html.DropDownListFor(m => m.Camp, new SelectList(ViewBag.Camps, "Id", "Name"))
it returns null instead of a chosen Camp, but if I change that into:
#Html.DropDownListFor(m => m.Camp.Id, new SelectList(ViewBag.Camps, "Id", "Name"))
It would return me a Camp object with correct Id, but the Name would be still null.
Why?
UPD:
And now another problem is if I choose the second approach it would screw up with unobtrusive validation. Although I'll be able to get the right camp based on the chosen id.
That's normal. Only the Id is posted to the controller action. That's how dropdown inside forms work. So that's all you can hope to get there. You will then use this Id to get the corresponding Camp object from the database:
[HttpPost]
public ActionResult Foo([Bind(Prefix = "Camp")]int id)
{
Camp camp = Repository.GetCamp(id);
...
}
Also please get rid of this ViewBag and use a real view model:
public class CampViewModel
{
public int Id { get; set; }
public IEnumerable<SelectListItem> Camps { get; set; }
}
and in the controller:
public ActionResult Index()
{
var model = new CampViewModel
{
Camps = Repository.GetCamps().Select(x => new SelectListItem
{
Value = x.Id.ToString(),
Text = x.Name
})
};
return View(model);
}
[HttpPost]
public ActionResult Index(int id)
{
Camp camp = Repository.GetCamp(id);
...
}
and the view:
#model CampViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(
x => x.Id,
new SelectList(Model.Camps, "Value", "Text")
)
<input type="submit" value="OK" />
}