My model is a generic List. I want to use DropDownList for foreign key property binding.
My code is
Model
public class PersonViewModel
{
public int Id { get; set; }
public string LastName{get;set;}
public int NationalityId { get; set; }
}
public class Nationality
{
public int Id { get; set; }
public string Name { get; set; }
}
Controller
public ActionResult Index()
{
var nationalities = new List<Nationality>
{
new Nationality{Id = 0, Name = "CHOOSE NATIONALITY..."},
new Nationality{Id = 1, Name = "POLAND"},
new Nationality{Id = 2, Name = "USA"},
new Nationality{Id = 3, Name = "CANADA"}
};
var Nationalities = new SelectList(nationalities, "Id", "Name");
var persons = new List<PersonViewModel>
{
new PersonViewModel{Id = 1, LastName = "KOWALSKI", NationalityId = 1},
new PersonViewModel{Id = 1, LastName = "SMITH", NationalityId = 2},
new PersonViewModel{Id = 1, LastName = "SCHERBATSKY", NationalityId = 3}
};
ViewBag.Nationalities = Nationalities;
return View(persons);
}
View
#model List<PersonViewModel>
#Html.EditorFor(m=> Model[0].LastName)
#Html.DropDownListFor(m => Model[0].NationalityId, (SelectList)ViewBag.Nationalities)
#Html.EditorFor(m => Model[1].LastName)
#Html.DropDownListFor(m => Model[1].NationalityId, (SelectList)ViewBag.Nationalities)
#Html.EditorFor(m => Model[2].LastName)
#Html.DropDownListFor(m => Model[2].NationalityId, (SelectList)ViewBag.Nationalities)
Anyone can tell me why NationalityId property is not bound well
I can't upload image but it's not binding at all. Every DropDownList has 'CHOOSE NATIONALITY...' .
I would recommend you using Editor templates:
First - create view Shared\EditorTemplates\PersonViewModel.cshtml containing:
#model PersonViewModel
#Html.EditorFor(m => Model.LastName)
#Html.DropDownListFor(m => Model.NationalityId, (SelectList)ViewBag.Nationalities)
And in your current view
#for (int i = 0; i < Model.Count; i++)
{
#Html.EditorFor(x => Model[i])
}
Change your view model to this
public class PersonViewModel
{
public int Id { get; set; }
public string LastName{get;set;}
public int NationalityId { get; set; }
public IEnumerable<Nationality> Nationalities {get;set;}
}
In your controller
public ActionResult Index()
{
var nationalities = new List<Nationality>
{
new Nationality{Id = 0, Name = "CHOOSE NATIONALITY..."},
new Nationality{Id = 1, Name = "POLAND"},
new Nationality{Id = 2, Name = "USA"},
new Nationality{Id = 3, Name = "CANADA"}
};
var nationalities = new SelectList(nationalities, "Id", "Name");
var persons = new List<PersonViewModel>
{
new PersonViewModel{Id = 1, LastName = "KOWALSKI", NationalityId = 1 , Nationalities = nationalities},
new PersonViewModel{Id = 1, LastName = "SMITH", NationalityId = 2, Nationalities = nationalities},
new PersonViewModel{Id = 1, LastName = "SCHERBATSKY", NationalityId = 3, Nationalities = nationalities}
};
return View(persons);
}
And in your view
#model List<PersonViewModel>
#Html.EditorFor(m => m[0].LastName)
#Html.DropDownListFor(m => m[0].NationalityId, Model[0].Nationalities)
#Html.EditorFor(m => m[1].LastName)
#Html.DropDownListFor(m => m[1].NationalityId, Model[1].Nationalities)
#Html.EditorFor(m => m[2].LastName)
#Html.DropDownListFor(m => m[2].NationalityId, Model[2].Nationalities)
Two things:
Each dropdown needs its own select list. Currently you are using the same select list for each dropdown.
You need to specify a selected value for each select list, like so:
new SelectList(nationalities, "Id", "Name", persons[0].NationalityId);
Related
I am trying to flat this data into a viewmodel but I am not sure how to do it. The example below is the type of data I am working with. It has a list of object with another list of objects and it should flatted the ListOfCarModel and build the viewmodel. Any help would be great.
static void Main(string[] args)
{
try
{
List<carmake> carmakes = new List<carmake>();
List<carmodel> carmodel = new List<carmodel>();
carmodel.Add(new carmodel() { Modelid = 1, Model = "S60" });
carmodel.Add(new carmodel() { Modelid = 2, Model = "A4" });
carmodel.Add(new carmodel() { Modelid = 3, Model = "A4s" });
carmakes.Add(new carmake() { Makeid = 1, MakeName = "Volvo",ListOfCarModel= carmodel });
List<carmodel> carmodel2 = new List<carmodel>();
carmodel2.Add(new carmodel() { Modelid = 4, Model = "535d" });
carmodel2.Add(new carmodel() { Modelid = 5, Model = "320d" });
carmodel2.Add(new carmodel() { Modelid = 6, Model = "M5" });
carmakes.Add(new carmake() { Makeid = 2, MakeName = "BMW",ListOfCarModel= carmodel2 });
List<carmodel> carmodel3 = new List<carmodel>();
carmodel2.Add(new carmodel() { Modelid = 4, Model = "Passat" });
carmodel2.Add(new carmodel() { Modelid = 5, Model = "dd" });
carmodel2.Add(new carmodel() { Modelid = 6, Model = "aaa" });
carmakes.Add(new carmake() { Makeid = 3, MakeName = "VW", ListOfCarModel = carmodel3 });
var listOfCars = carmakes.Select(x => new CarViewModel
{
Model = x.MakeName,
//MakeName = x.ListOfCarModel.SelectMany(x.ListOfCarModel)
});.ToList()
}
catch (Exception ex)
{
ex.ToString();
}
}
class carmake
{
public int Makeid { get; set; }
public string MakeName { get; set; }
public List<carmodel> ListOfCarModel { get; set; }
}
class carmodel
{
public int Modelid { get; set; }
public string Model { get; set; }
}
class CarViewModel
{
public string MakeName { get; set; }
public string Model { get; set; }
}
}
Try this:
List<CarViewModel> viewModels = new List<CarViewModel>();
foreach (var make in carmakes)
foreach (var model in make.ListOfCarModel)
viewModels.Add(new CarViewModel() { MakeName = make.MakeName, Model = model.Model });
Or if you want to use LINQ:
List<CarViewModel> viewModels = carmakes
.Select(carmake => carmake.ListOfCarModel.Select(x => new CarViewModel() { MakeName = carmake.MakeName, Model = x.Model }))
.SelectMany(x => x)
.ToList();
I have a question about a LINQ grouping.
I thought that grouping would be a simple matter of using the GroupBy function on the result set and specifying what to group it by. However my items appear to not be grouping together and instead are displaying as if the GroupBy function wasn't there. I want to group by the itemPk, but I'm can't seem to do it. I have tried grouping by both category.ItemFk and Item.Itempk, but no luck. Could someone give me a pointer on this?
var itemIds = items.Select(i => i.ItemId).ToList();
var itemAndCatJoin =
from item in Context.SCS_Items
join category in Context.SCS_ItemCategories
on item.ItemPk equals category.ItemFk
into temp
from category in temp.DefaultIfEmpty()
select new ExportItemTable
{
Category = category,
Item = item
};
return itemAndCatJoin.Where(i => itemIds.Contains(i.Item.ItemPk))
.GroupBy(n => new {n.Item, n.Category})
.Select(i => new ExportableItem
{
ItemPk = i.Key.Item.ItemPk,
Name = i.Key.Item.Name,
Description = i.Key.Item.Description,
Price = i.Key.Item.Price,
Category = i.Key.Category.Category.Category_Name,
GLDepartment = i.Key.Category.GL_Department.Name ?? "",
GLName = i.Key.Category.GL_Name.Name ?? "",
StartDate = i.Key.Item.StartDate,
EndDate = i.Key.Item.EndDate,
FiscalYear = i.Key.Item.SCS_FiscalYear.Name,
School = i.Key.Item.School != null ? i.Key.Item.School.School_Name : i.Key.Item.Board.Board_Name,
Beneficiary = i.Key.Item.SCS_Beneficiary.Name,
Quantity = i.Key.Item.MaxQuantity,
Deleted = i.Key.Item.DeletedFlag,
OptionalStudents = i.Key.Item.SCS_Attachments.Where(a => !a.IsRequired).SelectMany(a => a.SCS_StudentAttachments).Where(s => !s.DeletedFlag).Select(s => s.StudentFk).Distinct().Count(),
RequiredStudents = i.Key.Item.SCS_Attachments.Where(a => a.IsRequired).SelectMany(a => a.SCS_StudentAttachments).Where(s => !s.DeletedFlag).Select(s => s.StudentFk).Distinct().Count(),
IsPublic = i.Key.Item.IsPublic,
AllowRecurring = i.Key.Item.AllowRecurringPayments,
EffectiveCutoff = i.Key.Item.SCS_Attachments.Where(a => !a.DeletedFlag && a.CourseDropCutoff.HasValue).Select(a => a.CourseDropCutoff).OrderBy(a => a).FirstOrDefault(),
CreatedDate = i.Key.Item.CreatedDate
}).OrderBy(i => i.ItemPk).ToList();
}
your groupbyy is indeed doing nothing for you, you need to tell the groupby what to group by....
like
.GroupBy(n => n.Category)
Here is a simple example to your grouping question:
class Program
{
static void Main()
{
var allItems = GetAllItems();
var groups = from item in allItems
group item by item.Category
into newGroup
select newGroup;
foreach (var group in groups)
{
Console.WriteLine($"\nCategory: {group.Key}");
foreach (var item in group)
{
Console.WriteLine($"{item.Name}: {item.Price}");
}
}
Console.ReadLine();
}
static List<Category> GetAllCategories()
{
return new List<Category>()
{
new Category() { Id = 1, Name = "Programming Books" },
new Category() { Id = 2, Name = "Fiction Books" }
};
}
static List<Item> GetAllItems()
{
return new List<Item>()
{
new Item() { Id = 1, Name = "Embedded Linux", Category = 1, Price = 9.9 },
new Item() { Id = 2, Name = "LINQ In Action", Category = 1, Price = 36.19 },
new Item() { Id = 3, Name = "C# 6.0 and the .NET 4.6 Framework", Category = 1, Price = 40.99 },
new Item() { Id = 4, Name = "Thinking in LINQ", Category = 1, Price = 36.99 },
new Item() { Id = 5, Name = "The Book Thief", Category = 2, Price = 7.99 },
new Item() { Id = 6, Name = "All the Light We Cannot See", Category = 2, Price = 16.99 },
new Item() { Id = 7, Name = "The Life We Bury", Category = 2, Price = 8.96 }
};
}
}
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public int Category { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
This example is simple enough for anyone new to LINQ. I am sure you can make some adjustment to make it work for your specific issue. Hope this will help.
Theres links already on how to use multiple models for a view with different ways to do it, however, I tried those and could not get them to work, what am I doing wrong?
I simply want two form inputs in 1 view, and one model, but one of the form inputs uses a list<'model'> and the other uses 'model', here's what I mean:
UPDATE: copy/paste this code, if you select and submit any check box items you will get an error at #Model.input.passWord and I have no idea why, checkbox items wont show either, need help.
View (Index.cshtml):
#using stupidassTests.Models
#model MyViewModel
#{
ViewBag.Title = "Index";
}
<h2>Password Input</h2>
<div>
<p>Enter Password</p>
#using (Html.BeginForm("Index", "Home", FormMethod.Get))
{
#Html.TextBox("password")
<button type="submit" value="Search"></button>
}
<p>#Model.input.passWord</p> <!--passWord is underlined with red because it conflicts with the List'model'-->
</div>
<h2>Checkbox</h2>
<div>
#using (Html.BeginForm())
{
for (var i = 0; i < Model.inputCollection.Count; i++)
{
<p>
#Html.HiddenFor(n => n.inputCollection[i].Id)
#Html.DisplayFor(n => n.inputCollection[i].Name)
#Html.HiddenFor(n => n.inputCollection[i].Name)
#Html.CheckBoxFor(n => n.inputCollection[i].Checked)
</p>
}
<input id="Submit1" type="submit" value="submit" />
if (ViewBag.Values != null)
{
foreach (var item in ViewBag.Values)
{
<p>#item</p>
}
}
}
So as you can see, copy/paste my code and try to run it, 'password' form input is being shoved out by 'checkbox' input, it seems the two '#model' are conflicting under one model class, how do I fix this?
Controller (HomeController.cs):
public ActionResult Index()
{
return View();
}
[HttpGet, ActionName("Index")]
public ActionResult PasswordInput(string password)
{
FormInputs pss = new FormInputs();
pss.passWord = password;
MyViewModel mvm = new MyViewModel() { input = pss, isList = false };
return this.View("Index", mvm);
}
[HttpGet]
public ActionResult CheckBoxGet()
{
var list = new List<FormInputs>
{
new FormInputs { Id = 1, Name = "Aquafina", Checked = false },
new FormInputs { Id = 2, Name = "Mulshi Springs", Checked = false },
new FormInputs { Id = 3, Name = "Alfa Blue", Checked = false },
new FormInputs { Id = 4, Name = "Atlas Premium", Checked = false },
new FormInputs { Id = 5, Name = "Bailley", Checked = false },
new FormInputs { Id = 6, Name = "Bisleri", Checked = false },
new FormInputs { Id = 7, Name = "Himalayan", Checked = false },
new FormInputs { Id = 8, Name = "Cool Valley", Checked = false },
new FormInputs { Id = 9, Name = "Dew Drops", Checked = false },
new FormInputs { Id = 10, Name = "Dislaren", Checked = false },
};
MyViewModel mvm = new MyViewModel() { inputCollection = list, isList = true };
return this.View("Index", mvm);
}
[HttpPost]
public ActionResult CheckBoxPost(List<FormInputs> list)
{
var selected = list.Where(x => x.Checked).Select(x => x.Name);
ViewBag.Values = selected;
MyViewModel mvm = new MyViewModel() { inputCollection = list, isList = true };
return this.View("Index", mvm);
}
Model (FormInputs.cs):
public class MyViewModel
{
public FormInputs input;
public List<FormInputs> inputCollection;
public bool isList;
}
public class FormInputs
{
public string passWord = "";
public int Id { get; set; }
public string Name { get; set; }
public bool Checked { get; set; }
public List<string> checkBox = new List<string>();
}
So just as a summary, because I'm a beginner at MVC, how do I re-work this code (btw copy/paste it) so that both form inputs can co-exist in 1 view?
You can use viewmodel.
Use ViewModel
For view model you have to create a class and in this class you will define all models as properties of this class.Here are two classes.
public class EmployeeDetails
{
[Required]
[Display(Name = "Name")]
public string Name { get; set; }
}
public class Employee
{
public int Id { get; set; }
}
Here is viewmodel
public class ViewModel
{
public Employee emp { get; set; }
public EmployeeDetails empdet{ get; set; }
}
Now in Controller you will do like this
public ActionResult About()
{
ViewModel vm = new ViewModel();
vm.emp = new Employee();
vm.empdet = new EmployeeDetails();
return View(vm);
}
And in view you will receive it like this
#model ViewModel
This might be a good example to use the Composite Pattern. You can have a ViewModel with two properties:
public class MyViewModel{
public FormInputs input;
public List<FormInputs> inputCollection;
public bool isList;
}
And arrange the data accordingly:
public ActionResult PasswordInput(string password)
{
FormInputs pss = new FormInputs();
pss.passWord = password;
MyViewModel mvm = new MyViewModel(){input = pss, isList = false}
return this.View("Index", mvm);
}
AND
public ActionResult CheckBoxGet()
{
var list = new List<FormInputs>
{
new FormInputs { Id = 1, Name = "Aquafina", Checked = false },
new FormInputs { Id = 2, Name = "Mulshi Springs", Checked = false },
new FormInputs { Id = 3, Name = "Alfa Blue", Checked = false },
new FormInputs { Id = 4, Name = "Atlas Premium", Checked = false },
new FormInputs { Id = 5, Name = "Bailley", Checked = false },
new FormInputs { Id = 6, Name = "Bisleri", Checked = false },
new FormInputs { Id = 7, Name = "Himalayan", Checked = false },
new FormInputs { Id = 8, Name = "Cool Valley", Checked = false },
new FormInputs { Id = 9, Name = "Dew Drops", Checked = false },
new FormInputs { Id = 10, Name = "Dislaren", Checked = false },
};
MyViewModel mvm = new MyViewModel(){inputCollection = list , isList = true}
return this.View("Index", mvm);
}
AND in view, use this:
#model MyViewModel
Check the isList property before using the input/inputCollection
I have a drop down box in my view which I would like to alter depending on the ClientID. I don't have a clue where to start with this, I thought about using Javascript but I would rather avoid it as some users could have Javascript turned off.
ViewModel:
public class ReportType {
public int ReportID { get; set; }
public string ReportName { get; set; }
}
public IEnumerable<ReportType> ReportTypeOptions = new List<ReportType>
{
new ReportType {ReportID = 0, ReportName = "Claims by Supplier"},
new ReportType {ReportID = 1, ReportName = "Department Breakdown"},
new ReportType {ReportID = 2, ReportName = "Reason Code Breakdown"},
new ReportType {ReportID = 3, ReportName = "Monthly Debiting Report"},
};
View:
#Html.DropDownListFor(m => m.ReportTypeOptions.First().ReportID, new SelectList(Model.ReportTypeOptions, "ReportID", "ReportName"), "Select Report", new { #class = "GRDropDown", #id = "ReportDD", onchange = "disableFunction()" })
I need help to bind drop-down values from models.
Model.cs
public class BloodGroup
{
public BloodGroup()
{
ActionsList = new List<SelectListItem>();
}
[Display(Name="Blood Group")]
public int Group { get; set; }
public IEnumerable<SelectListItem> ActionsList { get; set; }
}
public class ActionType
{
public int GroupId { get; set; }
public string BloodGroup { get; set; }
}
In the Controller:
List<ActionType> actionType = GetCourses();
bGroup.ActionsList = from action in actionType
select new SelectListItem
{
Text = action.BloodGroup,
Value = ((int)action.GroupId).ToString(),
Selected = action.BloodGroup.Equals("A+")?true:false
};
return view;
public List<ActionType> GetCourses()
{
return new List<ActionType> {
new ActionType () { GroupId = 1, BloodGroup = "A+"},
new ActionType () { GroupId = 2, BloodGroup = "B+"},
new ActionType () { GroupId = 3, BloodGroup = "O+" },
new ActionType () { GroupId = 4, BloodGroup = "AB+" },
new ActionType () { GroupId = 5, BloodGroup = "A-"},
new ActionType () { GroupId = 6, BloodGroup = "B-"},
new ActionType () { GroupId = 7, BloodGroup = "O-" },
new ActionType () { GroupId = 8, BloodGroup = "AB-" }
};
}
It successfully return to view. But in view when bind dropdown it throws an error.
in view
#model MyMVC.Models.BloodGroup
#Html.DropDownListFor(m => m.Group, new SelectList(Model.ActionsList, "Value", "Text",true), "-- Select --")</li>
It returns error.
Object reference not set to an instance of an object.
Model.ActionsList is set a Null.
I don't know why it shows null, though I inherit the model.
I need help on how to bind the SelectList value to dropdown
You need to pass a instance of BloodGroup class to the view in your action method, like below:
public ActionResult YourAction()
{
List<ActionType> actionType = GetCourses();
var model = new BloodGroup()
{
ActionsList = (from action in actionType
select new SelectListItem
{
Text = action.BloodGroup,
Value = ((int) action.GroupId).ToString(),
Selected = action.BloodGroup.Equals("A+")
})
};
return View(model);
}
Then in your view:
#model BloodGroup
#Html.DropDownListFor(m => m.Group, Model.ActionsList,"-- Select --")
Notice
Using above example it'll show you the view without errors, but the selected item in your downdownList will NOT show correctly. For showing the selected item correctly, you need to change the type of Grop property to String, like below:
public class BloodGroup
{
//
[Display(Name = "Blood Group")]
public string Group { get; set; }
//
}
Then use above same action method, make your view like:
#model BloodGroup
#Html.DropDownList("Group", Model.ActionsList, "-- Select --")