drop down list in MVC - asp.net-mvc

I am absolutely new to the MVC application.I want a dropdown list on my form I have done it this way
"<%= Html.DropDownList("Categories", (IEnumerable<SelectListItem>)ViewData["Categories"])%>"
I am sending the viewdata[Categories] from the controller class file.
this way
IList allCategories = _dropdownProvider.GetAllCategories();
ViewData["Categories"] = new SelectList(allCategories, "catid", "catname");
Now my requirement is that when the user selects a particular category from the dropdownlist its id should get inserted in the database,
The main problem is category id I want to insert the category id in the product table where the category Id is the foreign Key.
Please tell me how can I do this.

Normally you would do the following:-
On your view you would have...
Inherits="System.Web.Mvc.ViewPage<Product>" THIS IS A REFERENCE TO YOUR PRODUCT ENTITY
and in the page you can do this...
Category <%=Html.DropDownList("CatId") %>
you would also have the GET controller which defines the list
public ActionResult Add()
{
ViewData["CatId"] = new SelectList(allCategories, "catid", "catname");
then you can get the CatId from the product passed in to the Add method
e.g.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(Product product)
{
int catId = product.CatId
HTH. You ought to buy a book on the subject as MVC takes away alot of the pain of binding from you.

when you try to post the view, you'll have a "Categories" key in your querystring. you could convert it to long or the type you use in your table and set it to the product instance that you want to.
if this is not so clear, please send your code for a better explanation.

If i Understand right your question, the only thing you have to do, is inspect the POST for the "Categories" Key, and it will contain the selected value of the DropDownList.
var selectValue = System.Convert.ToInt16(Request.Form["name"]);
Or if you use ModelBinder and define a model that bind that value directly, you just have to Update the Model with
bool x = TryUpdateModel(YourModelNameHere);
This will automatically inspect the current ControllerĀ“s Value Provider and bind that value to the corresponding property in your model.
I recoment you to use the parameter FormCollection in your controller, and put a breakpoint, you can see all the values send within the POST. All that values are accessible through Request.Form["KEY"].

Related

MVC Populate dropdownlistfor in CREATE view from another model

So I basically have the same issue as this post: ASP.NET MVC - How to populate dropdownlist with another model?
The solution works... technically.. as long as the model is populated. However, I'm working with a CREATE view where the controller's action simply returns a blank "View()" obviously because it's creating something so you don't have any data yet.... yet I obviously still want the dropdownlist to populate from a model which gets it's data from the DB. If I try to run this code on a view with an empty model I get "Object reference not set to object" when it tries to grab the property that returns the list.
I tried instantiating a new, blank model in the Create action with the USING statement and set only PropertyTypeList property with a new instance of the Type model, and passed it to the view and it sort of worked... the view showed up with the dropdown of the other Type model populated, but it pre-filled in a bunch of the int/date types with 0's and 1/1/1900's because I have non-nullable fields. This is the closest I've gotten so far to simply letting the user create a new record with a pre-populated dropdown from ome of the fields that comes from a model.
I could just create a new Type model in the Create Action and assign it to the Viewbag or Tempdata, which I've done in the past, but this idea just makes me feel DIRTY. Viewbag disappears if the person refreshes the page so they get an error and is totally unprofessional. And I don't use Tempdata much because it relies on session state which gets very problematic if a user has my form open in mulitple tabs which could easily happen.
I feel like the solution from this post is SO close. It works fine when you're working with the EDIT action because you're passing a full model. But does anyone know how to get a dropdownlist to populate like this with an empty model? I tried something like adding an extra class to my secondary Type model
namespace blablanamespace {
public partial class PropertyType {
.. bla bla bla propertytype ID and name here
}
public class ViewModel
{
private readonly List<PropertyType> _keytypes;
public IEnumerable<SelectListItem> PropTypeItems
{
get { return new SelectList(_keytypes, "TypeID", "TypeID"); }
}
}
}
and
#Html.DropDownListFor(model => model.TypeID, new SelectList(new blablanamespace.Models.ViewModel().PropTypeItems))
but then I just get this error:
Value cannot be null. Parameter name: items
If I change the ViewModel class to instantiate a new list of types like so
public class ViewModel
{
public class ViewModel
{
private readonly List<PropertyType> _keytypes = new List<PropertyType>;
public IEnumerable<SelectListItem> PropTypeItems
{
get { return new SelectList(_keytypes, "TypeID", "TypeID"); }
}
}
I don't get the error this time, but I just get a blank form(yay) with a blank dropdownlist(boo!!). I figured this latter method would work since when I want to populate a new fresh list in the controller I basically do the same thing
List<ApplicationKeyType> _keytypes = new List<ApplicationKeyType>();
That behavior doesn't appear to be the same in the model.

How to make DropDownListFor use item IDs instead of indices?

I have a table with a dropdown list in each row, like this:
#Html.DropDownListFor(m => m.Transactions[i].CategoryID, ...)
and everything mostly works. I can select items, submit the form, and the model has my updated selections. So far so good.
The problem is that this isn't very reliable. Since the name of each dropdown is based on an index rather than an ID that means the match-up between the post values and the actual items living in the database are based on indices. Most of the time that works fine, but what if the list of items changes between the time the page loads and the time a user does a postback? The indices have changed, which means the post data won't match up correctly, and bad things happen. OR I've seen the browser incorrectly try to preserve selections in dropdowns between posts, but because the list of items is changing (what may be item #2 now may be item #3 by the time the page is refreshed) and everything is based on indices, the wrong dropdowns get the wrong values.
So basically, how can I force the dropdowns to generate a name and ID that looks more like this:
Transactions_CategoryID_12385652 // 12385652 is the CategoryID
rather than this:
Transactions_4_CategoryID // 4 is the array index
and still have the benefits of automatic binding?
Edit: The second issue I mentioned (input values being restored incorrectly after a refresh) seems to only happen with Firefox. https://bugzilla.mozilla.org/show_bug.cgi?id=46845
You'd have to write your own custom model binder as well as a Html extension to generate the element names in this way, or you could generate the markup manually using Razor.
Is there a particular reason you want need to do it this way? You're almost always following the conventions of the framework unless there's a good reason not to.
You can pass the exact collection you want to the view and bind that to the DropDownFor html helper.
Say you have a Person.
public class Person
{
public int Id { get; set; }
public int Name { get; set; }
}
And you want to add a new person. Create a view model. Create a property in this view model of type SelectList. This select list will hold the collection of the model you want to populate the dropdown list with.
public class PersonViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public SelectList MySelectList { get; set; }
}
Let's say you want the drop down list to hold the Person's Id as the selected value and the Person's name as the text value. You may want to create a second view model to represent that or use an anonymous object. Let's call the collection myCollection. And let's say that the collection is made up of objects that have two properties (and Id and Name property). Now simply pass this view model with a value for MySelectList.
var viewModel = new MyViewModel
{
MySelectList = new SelectList(myCollection, "Id", "Name")
};
In your razor view you can set up the #Html.DropDownListFor like so:
#Html.DropDownListFor(m => m.Id, Model.MySelectList)
In order to pass a select value to the view for the dropdownlist simply use the SelectList constructor overload that allows this value to be passed:
new SelectList(myCollection, "Id", "Name", selectedValue)

Is there a way to search for an item in a ViewBag?

I have a ViewBag.People made up from a View;
var query = db.Vw_INTERACTPEOPLE.Select(p => new { p.PersonID, p.Fullname });
ViewBag.People = new SelectList(query.AsEnumerable(), "PersonID", "FullName");
Which all works fine, but in my view I have another model populating a table, and one of the items is populates is an JobcontactID (textbox) which links to the PersonID (i didnt design the database). So I want to search the viewbag for the ID and rather than displaying it I want to display the persons Fullname, so is there any viewbag search functionality?
I would suggest to pass that information in your ViewModel. It will keep it clean and maintainable in long run. Here is a good post: Use ViewModels to manage data & organize code in ASP.NET MVC applications
ViewBag is just a dynamic wrapper around ViewData (which allows the property invoked at runtime to become the key which will be used to look up the value in ViewData). You can query ViewData like this:
SelectList peopleSelectList = (from pair in ViewData
where pair.Key == "People"
select pair.Value);
Update So you wish to query the select list itself?
Here's a function defined in the razor view:
#functions {
public string FindPersonName(string id)
{
return (from item in ViewBag.People as SelectList
where item.Value == id
select item.Value).FirstOrDefault();
}
}
#functions.FindPersonName(jobContactId)

quick FormCollection question ASP.NET MVC2

I have a simple object
public class SomeObject
{
public Int32 id { get; set; }
public string name { get; set; }
}
In a strongly typed view I am letting the user edit SomeObject.name, when the form is posted the receiving method doesn't see SomeObject.id in FormCollection (it does see SomeObject.name). Do I need to actually place every object property in the form to be able to access them when form is posted?
What's the best practice, should I just insert hidden fields for each property I don't plan letting the user edit? maybe I should place the entire object in the ViewData?
Thanks
FormCollection contains only properties that have been posted either through text fields or hidden fields. So if you need to use the Id property in your controller action you need to include it in your form. Depending on what you are doing in your controller action you might or might not include it. It is not necessary to include hidden fields for each property.
Usually the Id is sufficient because it allows you to later retrieve the object from your data store given this id.
What does your action method look like to which you are posting the form? If your method to handle the GET requests takes id, if your POST method also takes id and you are using the BeginForm helper method with none of the parameters overloaded, the form method will take the id as a parameter and you won't need to worry about including hidden fields for the id itself.

Storing state in asp.net MVC

I'm building an asp.net MVC 2 app.
I have a list view which lists items based on a parameter. In the database I have a parent and child table, so my list view lists all the child records for where the parent's id matches the value specified in the parameter.
This is my controller and model:
public ActionResult List(int ParentID)
{
return View(new Models.ChildListModel(ParentID));
}
public class ChildListModel
{
public int ParentID {get;set;}
public ManagementUserListModel(int iParentID)
{
this.ParentID = iParentID;
this.Children = DataAccessLayer.ListChildrenForParent(iParentID);
}
public List<Child> Children {get;set;}
}
I also have a details and create action for that controller. The details and create view have a "back to list" action, which I want to go back to the list view, and maintain the original ParentID. So far I've been doing this by creating a hidden field called ParentID in the list, edit, create and details views, so that the model's ParentID property will get populated correctly:
<%= Html.HiddenFor(model => model.ParentID) %>
Then in the "Back to List" action in each view I pass the ParentID:
<%=Html.ActionLink("Back to List", "List", new {ParentID = Model.ParentID}) %>
This all works, but I'm not a big fan of storing raw IDs in the html. Are there any better ways to do this? Is there some built in way to encrypt the data (kind of like the standard asp.net viewstate did?) I'm just trying to achieve some sort of tamper resistance, and trying to avoid using session state (TempData, etc) because I don't want to have to handle session timeouts.
You may take a look at this article. You could use the new Html.Serialize extension method in your view which allows you to serialize entire objects and encrypt it:
<%= Html.Serialize("person", Model, SerializationMode.Encrypted) %>
Which serializes the Model into a hidden field and encrypts the value. To get the model back you use the DeserializeAttribute in the controller action to which the form is submitted:
public ActionResult Edit([Deserialize]Person person) { }
Another way to do this that doesn't expose the id and also doesn't add to the weight of the subsequent form post (like Webform's ViewState does and Html.Serialize would) is to use the session as the backing store inside your Model class.
public class ChildListModel
{
public int ParentID {
get
{
return (int)HttpContext.Current.Session["ChildListModel.ParentID"];
}
set
{
HttpContext.Current.Session["ChildListModel.ParentID"] = value;
}
}
public ManagementUserListModel(int iParentID)
{
this.ParentID = iParentID;
this.Children = DataAccessLayer.ListChildrenForParent(iParentID);
}
public List<Child> Children {get;set;}
}
If you like, you could even store the entire Parent object in your model that way instead of just it's ID - that would add to the session size on the server which may or may not be desirable (depending on how long your session lasts and whether it is set to be stored in memory or in sql server, etc.)
The easiest way would be to keep the parentid in the URL. It will look a bit strange for the Create Action but I still think that this the less troublesome way.
If you keep state, you will alwas have the problem that you can not hit F5 and you can not bookmark the page.
The backlink is a simple ActionLink in this case.
Urls would be:
/YourController/List/YourParentParameterValue
/YourController/Detail/YourParentParameterValue/YourDetailParameterValue
/YourController/Create/YourParentParameterValue

Resources