passing a Dictionary<string, List<model>> model to a view - c#

Unclear on how to pass this model to my view.
I have a list model being passed into my view. But I want to separate the Participant's inside the list depending on which User is logged in on the ViewBag.
current view code (working):
this code works as it should but its not separating the participants depending on what user is logged in. it displays the entire list. I'm getting red squilies under #model, League inside my foreach line, and MMLeagueParticipants in my secondforeach. But it still worked.
error:
when I hovered over #model and League:
The type or namespace name 'League' could not be found (are you missing a using directive or an assembly reference?)[LeagueProect]
When I hovered over MMLeagueParticipant:
The type or namespace name 'MMLeagueParticpant' could not be found (are you missing a using directive or an assembly reference?`
//RED SQUIGLY #1 #model
#model List<League>
#{
if (Model != null && Model.Any())
{
//RED SQUIGLY #2 League
foreach(League i in Model)
{
//RED SQUIGLY #3 MMLeagueParticipant
foreach (MMLeagueParticipant mmLeagueParticipant in i.allParticipants)
{
<p>#mmLeagueParticipant.child.ParticipantFirstName #mmLeagueParticipant.child.ParticipantLastName</p>
}
}
}
else
{
<p>the list is empty</p>
}
}
Attempt to separate (not working)
still using #model List<League>.
When I change my code to try and separate it crashes entirely
<p>Your kid(s):</p>
if (Model != null && Model.Any())
{
foreach(League i in Model)
{
var userParticipants = i.allParticipants.Where(p => p?.child?.Parent?.UserId == ViewBag.UserId).ToList();
foreach (MMLeagueParticipant mmLeagueParticipant in userParticipants)
{
<p>#mmLeagueParticipant.child.ParticipantFirstName #mmLeagueParticipant.child.ParticipantLastName</p>
}
}
}
<p>not your kid(s):</p>
if (Model != null && Model.Any())
{
foreach(League i in Model)
{
var userParticipants = i.allParticipants.Where(p => p?.child?.Parent?.UserId != ViewBag.UserId).ToList();
foreach (MMLeagueParticipant mmLeagueParticipant in userParticipants)
{
<p>#mmLeagueParticipant.child.ParticipantFirstName #mmLeagueParticipant.child.ParticipantLastName</p>
}
}
}
The error I get from trying this:
NullReferenceException: Object reference not set to an instance of an object.
It doesn't like the lines:
var userParticipants = i.allParticipants.Where(p => p.child.Parent.UserId == ViewBag.UserId).ToList();
#await Html.PartialAsync("_Displayeach", Model["bbM7and8"])
I'm assuming the way I'm passing in the model to my view is incorrect. But entirely unsure why one way is working and the other isn't.
Controller details:
in my controller I have a list of age groups that i add new participant models to.
Then I pass the list to my RosterPageBasketball view.
Inside that view I have 12 tabs; each displaying differnt lists depending on the age group.
model used in RosterPageBacketball: #model List<League>
Each tab in the RosterPageBasketball that displays different agegroups:
#await Html.PartialAsync("_Displayeach", Model["bbM7and8"])
_displayeach is my Current view code
The tabs were working as needed when showing all Participants with my Current view code (as showed above) with their own list of different age groups when I wasn't sperating the participants depending on if they belong to the logged on user or not.
each tab in my RosterPageBasketballcontains the following code: #await Html.PartialAsync("_Displayeach", Model["bbM#and#"])
where I thought the issue might be:
("_Displayeach", Model["bbM7and8"])
the model I'm sending to my partial is Model["bbM7and8"] but the model I'm using in my _Displayeach is #model List<League>. unsure how or if it's possible to pass in #model Dictionary<string, List<League>>.
controller:
public async Task<IActionResult> GetBasketballRoster()
{
String[] leagueNames = new[]
{
"bbM7and8",
"bbM9and10",
"bbM11and12",
"bbM13and14",
"bbM15and16",
"bbM17and18",
"bbF7and8",
"bbF9and10",
"bbF11and12",
"bbF13and14",
"bbF15and16",
"bbF17and18"
};
Dictionary<string, List<League>> d = new Dictionary<string, List<League>>();
foreach (var name in leagueNames)
{
List<League> bbLeagues = await db.Leagues
.Where(l => l.sport == "Basketball")
.Where(l => l.ageRange==name)
.ToListAsync();
foreach (League league in bbLeagues)
{
List<MMLeagueParticipant> leagueParticipants = await db.Entry(league)
.Collection(l => l.allParticipants)
.Query() // <-- This is needed to allow for `Include()`
.Include(mmp => mmp.child)
.ToListAsync();
}
d.Add(name,bbLeagues);
}
return View("RosterPageBasketball", d);
}
Dictionary<string, List> d is passed to the RosterpageBasketball
_Displayeach view is passes a model["bbM#and#"]
_Displayeach view uses #model List<League>

From your code, it seems you want to display List<League> which is in partial view for specific ageRange.
Here is a working demo you could follow:
Model:
public class League
{
public string sport { get; set; }
public string ageRange { get; set; }
public List<MMLeagueParticipant> allParticipants { get; set; }
}
public class MMLeagueParticipant
{
public child child { get; set; }
}
public class child
{
public string ParticipantFirstName { get; set; }
public string ParticipantLastName { get; set; }
}
RosterPageBasketball.cshtml:
#model Dictionary<string, List<League>>
#{
var data = Model.Where(a => a.Key == "bbF17and18").Select(a => a.Value).FirstOrDefault();
}
#await Html.PartialAsync("_Displayeach", data)
_Displayeach.cshtml:
#model List<League>
#{
if (Model != null && Model.Any())
{
foreach (League i in Model)
{
foreach (MMLeagueParticipant mmLeagueParticipant in i.allParticipants)
{
<p>#mmLeagueParticipant.child.ParticipantFirstName #mmLeagueParticipant.child.ParticipantLastName</p>
}
}
}
else
{
<p>the list is empty</p>
}
}
Controller:
public async Task<IActionResult> Index()
{
String[] leagueNames = new[]
{
"bbM7and8",
"bbM9and10",
"bbM11and12",
"bbM13and14",
"bbM15and16",
"bbM17and18",
"bbF7and8",
"bbF9and10",
"bbF11and12",
"bbF13and14",
"bbF15and16",
"bbF17and18"
};
Dictionary<string, List<League>> d = new Dictionary<string, List<League>>();
foreach (var name in leagueNames)
{
//hard coded the data....
List<League> bbLeagues = new List<League>()
{
new League(){sport="Basketball",ageRange="bbF17and18",allParticipants =new List<MMLeagueParticipant>(){ new MMLeagueParticipant() { child= new child() {ParticipantFirstName="San",ParticipantLastName="Da" } } } },
new League(){sport="Basketball",ageRange="bbF17and18",allParticipants =new List<MMLeagueParticipant>(){ new MMLeagueParticipant() { child= new child() {ParticipantFirstName="Api",ParticipantLastName="Ee" } } }},
new League(){sport="Basketball",ageRange="bbF9and10",allParticipants =new List<MMLeagueParticipant>(){ new MMLeagueParticipant() { child= new child() {ParticipantFirstName="May",ParticipantLastName="Fa" } } }},
new League(){sport="Basketball",ageRange="bbM17and18",allParticipants =new List<MMLeagueParticipant>(){ new MMLeagueParticipant() { child= new child() {ParticipantFirstName="Ben",ParticipantLastName="He" } } }},
new League(){sport="Basketball",ageRange="bbF15and16",allParticipants =new List<MMLeagueParticipant>(){ new MMLeagueParticipant() { child= new child() {ParticipantFirstName="Jun",ParticipantLastName="Pa" } } }},
new League(){sport="FootBall",ageRange="bbF15and16",allParticipants =new List<MMLeagueParticipant>(){ new MMLeagueParticipant() { child= new child() {ParticipantFirstName="Pen",ParticipantLastName="Me" } } }}
};
var data = bbLeagues.Where(l => l.sport == "Basketball").Where(l => l.ageRange == name).ToList();
d.Add(name, data);
}
return View("Index", d);
}

Related

ASP.NET MVC - HTML Error "No ViewData of Type IEnumerable<SelectListItem>"

It's just a simple application that allows me to add music to a database via a HTML form.
What is happening is when I try to submit the data to be committed into the DB, I get this error:
System.InvalidOperationException: There is no ViewData item of type
'IEnumerable' that has the key 'Genre'.
This error is appearing on the HTML page and from my assumptions, is passing a NULL value instead of the what I have chosen.
Music service class:
public void AddMusic(MusicGenreArtist musicGenreArtist, string userID)
{
Music newMusic = new Music()
{
Title = musicGenreArtist.Title,
num_track = musicGenreArtist.num_track,
duration = musicGenreArtist.duration,
DateReleased = musicGenreArtist.DateReleased,
Price = musicGenreArtist.Price,
Image = musicGenreArtist.Image
};
using (var context = new ForestContext())
{
musicDAO.AddMusic(newMusic, context);
Genre genre = genreDAO.GetGenre(musicGenreArtist.Genre, context);
genreDAO.AddMusicToCollection(newMusic, genre, context);
Artist artist = artistDAO.GetArtist(musicGenreArtist.Artist, context);
artistDAO.AddMusicToCollection(newMusic, artist, context);
userDAO.AddMusicToCollection(newMusic, userID, context);
}
}
Genre DAO:
public Genre GetGenre(Music music, ForestContext context)
{
IList<Genre> genres = GetGenres(context);
for (int i = 0; i < genres.Count; i++)
{
if (genres[i].Musics.Contains<Music>(music))
{
return genres[i];
}
}
return null;
}
DAO for music:
public void AddMusic(Music music, ForestContext context)
{
context.Musics.Add(music);
context.SaveChanges();
}
Music Controller:
public ActionResult AddMusic()
{
Helper helper = new Helper();
ViewBag.genreList = helper.GetGenreDropDown();
ViewBag.artistList = helper.GetArtistDropDown();
return View();
}
// POST: AddMusic/Create
[HttpPost]
public ActionResult AddMusic(MusicGenreArtist musicGenreArtist)
{
try
{
// TODO: Add insert logic here
musicService.AddMusic(musicGenreArtist, "user");
return RedirectToAction("GetGenre", "Genre",
new { id = musicGenreArtist.Genre });
}
catch
{
return View();
}
}
Helper controller for dropdown:
public class Helper
{
private IGenreService genreService;
private IArtistService artistService;
public Helper()
{
genreService = new GenreService();
artistService = new ArtistService();
}
public List<SelectListItem> GetGenreDropDown()
{
List<SelectListItem> genreList = new List<SelectListItem>();
IList<Genre> genres = genreService.GetGenres();
foreach (var item in genres)
{
genreList.Add
(
new SelectListItem()
{
Text = item.Name,
Value = item.ID.ToString(),
Selected = (item.Name == (genres[0].Name) ? true : false)
}
);
}
return genreList;
}
public List<SelectListItem> GetArtistDropDown()
{
List<SelectListItem> artistList = new List<SelectListItem>();
IList<Artist> artists = artistService.GetArtists();
foreach (var item in artists)
{
artistList.Add
(
new SelectListItem()
{
Text = item.Name,
Value = item.ID.ToString(),
Selected = (item.Name == (artists[0].Name) ? true : false)
}
);
}
return artistList;
}
}
}
Genre Model:
public class Genre
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Music> Musics { get; set; }
}
HTML:
<div class="form-group">
#Html.LabelFor(model => model.Genre, htmlAttributes: new { #class = "control-label col-md-2"
})
<div class="col-md-10">
#Html.DropDownListFor(model => model.Genre, (List<SelectListItem>)ViewBag.genreList)
#Html.ValidationMessageFor(model => model.Genre, "", new { #class = "text-danger" })
</div>
</div>
The model you are sending in your view and the one you are waiting for in your controller doesn't match.
Your view use the model Genre
But your controller :
public ActionResult AddMusic(MusicGenreArtist musicGenreArtist)
is waiting for MusicGenreArtist
Please double check this

Iterating over a session variable in view

I am wondering how can an iterate over a session , to which I am assigning a list of string in an action method.
I want to display each of the elements in the session as links via the for loop.
Any help is appreciated.
Here is my index method :
public ActionResult Index()
{
Session["num"] = Posts;
//Posts = new List<string> { "element1", "element2", "element3" };
return View();
}
And here is my view :
<h2>Index</h2>
#foreach (#item c in #Session["num"])
{
}
You will need to cast your session variable since it's an object.
Something like...
#{
var posts = Session["num"] as List<string>;
if (posts != null) {
foreach (var item in posts) {
...
}
}
}
You have tagged this question as asp.net-mvc, why not take advantage of the framework?
Model
class MyModel
{
public List<string> Posts { get; set; }
}
View (Index.cshtml)
#model MyModel
<h2>Index</h2>
#foreach(var post in Model.Posts)
{
<span>#post</span>
}
Controller
public ActionResult Index()
{
var model = new MyModel();
model.Posts = Posts; //Posts = new List<string> { "element1", "element2", "element3" };
return View(model);
}

I want to show viewbag list

in my class menu code and description name
namespace Test.Controllers
{
class menus
{
public string Idmenus { get; set; }
public string desname { get; set; }
}
}
in my controller I want to add data to object List
var viewdes = db.menudescriptions.Where(w => w.Idmenu == mids).ToList();
var desc = new List<menus>();
foreach (var b in viewdes) {
desc.Add(new menus { Idmenus = b.Iddesmenu });
desc.Add(new menus { desname = b.descriptionname });
}
if ((desc.Count != 0))
{
ViewBag.Id = desc.ToList();
}
I want to show ViewBag.Id To Viewpage?
#if (ViewBag.Id != null)
{
<td>
#foreach (var per in `enter code here`)
{
#Html.ActionLink(#per.ToString(), "detail", new { mides = per })
}
</td>
}
You basically just need to iterate your ViewBag.Id like what you normally do when using foreach
#foreach(var per in ViewBag.Id as List<menus>)
{
#Html.ActionLink(per.desname, "detail", new { mides = per })
}

ViewData Int32 must be of type IEnumerable in MVC

I am getting an error that I cant seem to fix:
"The ViewData item that has the key 'posts.Id' is of type
'System.Int32' but must be of type 'IEnumerable'."
ViewModel/PostViewModel
namespace MyBlogger.ViewModel
{
public class PostsViewModel
{
public Post posts { get; set; }
public IEnumerable<SelectListItem> Tags { get; set; }
private List<int> _selectedPostTags;
public List<int> SelectedPostTags
{
get
{
if (_selectedPostTags == null)
{
_selectedPostTags = posts.Tags.Select(m => m.Id).ToList();
}
return _selectedPostTags;
}
set { _selectedPostTags = value; }
}
}
}
PostController: (Manually Setting the Id for now)
public ActionResult EditPostTag(int id = 12)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var postsViewModel = new PostsViewModel
{
posts = db.Posts.Include(i => i.Tags).First(i => i.Id == id),
};
if (postsViewModel.posts == null)
return HttpNotFound();
var tagsList = db.Tags.ToList();
postsViewModel.Tags = tagsList.Select(o => new SelectListItem
{
Text = o.Name,
Value = o.Id.ToString()
});
ViewBag.UserID =
new SelectList(db.BlogUsers, "Id", "Email", postsViewModel.posts.Id);
return View(postsViewModel);
}
You have
#Html.DropDownListFor(m => m.posts.Id, (SelectList)ViewBag.Id, Model.posts.Id);
but your controller method does not assign a SelectList to a ViewBag property named Id, hence it it null in the view, which results in that exception.
You need to assign the value of ViewBag.Id to a SelectList before you return the view, although since you are using a view model, I recommend you include a property public SelectList PostsList { get; set;} in your view model and assign it to that instead and use it as
#Html.DropDownListFor(m => m.posts.Id, Model.PostsList);
Side note: Its not clear what you think the 3rd parameter (Model.posts.Id) of your current usage is doing (its for generating a null value label option)

ASP MVC View posts null to Controller

I am a beginner in ASP MVC, and, after a lot of help from SO, am progressing through ViewModels. Using a ViewModel however, I have encountered the following error.
Given the following View:
#model November.ViewModels.Staff_Salutation_VM
//...
using (Html.BeginForm("UpdateStaff", "Settings", FormMethod.Post,
new { #class = "clearfix parameter-form update-parameter update-staff", enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
//...
#for (int i = 0; i < Model.AvailableStaffMembers.Count; i++)
{
var staff = Model.AvailableStaffMembers[i];
<tr>
<td>#Html.HiddenFor(model => staff.ID)#Html.ValueFor(model => staff.ID)</td>
<td>
#Html.DropDownListFor(
model => model.SalutationID, Model.AvailableSalutations.Select(option => new SelectListItem
{
Text = option.Desc.ToString(),
Value = option.ID.ToString(),
Selected = (option.ID.ToString() == staff.SalutationID.ToString())
}
),
"Choose...")
</td>
<td>#Html.EditorFor(model => staff.FName)</td>
<td>#Html.EditorFor(model => staff.LName)</td>
<td>#Html.EditorFor(model => staff.Active)</td>
<td>Delete</td>
</tr>
}
and the following Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using November.Models;
using November.ViewModels;
using November.DAL;
//...
//GET
var staffCreateViewModel = new Staff_Salutation_VM();
staffCreateViewModel.AvailableSalutations = new List<Prm_Salutation>();
var activeSalts = (from a in db.Prm_Salutations
where a.Active == true
orderby a.Desc ascending
select a);
staffCreateViewModel.AvailableSalutations = activeSalts.ToList();
staffCreateViewModel.AvailableStaffMembers = new List<Prm_Staff>();
var activeStaff = (from a in db.Prm_Staffs
where a.Active == true
orderby a.LName ascending
select a);
staffCreateViewModel.AvailableStaffMembers = activeStaff.ToList();
return View("StaffMembers", staffCreateViewModel);
//POST
public ActionResult UpdateStaff(Staff_Salutation_VM list)
{
if (ModelState.IsValid)
{
foreach (var formData in list) //no longer works due to dropping List<>
{
var tbl = db.Prm_Staffs.Where(a => a.ID.Equals(formData.ID)).FirstOrDefault();
if (tbl != null)
{
var Prm_StaffModel = new Prm_Staff();
Prm_StaffModel.SalutationID = formData.SalutationID;
Prm_StaffModel.FName = formData.FName;
Prm_StaffModel.LName = formData.LName;
Prm_StaffModel.Active = formData.Active;
}
}
db.SaveChanges();
ViewBag.UpdateRtrn = "Successfully Updated.";
return RedirectToAction("Parameters", new { param = "Staff Members" });
}
else
{
ViewBag.UpdateRtrn = "Failed ! Please try again.";
return RedirectToAction("Parameters", new { param = "Staff Members" });
}
}
return RedirectToAction("Parameters", new { param = "Staff Members" });
}
And, for good measure, the ViewModel itself:
public class Staff_Salutation_VM
{
public int ID { get; set; }
public int SalutationID { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public bool Active { get; set; }
public List<Prm_Salutation> AvailableSalutations { get; set; }
public List<Prm_Staff> AvailableStaffMembers { get; set; }
public Staff_Salutation_VM() { }
}
When triggered, no form values populate the ActionResult, resulting in a Object reference not set to an instance of an object. exception being thrown when the foreach (var formData in list) line is reached. Debugging shows list as being null. How can this be so? Or rather, what am I doing wrong?
EDIT: the list variable in my POST ActionResult is now getting data - or at least, is showing the various types in the class when debugged. How do I then iterate through it to save that data in the appropriate rows of the DB?
I totally missed the method signature, sorry! Your initial view load passes a model Staff_Salutation_VM but your UpdateStaff (form posted) is expecting List<Staff_Salutation_VM>. These are different animals. Change public ActionResult UpdateStaff(List<Staff_Salutation_VM> list) to public ActionResult UpdateStaff(Staff_Salutation_VM staff) just to see if you get past the null ref exception. Note, you'll need to remove your foreach since you don't have an IEnumerable coming in.
I hope this post will be helpful for you.
Model Binding To A List

Categories