How to populate dropdown list for specific user? - asp.net-mvc

I have three dropdown list:
#Html.DropDownListFor(m => m.Edit.SelectCountryId, Model.Edit.Countries, "Please select", new { id = "CountryID", #class = "form-control", #onchange = "LoadRegions();" })
#Html.DropDownListFor(m => m.Edit.SelectRegionId,Model.Edit.Region, "Please select", new { id = "RegionID", #class = "form-control", #onchange = "LoadCities();" })
#Html.DropDownListFor(m => m.Edit.SelectCityId, Model.Edit.City, "Please select", new { id = "CityID", #class = "form-control" })
I populate second one depending on first one and third depending on second...but when i want to display those dropdown lists for some specific user im able to display just countries
My model:
public int SelectCountryId { get; set; }
public int SelectRegionId { get; set; }
public int SelectCityId {get; set;}
public System.Web.Mvc.SelectList City { get; set; }
public System.Web.Mvc.SelectList Region{ get; set; }
public System.Web.Mvc.SelectList Country{ get; set; }
My controller:
model.Edit.SelectCountryId = user.ContactInformation.First().City.Region.Country.Id;
model.Edit.SelectRegionId = user.ContactInformation.First().City.Region.Id;
model.Edit.SelectCityId = user.ContactInformation.First().City.Id;
I get values on controller but i cant get display them in view
EDIT:
My scripts:
var region = $('#RegionID');
var urlCountries = "/Account/GetRegions";
$.getJSON(urlCountries, { countryId: $('#CountryID').val() }, function (response) {
// clear and add default (null) option
region.empty().append($('<option></option>').val('').text('Please select'));
for (var i = 0; i < response.length; i++) {
region.append($('<option></option>').val(response[i].Id).text(response[i].Name));
}
});
var city = $('#CityID');
var url = "/Account/GetCities"; // use the helper (dont hard code)
$.getJSON(url, { regionId: $('#RegionID').val() }, function (response) {
// clear and add default (null) option
city.empty().append($('<option></option>').val('').text('Please select'));
for (var i = 0; i < response.length; i++) {
city.append($('<option></option>').val(response[i].Id).text(response[i].Name));
}
});
My methods for GetCity() and GetRegions()
public IEnumerable<IRegion> GetRegions(int countryId)
{
Model.Administration.Region[] modelRegions = Model.Administration.Region.FindAll(DetachedCriteria.For<Model.Administration.Region>().Add(Restrictions.Eq("Country.Id", countryId)));
return modelRegions.Select(Region.ConvertFromModel).Cast<IRegion>().ToList();
}
public IEnumerable<ICity> GetCities(int regionId)
{
CityLimited[] modelCities = CityLimited.FindAll(DetachedCriteria.For<CityLimited>().Add(Restrictions.Eq("Region.Id", regionId)));
return modelCities.Select(City.ConvertFromModel).Cast<ICity>().ToList();
}

You need to pass an additional value indicating the selected option in the json data your returning to the view. Your GetRegions() method should look like
public JsonResult GetRegions(int countryId) // return a JsonResult
{
Model.Administration.Region[] modelRegions = Model.Administration.Region.FindAll(DetachedCriteria.For<Model.Administration.Region>().Add(Restrictions.Eq("Country.Id", countryId)));
var options = modelRegions.Select(Region.ConvertFromModel).Cast<IRegion>().ToList();
var selection = 1; // set the value of the selected option here - must match the `ID` property of one of one of the `IRegion` your returning
return Json(new { options = options, selection = selection }, JsonRequestBehavior.AllowGet);
}
Side note: Its not clear what modelRegions.Select(Region.ConvertFromModel).Cast<IRegion>().ToList(); returns but if IRegion contains more that just the ID and Name properties you need for the view, consider creating a collection of anonymous objects so you don't send unnecessary data across the wire
Then the corresponding script should be
var url = '#Url.Action("GetRegions", "Account")'; // use the helper (dont hard code)
var regions = $('#RegionID'); // cache the element
$('#CountryID').change(function() {
$.getJSON(url, { id: $(this).val() }, function(response) {
// clear and add default (null) option
regions.empty().append($('<option></option>').val('').text('Please select'));
$.each(response.options, function(index, item) {
cities.append($('<option></option>').val(item.Value).text(item.Text));
});
regions.val(response.selection); // set the selected value
});
});
and remove the #onchange = "LoadRegions(); from you markup
Ditto for the GetCities() controller method and the corresponding script

