I am new to MVC and EF, but i have a group of models that represent lookup tables that all have the same structure
public int ID {get; set;}
public string Value {get; set;}
public bool IsActive {get; set;}
Rather than writing one Controller and View for each is there a way to create one, that is defined by a previous selected value.
So if 2 of my lookups are Gender and Status and a dropdown with these values
can I then take the name of the selected option and then dynamically bind to the model
so rather than having Status status = new Status its Object object = new Object where object has been defined by the selection of Status in the previous dropdown
It is definitely possible. There are several ways you could achieve this. You could have an EditorTemplate with everything you need to display your dropdown. In ~/Views/Shared/EditorTemplates/DropDown.cshtml
#model string
#{
Layout = null;
List<SelectListItem> ListItems = (List<SelectListItem>)ViewBag.ListItems;
}
// not sure what the syntax for a dropdown is, I don't use them
#Html.SelectFor(m => Model, ListItems)
Then in your view
#Html.EditorFor(m => m.Status, "DropDown", new { ListItems = MyModel.StatusSelectListItems })
#Html.EditorFor(m => m.Gender, "DropDown", new { ListItems = MyModel.GenderSelectListItems })
Where in your model you would have the selection options:
public class MyModel
{
// other stuff
public static List<SelectListItem> GenderSelectListItems = new List<SelectListItem>
{
new SelectListItem{ Value = "Male", Text = "Male" },
new SelectListItem{ Value = "Female", Text = "Female" }
};
// etc
}
Related
I have the following two models, one of which contains a list of the other model i.e. UserModels.
public class UserModel
{
public int SelectedUserId { get; set; }
public SelectList UserOptions { get; set; }
public UserModel()
{
var users = new List<SelectListItem>
{
new SelectListItem { Text = "Mickey Mouse", Value = "1" },
new SelectListItem { Text = "Goofy", Value = "2" },
new SelectListItem { Text = "Donald Duck", Value = "3" },
};
UserOptions = new SelectList(users, "Value", "Text");
}
}
public class MyModel
{
public IList<UserModel> Users { get; set; }
public MyModel()
{
Users = new List<UserModel>();
}
}
When I attempt to bind this list of UserModels to a MVC Razor page with multiple DropDownList, the values do not bind and the selected item in the DropDownList is not displayed correctly.
#for(int i=0; i < Model.Users.Count; i++)
{
#Html.DropDownListFor(x => x.Users[i].SelectedUserId, Model.Users[i].UserOptions)
}
However, if I select different values in each DropDownList on the page and then post the form back to the server, the correct values bind within each individual UserModel in the List of models i.e. 'Users'.
Am I missing something here? Is this a known bug? Why is it when setting the values of SelectedUserId in each model on the server, does the correct option in the select list not bind, but selecting an option in the select list on the web page does work?
#Html.DropDownListFor works very weird way, when you init one, you have to init selected value too. So if you create list like this:
Users.Add(new UserModel { SelectedUserId = "2" });
you will have to assign selected item inside of UserModel :
List<SelectListItem> users=null;
public string SelectedUserId
{
get { return users.Where(u=>u.Selected).FirstOrDefault().Value; }
set {
var sUser=users.Where(u=>u.Value=value).FirstOrDefault();
sUser.Selected=true;
}
}
if you use net core much better to use " select " tag. It assigns automatically.
The DropDownListFor is not selecting the SelectListItem that I am specifying should be selected. Unable to figure out why as all parameters appear to be correct.
ViewModel:
public class SchemesViewModel
{
public int SchemeId { get; set; }
public SelectList Schemes { get; set; }
}
Controller (select list preparation):
var schemes = schemeManager.GetUserSchemes(this.UserId);
var selectListItems = schemes.Select(x => new SelectListItem() { Value = x.Id.ToString(), Text = x.Name, Selected = (x.Id == 2) });
var vm = new UserSchemesViewModel()
{
Schemes = new SelectList(selectListItems, "Value", "Text", selectedValue: selectListItems.FirstOrDefault(x => x.Selected == true).Value)
};
return PartialView("_UserSchemes", vm);
View:
Note: This is where the select option with value of 2 is not selected!
#Html.DropDownListFor(x => x.SchemeId, Model.Schemes)
Setting the Selected property of SelectListItem is ignored by the DropDownListFor() method. Internally the method build a new IEnumerable<SelectListItem> using the Value of Text properties of you existing SelectList and sets the new Selected property based on the value of property you binding to. You need to set the value of SchemeId before you pass the model to the view.
There is also no point creating a second identical SelectList from you first one (its just unnecessary extra overhead).
Modify your code to
public class SchemesViewModel
{
public int SchemeId { get; set; }
public IEnumerable<SelectListItem> Schemes { get; set; }
}
Controller
var schemes = schemeManager.GetUserSchemes(this.UserId);
var selectListItems = schemes.Select(x => new SelectListItem()
{
Value = x.Id.ToString(),
Text = x.Name
});
var vm = new UserSchemesViewModel()
{
Schemes = selectListItems,
SchemeId = 2
};
return PartialView("_UserSchemes", vm);
Now if one of your options has value="2" then that option will be selected when you first render the view.
I am trying to create a multiple select from a single select drop down menu.
my model originally had:
public int country_id { get; set; }
and my view had:
#Html.DropDownList("country_id", String.Empty)
to change it to multiple select i changed my model to:
public List<Country> country_id { get; set; }
and my view to:
#Html.ListBoxFor(model => model.country_id, ViewBag.ActionsList as MultiSelectList, new { #class = "multiselect", #style = "width: 450px;height:200px" })
the problem i am having is updating my databse using migration since the i am changing int to list, however, it keeps saying
"Cannot drop the index 'dbo.People.IX_country_id', because it does
not exist or you do not have permission."
I do have permission so I am not sure if I am missing something?
My list of countries is coming straight from the country database.
thanks for your inputs.
You need to populate a selectlist in the controller & pass it to the view, something like this:
var countries = from d in db.Countries
select new
{
Id = d.Id,
Name = d.Name
};
// I'd pass this in a model, but use ViewBag if that's what you're familiar with
ViewBag.ActionsList = new SelectList(countries , "Id", "Name");
And in the View:
#Html.DropDownListFor(model => model.country_id, ViewBag.ActionsList)
UPDATE:
You should use a ViewModel for this:
public class CountryList
{
// this may have to be a List<SelectListItems> to work with MultiSelectList - check.
public SelectList Countries{ get; set; }
public List<int> SelectedCountryIds { get; set; }
}
In the controller:
var model = new CountryList
{
SelectList = //assign the selectlist created earlier
}
return View(model);
In the View:
#Html.ListBoxFor(m => m.SelectedCountryIds, new MultiSelectList(#Model.Countries, "Id", "Name", #Model.SelectedCountryIds))
I want to use ComboBox in my MVC application but the Html.DropDownListFor is not giving the desired output. My controller code is as follows
public class Data_TableController : Controller
{
public ActionResult ListIndex()
{
List<SelectListItem> listSelectListItems = new List<SelectListItem>();
SelectListItem selectList = new SelectListItem()
{
Text = "DD",
Value = "1"
};
listSelectListItems.Add(selectList);
selectList = new SelectListItem()
{
Text = "XX",
Value = "2"
};
listSelectListItems.Add(selectList);
CitiesViewModel citiesViewModel = new CitiesViewModel()
{
Cities = listSelectListItems
};
return View(citiesViewModel);
}
}
ListIndex.cshtml code is:
#model MvcDemo.Models.CitiesViewModel
#{
ViewBag.Title = "ListIndex";
}
<div style=”font-family:Arial”>
<h2>Index</h2>
#using (Html.BeginForm())
{
#Html.DropDownListFor(m => m.SelectedCities, Model.Cities, new { size = Model.Cities.Count() })
<br />
<input type="submit" value=”Submit” />
}
</div>
View Model as follows
public class CitiesViewModel
{
public IEnumerable<string> SelectedCities { get; set; }
public IEnumerable<SelectListItem> Cities { get; set; }
}
But the HTML out is as pure list box. Also I like to know, How to add a label here? Attaching the output which I want to be in a combobox.
You are growing the 'display size' of your drop down list by adding:
new { size = Model.Cities.Count() }
So removing it will make it the default 'display size' of one element.
To add a label, I find the best way is as follows:
In your model, on the property use the DisplayName attribute:
[DisplayName("The City:")]
public string Cities { get; set; }
Then in your View display it like so:
#Html.LabelFor(m => m.Cities)
To give the drop down list / combobox a style do something like the following, i.e. use the new operator:
#Html.DropDownListFor(m => m.SelectedCities, Model.Cities, new { id = "cities", style = "width:320px;color:red;background-color:blue;" })
Edit:
As jbutler483 pointed out styling could be achieved through the following if you wish to use a css file (however if the style is a one off and is not used elsewhere in the site then inline styles are best):
Html.DropDownListFor(..., new { #class = "myclassname" } );
I obtain a list of data through docs which has a list of every single department and function the currently logged in user has access to. I need to populate a distinct list of Departments for a DropDownList and a distinct list of Functions for a DropDownList on the View page. I am currently not even using docs to do this but a different LINQ query to acheive this. Is there a way I can use the current model I am passing?
var docs = (Long LINQ query that joins in four different tables and returns a model)
ViewBag.DepartmentList = db.Department.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Department's from the table.
ViewBag.FunctionList = db.Function.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Function's from the table.
Code on View: (Strongly Typed Model)
#model IEnumerable<DB.Models.MasterList>
#Html.DropDownList("DepartmentList", "Select a Department")
#Html.DropDownList("FunctionList", "Select a Function")
Define a model that will be used in your view.
public class MyViewModel
{
public string SelectedDepartment { get; set; }
public string SelectedFunction { get; set; }
public IEnumerable<SelectListItem> Departments { get; set; }
public IEnumerable<SelectListItem> Functions { get; set; }
// Your old model
public IEnumerable<MasterList> Master { get; set;}
}
In your controller, populate these collections and return your model to view.
[HttpGet]
public ActionResult ActionMethodName()
{
var model = new MyViewModel();
model.Departments = db.Departments.Where(x => (x.name != null))
.Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct();
model.Functions = db.Functions.Where(x => (x.name != null))
.Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct();
return View(model);
}
Inside your view, use strongly typed html helpers.
#model MyViewModel
#Html.DropDownListFor(m => m.SelectedDepartment, Model.Departments)
#Html.DropDownListFor(m => m.SelectedFunction, Model.Functions)
When you post back your form to server, SelectedDepartment and SelectedFunction should have the values selected in your view.
You could create a ViewModel and put all this data in this ViewModel:
ViewModel
public class MyViewModel{
public object DepartmentList{get; set;}
public object FunctionList{get; set;}
public IEnumerable<MasterList> Master {get; set;}
}
Controller
var docs = (Long LINQ query that joins in four different tables and returns a model)
MyViewModel vm = new MyViewModel();
vm.Master = docs; // I guess docs is a list of Masterlist
vm.DepartmentList = db.Department.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Department's from the table.
vm.FunctionList = db.Function.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Function's from the table.
return View(vm);
View
#model MyViewModel
#Html.DropDownList("DepartmentList", "Select a Department")
#Html.DropDownList("FunctionList", "Select a Function")
You can always create a ViewModel class for your view and put all the necessary view information in it.
You can use a framework like AutoMapper (https://github.com/AutoMapper/AutoMapper) to help you with the mapping between your database model and your view model (I belive it's best that the view won't know the database model at all), and beside the model information you can also add those lists (That's what I do, I have a property for the entity, and properties for those kinds of lists).
If you need this information in many of your views you can always create a BaseViewModel and polpulate that information in a BaseController.