I have a model called club and each club has a virtual list property for the members of that club. I am lost as to how to add more members to that list and then save it to my database.
public class Club
{
[Key]
public int ClubID { get; set; }
public string ClubName { get; set; }
public string ClubDescription { get; set; }
//List of Members that are members of this Club
public virtual List<ClubMember> ClubMembers { get; set; }
}//end Club
This is the ClubMember model:
public class ClubMember
{
[Key]
public int MemberId { get; set; }
//First Name
[Display(Name = "First Name")]
public string MemberFName { get; set; }
//Last Name
[Required(ErrorMessage = "You must enter a Last Name")]
[Display(Name = "Last Name")]
public string MemberLName { get; set; }
[Display(Name = "Member Name")]
public string MemberName { get; set; }
public string MemberEmail { get; set; }
//Foreign Key for Club
public int ClubID { get; set; }
[ForeignKey("ClubID")]
public virtual Club Club { get; set; }
}
I am using a wrapper model to get a list of the selected ids for the members that the user wishes to add but I'm not sure if this is needed:
public class NewMemberList //Class used when adding new members to the members list of a club
{
public List<ClubMember> NewMembers { get; set; }
public List<int> SelectedIDs { get; set; }
}
This is what I currently have in my view for adding a member, it just displays a drop-down list with a list of members and a submit button
#model ultimateorganiser.Models.NewMemberList
#{
ViewBag.Title = "Add Members";
}
#using (Html.BeginForm(#Model.SelectedIDs))
{
#Html.AntiForgeryToken()
#Html.ListBoxFor(m => m.SelectedIDs, new MultiSelectList(Model.NewMembers, "UserId", "UserFName", Model.SelectedIDs))
<input type="submit" value="save" />
}
This is the controller method I have. It is not finished as I do not know how to handle the post part so that it gets the list of selected ids and adds all of the data for that member to the members list in the club:
[HttpGet]
public ActionResult AddMembers(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Club club = db.Clubs.Find(id);
if (club == null)
{
return HttpNotFound();
}
List<ClubMember> CurrentMembers = club.ClubMembers;
List<ClubMember> MembersList = new List<ClubMember>();
MembersList = db.ClubMembers.ToList();
ViewBag.CurrentMembersList = CurrentMembers;
return View(new NewMemberList() { NewMembers = MembersList });
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddMembers([Bind(Include = "SelectedIDs")] Club club)
{
if (ModelState.IsValid)
{
//Get selected members and add them to Members list for the club
return RedirectToAction("Index");
}
return View(club);
}
If you have questions or would like to see more of my code just ask.
Your view model should store the ClubId as well since you are adding the new members to a specific Club.
public class AddMembersToClub
{
public string Name { set;get;}
public int ClubId { set;get;}
public List<SelectListItem> Members { set;get;}
public int[] SelectedMembers { set;get;}
}
And in your GET action,
public ActionResult AddMembers(int id)
{
var club = db.Clubs.Find(id);
if (club == null)
{
return HttpNotFound();
}
var vm = new AddMembersToClub { ClubId=id , Name = club.ClubName };
//Here I am getting all the members, If you want a subset, update the LINQ query
vm.Members = db.ClubMembers
.Select(x=> new SelectListItem { Value = x.MemberId.ToString(),
Text=x.MemberFName }).ToList();
return View(vm);
}
and in your view, which is strongly typed to our AddMembersToClub view model. You need to keep the ClubId in a hidden form field as we need that in the HttpPost action.
#model AddMembersToClub
#using(Html.BeginForm())
{
<p>Adding members to #Model.Name</p>
#Html.HiddenFor(s=>s.ClubId)
#Html.ListBoxFor(s => s.SelectedMembers, Model.Members)
<input type="submit" />
}
And in your HttpPost action, Read the SelectedMembers property which is an int array storing the Id's of selected members and using the Id, get the Member entity and udpate the ClubId property.
[HttpPost]
public ActionResult AddMembers(AddMembersToClub model)
{
foreach(var item in model.SelectedMembers)
{
var member = db.ClubMembers.FirstOrDefault(s=>s.MemberId==item);
if(member!=null)
{
member.ClubId = model.ClubId;
}
db.SaveChanges();
}
return ReidrectToAction("Index");
}
Related
I'm building a website in ASP.Net, using MVC, and need to list a set of results
but i get error in the code
model:
public class Customers
{
public int Id { get; set; }
public string Name { get; set; }
public List<Customers> Itemlst { get; set; }
}
controller:
public ActionResult List()
{
Customers itemobj = new Customers();
return View(itemobj);
}
view:
#foreach(var item in Model.Itemlst)
{
<tr>
<td>Items ID:</td>
<td>#item.ID</td>
<td>Items Name:</td>
<td>#item.Name</td>
</tr>
}
</table>
From the NullReferenceException that you are receiving we can see that the issue is because of the Itemlst not being initialised. One of the ways to solve this is just to make sure that there is a valid list when you create the object:
public class Customers
{
public Customers()
{
Itemlst = new List<Customers>();
}
public int Id { get; set; }
public string Name { get; set; }
public List<Customers> Itemlst { get; set; }
}
So you can add values to the list in your action if need:
public ActionResult List()
{
Customers itemobj = new Customers();
var example = new Customers ();
example.Id = 1;
example.Name = "Example";
itemobj.Add();
return View(itemobj);
}
I don't know if you are just using this as an example for your question, but I can't help but notice that there is something weird. You could use something different like:
public class ViewModel // Name to what makes sense to you
{
// Some other properties...
public List<Customer> Customers { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
Or you could just use List<Customer> as your model in the view directly (yes, your model can be a object which is simply a list of objects).
When you pass the Customers list to the view, this list itself is the model.
Change Model.Itemlst —> Model inside the foreach loop.
This will iterate the list of customers.
I want to display both user info and address model in the same view.
These are my code structures:
In Data Access Layer, I have model classes:
User.cs:
public class User
{
[Key]
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string RestaurantName { get; set; }
public string PrimaryPhone { get; set; }
}
Location.cs:
public class Location
{
public int Id { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string ZipCode { get; set; }
public User User { get; set; }
}
So, I have two separate repositories for user and address models which perform add and get all functions which is working perfectly fine.
Now, I want both of this model information should be displayed in the view at the same time.
How can I combine both in the same view. I'm unable to do it. I can do it, but the thing is both are displayed in separate views.
Any advice would be appreciated!
Use a ViewModel. Your ViewModel could look something like this:
public class MyViewModel
{
public User UserVm {get;set;}
public Location LocationVm {get;set;}
}
Use the MyViewModel in your view. Your controller will accept a MyViewModel object.
You can then pass the LocationVm and UserVm objects from your viewModel to your repository.
Add One more Property To your User Model like below
-- Model Section
public class User
{
public List<Location> location {get;set;}
}
-- Controller Section
public ActionResult Index()
{
List<Location> loc= new List<Location>() { new Location{ City = "one" }, new
Location{ City = "two" } };
List<User> user= new List<User>() { new User{ FirstName = "A", location =
loc }, new User{ FirstName = "B" } };
return View(user);
}
-- View Section
#model IEnumerable<YourSolutionName.Models.User>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
#{
if (item.location != null) {
foreach(var i in item.location)
{
<h1>#i.City</h1>
}
}
}
}
This is one approach by using, we can use two different models on same view.
As for demo i added static values you can add dynamic using your context object.
it may help you. Thank You
I'm new to MVC and are having a hard time figuring some "basic" things out.
I have a ViewModel shaped as follows:
public class ProjectViewModel
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
public DateTime CreatedDate { get; set; }
[Required]
[Display(Name = "Final due date")]
public DateTime FinalDueDate { get; set; }
[Required]
[Display(Name = "Attached equipment")]
public Equipment AttachedEquipment { get; set; }
}
In my Create view I would like to be able to select the value for AttachedEquipment from a dropdownlist. I have a table in my database with all the available Equipments.
I know there is an #Html helper #Html.DropDownListFor which serves this very purpose. However I fail to see how I get the values from the database and spit them out into my view.
My ProjectController looks like this:
private AdventureWorks db = new AdventureWorks();
// GET: Project
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult Create()
{
// I'm guessing this is where I need to do some magic
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ProjectViewModel model)
{
if (ModelState.IsValid)
{
var project = new Project
{
Title = model.Title,
Description = model.Description,
CreatedDate = DateTime.Now,
FinalDueDate = model.FinalDueDate,
Equipment = model.Equipment
};
db.Projects.Add(project);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
How do I load the Equipment values from my DB into a dropdownlist in my Create view?
Since you cant bind a dropdownlist to the complex object AttachedEquipment, I would change the view model to include properties for the selected equipment and a SelectList for the options
public class ProjectViewModel
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
public DateTime CreatedDate { get; set; }
[Required]
[Display(Name = "Final due date")]
public DateTime FinalDueDate { get; set; }
[Required(ErrorMessage="Please select equipment)]
public int? SelectedEquipment { get; set; }
public SelectList EquipmentList { get; set; }
}
Controller
public ActionResult Create()
{
ProjectViewModel model = new ProjectViewModel();
// Assumes your Equipments class has properties ID and Name
model.EquipmentList = new SelectList(db.Equipments, "ID", "Name");
return View(model);
}
View
#model ProjectViewModel
#using(Html.BeginForm())
{
....
#Html.DropDownListFor(m => m.SelectedEquipment, Model.EquipmentList, "--Please select--")
....
}
Alternatively you can bind to m => m.AttachedEquipment.ID (assuming Equipment contains property ID)
Let's say I have a model like this (simplified from the original):
public class Location
{
public int ID { get; set; }
public string BinNumber { get; set; }
}
public class Item
{
public int ID { get; set; }
public string Description { get; set; }
public virtual Location Bin { get; set; }
}
public class LineOnPickList
{
public int ID { get; set; }
public virtual Item Item { get; set; }
}
The usual thing to do here on the LineOfPickList Create view would be to have a dropdownlist that listed all the Item Descriptions and put the selected item in the newly created LineOnPickList record when Create was clicked.
What I need to do however is show a dropdownlist of Location BinNumbers, yet still have the Item associated with that Location in the newly created LineOnPickList record.
How would that be done?
Define a view model for your drop down
public class ItemViewModel
{
public int ID { get; set; }
public string BinNumber { get; set; }
}
Then build the drop down list data in your controller action as follows
public class CreateLineOnPickListViewModel
{
public int ItemId { get; set; }
public IEnumerable<ItemViewModel> Items { get; set; }
}
public ActionResult Create()
{
var model = new CreateLineOnPickListViewModel();
model.Items = db.Items
.Select(i => new ItemViewModel { ID = i.ID, BinNumber = i.Bin.BinNumber });
return View(model);
}
Then in your view
#model CreateLineOnPickListViewModel
#Html.DropDownListFor(m => m.ItemId, new SelectList(Model.Items, "ID", "BinNumber"), "-")
Then your post action method in your controller would look like this
public ActionResult Create(CreateLineOnPickListViewModel model)
{
var item = new Item { ID = model.ItemID };
db.Items.Attach(item);
var lineOnPickList = new LineOnPickList { Item = item };
db.SaveChanges();
return View(model);
}
I have the following 2 entities:
public class Product
{
[Key]
public int ID { get; set; }
[Required]
public string Name { get; set; }
public virtual Category Category { get; set; }
}
public class Category
{
[Key]
public int ID { get; set; }
[Required]
public string Name { get; set; }
public ICollection<Product> Products { get; set; }
}
and a view model
public class ProductCreateOrEditViewModel
{
public Product Product { get; set; }
public IEnumerable<Category> Categories { get; set; }
}
The create view for Product uses this ViewModel. The category ID is set as follows in the view:
<div class="editor-field">
#Html.DropDownListFor(model => model.Product.Category.ID,new SelectList
(Model.Categories,"ID","Name"))
#Html.ValidationMessageFor(model => model.Product.Category.ID)
</div>
When the form posts I get an instance of the view model with a product and the selected category object set but since the "Name" property of Category has a [Required] attribute the ModelState is not valid.
As far as creating a Product goes I don't need or care for the "Name" property. How can I get model binding to work such that this is not reported as a ModelState error?
You should create a correct ViewModel for your View.
The best approach imo is not to expose your domain entities to the view.
You should do a simple DTO flattening from your entities to your viewmodel.
A class like that
public class ProductViewModel
{
public int ID { get; set; }
[Required]
public string Name { get; set; }
public int CategoryId? { get; set; }
public SelectList Categories { get; set; }
}
From your controller you map the product to your viewmodel
public ViewResult MyAction(int id)
{
Product model = repository.Get(id);
//check if not null etc. etc.
var viewModel = new ProductViewModel();
viewModel.Name = model.Name;
viewModel.CategoryId = model.Category.Id;
viewModel.Categories = new SelectList(categoriesRepo.GetAll(), "Id", "Name", viewModel.CategoryId)
return View(viewModel);
}
Then in the action that respond to the post, you map back your viewModel to the product
[HttpPost]
public ViewResult MyAction(ProductViewModel viewModel)
{
//do the inverse mapping and save the product
}
I hope you get the idea