Related

Placeholder on a #Html.Dropdownlist that is not selectable

How do i put a placeholder on my #Html.Dropdownlist that is not selectable.
I implemented chosen-jquery on my dropdown.
My code is as per below:
#Html.DropDownList("Id", new SelectList(new Ahib.Membership.UserFacade().GetAllUsers(), "Id", "Username"), "-select a system owner-", new { #class="chosen1-select" })
Currently my dropdownlist has a placeholder but the "-select a system owner-" becomes a selectable value which i dont want. How do solve this issue?
You can convert your list to the selectitem list and apply your disabled attribute from the controller itself.
like this
assuming your model is like this
class user
{
public int Id { get; set; }
public string Username { get; set; }
}
Convert your list to List<SelectListItem> like this, note here I am disabling the select a system owner entry.
public ActionResult Index()
{
List<user> users = new List<user>();
users.Add(new user { Id = 1, Username = "test1" });
users.Add(new user { Id = 2, Username = "test2" });
List<SelectListItem> list = new List<SelectListItem>();
list.Add(new SelectListItem { Text = "-select a system owner-", Value = "0", Disabled = true });
foreach (var item in users)
{
list.Add(new SelectListItem
{
Text = item.Username,
Value = item.Id.ToString()
});
}
ViewBag.listItems = list;
return View();
}
and in view use it like this
#Html.DropDownList("test", ViewBag.listItems as IEnumerable<SelectListItem>);
Result:

How to refresh Html.DropDownGroupList after another dropdown changes

I have difficulties to refresh an Html.DropDownGroupList.
I have two dropdowns which depends on each other: Makes and Models. The Models dropdown should be grouped, as you can see in the attached screenshot.
When I enter in the page the Models dropdown is filled with data and it is grouped correctly, but when I change the first dropdown, the Model is not refreshing correctly.
In the controller I have this code:
public ActionResult GetModels(string id)
{
if (!string.IsNullOrEmpty(id))
{
int number;
bool result = Int32.TryParse(id, out number);
if (!result)
return Json(null);
var selectedMake = makeRepository.GetMakeByID(number);
var list1 = db.Models.Where(m => m.MakeID == selectedMake.ID).ToList();
List<GroupedSelectListItem> models = new List<GroupedSelectListItem>();
foreach (var items in list1)
{
models.Add(new GroupedSelectListItem
{
Text = items.Name,
Value = items.ID.ToString(),
GroupName = items.GroupName,
GroupKey = items.GroupName
});
}
ViewBag.Alma = models;
return Json(models, JsonRequestBehavior.AllowGet);
}
return Json(null);
}
and in the View :
#Html.DropDownGroupList("models", ViewBag.Alma as List<GroupedSelectListItem>, "Select Model", new
{
#class = "dropdown-toggle col-md-9 form-control"
})
This is the code where I try to refresh the dropdown:
$.ajax({
type: 'POST',
url: '#Url.Action("GetModels")',
dataType: 'json',
data: { id: $("#makes").val() },
success: function (models) {
if (window.console) {
console.log(JSON.stringify(models))
}
$.each(models, function (i, model) {
$("#models").append
('<optgroup label="'+ model.GroupName + '"><option value="' + model.Value + '">' +
model.Text + '</option></optgroup>'
);
});
}
});
This is the way the dropdown looks after the refresh
The grouping is not working anymore. I know that this is the problem:
$("#models").append('<optgroup label="'+ model.GroupName + '"><option value="' + model.Value + '">' + model.Text + '</option></optgroup>');
but how to do this ajax call to group my dropdown? I don't have so much experience with ajax, javascript.
Can you please advise how to refresh the Model dropdown?
Your GetModels() method is returning List<GroupedSelectListItem> which is a special class used by the DropDownGroupList() method and is not suitable for building your html (at least without a lot of extra code to group data in the script).
Start by creating view models to represent the hierarchical data you need
public class GroupVM
{
public string Name { get; set; }
public IEnumerable<OptionVM> Options { get; set; }
}
public class OptionVM
{
public int Value { get; set; }
public string Text { get; set; }
}
Then modify the controller to group your data and project the results to the view model
public ActionResult GetModels(int? id)
{
if (!id.HasValue)
{
return Json(null);
}
var data = db.Models.Where(x => x.MakeID == id.Value).GroupBy(x => x.GroupName).Select(x => new GroupVM()
{
Name = x.Key,
Options = x.Select(y => new OptionVM()
{
Value = y.ID,
Text= y.Name
})
});
return Json(data);
}
And modify your script to
var models = $('#models'); // cache it
$('#makes').change(function () {
var id = $(this).val();
$.ajax({
type: 'POST',
url: '#Url.Action("GetModels")',
dataType: 'json',
data: { id: id },
success: function (data) {
models.empty(); // clear existing options
$.each(data, function (index, group) {
var optGroup = $('<optgroup></optgroup>').attr('label', group.Name);
$.each(group.Options, function (index, option) {
var option = $('<option></option>').val(option.Value).text(option.Text);
optGroup.append(option);
});
models.append(optGroup);
});
}
});
})

How to set the default value for Html.DropDownListFor in MVC

i have following code :
controller method:
public ActionResult Register(int? registrationTypeId)
{
IEnumerable<AccountType> accountTypes = new List<AccountType>
{
new AccountType
{
AccountTypeId = 1,
AccountTypeName = "Red"
},
new AccountType
{
AccountTypeId = 2,
AccountTypeName = "Blue"
}
};
// I want to select account type on registrationTypeId
ViewBag.AccountTypes = accountTypes;
return View();
}
View
<div class="col-md-10">
#Html.DropDownListFor(n => n.AccountType,
new SelectList(ViewBag.AccountTypes, "AccountTypeId", "AccountTypeName"), new { #class = "form-control" })
</div>
Model
public class RegisterViewModel
{
[Required]
[Display(Name = "Account Type")]
public int AccountType { get; set;
}
As you can see registrationTypeId in controller , i want to set the type on its bases if it is not null ,otherwise set to red. I have tried a alot but nothing worked for me. Any help will be appreciated !
I would highly recommend that you don't pass your list through the view bag. have seen too many questions where that has caused major issues. add this to your model
public List<SelectListItem> AccountTypes { get; set; }
in your controller in the get method set your default and set your list
Model.AccountType = 1; // change the one to your default value
Model.AccountTypes = accountTypes; //instead of ViewBag.AccountTypes = accountTypes;
then on your view
#Html.DropDownListFor(x => x.AccountType, Model.AccountTypes)
setting AccountType before passing the model to the view will set the default and the selected value on the view will be passed back in that same value.
The Wrong Way To Do This
var accountTypes = new SelectList(accountTypes, "AccountTypeId", "AccountTypeName");
foreach(var item in accountList)
if (item.AccountTypeId == registrationTypeId)
item.Selected = true;
ViewBag.AccountTypes = accountTypes;
In view,
#Html.DropDownListFor(n => n.AccountType, (SelectList)ViewBag.AccountTypes)

MVC checkboxes & FormCollection

On a mass-edit form page I display about 50 objects that have some boolean properties as well. The controller receives a FormCollection with all values from the edit page.
public void _EditAll(FormCollection c)
{
int i = 0;
if (ModelState.IsValid)
{
var arrId = c.GetValues("channel.ID");
var arrName = c.GetValues("channel.displayedName");
var arrCheckbox = c.GetValues("channel.isActive");
for (i = 0; i < arrId.Count(); i++)
{
Channel chan = db.Channels.Find(Convert.ToInt32(arrId[i]));
chan.displayedName = arrName[i];
chan.isActive = Convert.ToBoolean(arrCheckbox[i]);
db.Entry(chan).State = EntityState.Modified;
}
db.SaveChanges();
}
}
Now, for checkboxes, MVC creates hidden inputs on the form (otherwise "false" could not be posted back). In the controller, when receiving the FormCollection, this leads to the case that I receive an array of say
50 IDs,
50 names and ..
71 or so values for the checkboxes,
since the hidden checkbox has the same name as the visible one.
What's a good way to handle that and get the proper value of the checkbox?
Sample for editing array of entities that have boolean field.
Entity:
public class Entity
{
public int Id { get; set; }
public bool State { get; set; }
}
Controller:
public ActionResult Index()
{
Entity[] model = new Entity[]
{
new Entity() {Id = 1, State = true},
new Entity() {Id = 2, State = false},
new Entity() {Id = 3, State = true}
};
return View(model);
}
[HttpPost]
public ActionResult Index(Entity[] entities)
{
// here you can see populated model
throw new NotImplementedException();
}
View:
#model Entity[]
#{
using (Html.BeginForm())
{
for (int i = 0; i < Model.Count(); i++ )
{
#Html.Hidden("entities[" + i + "].Id", Model[i].Id)
#Html.CheckBox("entities[" + i + "].State", Model[i].State)
}
<input type="submit"/>
}
}
The only tricky thing is html elements naming.
More info about binding arrays.
I'm converting all arrays containing checkbox-values:
"false" => "false", if not preceded by "true"

Will a DropDownList html helper work correctly with a IList<SelectListItem>?

I am having problems with getting a DropDownList to correctly select the right value and display it.
I am using the following:
#Html.DropDownListFor(x => Model.AdminSummaries[index].Status, AdminStatusReference.GetAdminStatusOptions(), new { id = string.Format("Status_{0}",index ) })
Is it okay that AdminStatusReference.GetAdminStatusOptions() returns a List or MUST it return an IEnumerable?
Model:
public class MyViewModel
{
public IList<AdminSummary> AdminSummaries { get; set; }
}
public class AdminSummary
{
public string Status { get; set; }
}
public static class AdminStatusReference
{
public static IEnumerable<SelectListItem> GetAdminStatusOptions()
{
return new[]
{
new SelectListItem { Value = "1", Text = "status 1" },
new SelectListItem { Value = "2", Text = "status 2" },
new SelectListItem { Value = "3", Text = "status 3" },
};
}
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
AdminSummaries = new[]
{
// preselect the first item
new AdminSummary { Status = "1" },
// preselect the second item
new AdminSummary { Status = "2" },
// nothing will be preselected because there is no xxx Value in the list
new AdminSummary { Status = "xxx" },
}.ToList()
};
return View(model);
}
}
View:
#model MyViewModel
#for (int index = 0; index < Model.AdminSummaries.Count; index++)
{
#Html.DropDownListFor(
x => x.AdminSummaries[index].Status,
new SelectList(
AdminStatusReference.GetAdminStatusOptions(),
"Value",
"Text",
Model.AdminSummaries[index].Status
)
)
}
It will be fine.
List<T> implements IEnumerable<T>
for using
#Html.DropDownListFor<>
in my projects I have always used a IEnumerable<SelectListItem> in my View and therefore before hand I have set which item has the propery "Selected" as true. This will then set the default item.
forgot I could edit my original answer :P
here is the html rendered on my project

Resources