I have joined two tables(Projects, Task_Distribution) and pass the values to View as viewbag. But I can't access the value in view(such as: #item.Project_Id) and if I write like #item it displays the result like This image
How can I access only the value?
here is my controller code:
public class TableController : Controller
{
// GET: Table
public ActionResult Table()
{
Database_testEntities1 db1 = new Database_testEntities1();
List<Project> p = new List<Project>();
List<Task_Distribution> t = new List<Task_Distribution>();
var query = (from PI in db1.Projects join TI in
db1.Task_Distribution on PI.Project_Id equals TI.Project_Id select new { PI.Project_Id, TI.Employee_Id }).ToList();
ViewBag.table = query;
return View();
}
}
And this is my view
#{
ViewBag.Title = "Table";
}
<h2>Table</h2>
<table>
#foreach (var item in ViewBag.table)
{
<tr>
<td>
#item
</td>
</tr>
}
</table>
Can you guys give me a solution, please?
See this part of your LINQ expression,
select new { PI.Project_Id, TI.Employee_Id }
You are projecting the result to an anonymous object. So what you have in the ViewBag is a list of these anonymous objects. When you loop through them and executes the code #item, razor will call the ToString method on that which renders the property name and values(which is what you are seeing)
You can create a view model to represent this data and do a projection using that
public class ProjectEmployeeVm
{
public int ProjectId { set;get;}
public int EmployeeId { set;get;}
}
Now in your LINQ expression,
select new ProjectEmployeeVm { ProjectId = PI.Project_Id,EmployeeId = TI.Employee_Id }
Now in your view,you can use cast your viewbag item to a list of this view model
#foreach (var item in ViewBag.table as List<ProjectEmployeeVm>)
{
<p>#item.ProjectId<p>
<p>#item.EmployeeId <p>
}
Also now since you have a view model, why not use that to transfer data to view instead of using dynamic view bag which is prone to errors.
var items = (from PI in db1.Projects join TI in
db1.Task_Distribution on PI.Project_Id equals TI.Project_Id
select new ProjectEmployeeVm { ProjectId = PI.Project_Id,
EmployeeId = TI.Employee_Id
}).ToList();
return View(items);
Now in your view,
#model List<ProjectEmployeeVm>
#foreach (var item in Model)
{
<p>#item.ProjectId<p>
<p>#item.EmployeeId <p>
}
Related
For the task I have to download several items from several xml documents (RssReader) then display random 4 elements on the page. I have already done all the code, the only problem is that the page displays the same 4 items, if I set the trap in the debuggeer in the view/controller everything loads correctly. I do not know what the problem may be, it's my beginnings in ASP.NET for all the clues to the code, thank you very much!
View code:
<table class="table">
#foreach (var item in Model)
{
<tr>
<td>
#item.Title
</td>
<td>
#item.PubDate
</td>
</tr>
}
</table>
Model Code:
public class RssItem
{
public string Title { get; set; }
public string PubDate { get; set; }
}
Controller Code:
public class PortfolioController : Controller
{
// GET: Portfolio
public ActionResult Index()
{
var linkList = new List<string> {
"https://news.google.com/rss?hl=pl&gl=PL&ceid=PL:pl",
"https://news.google.com/rss?hl=pl&gl=PL&ceid=PL:pl",
"https://news.google.com/rss?hl=pl&gl=PL&ceid=PL:pl",
"https://news.google.com/rss?hl=pl&gl=PL&ceid=PL:pl"
};
List<RssItem> rssItems = new List<RssItem>();
List<RssItem> randomRSS = new List<RssItem>();
foreach (string linkRss in linkList)
{
XElement xml = XElement.Load(linkRss);
var query = xml.Descendants("item").Select(item =>
new RssItem
{
Title = item.Element("title").Value,
PubDate = item.Element("pubDate").Value,
}).ToList();
foreach (var item in query)
{
rssItems.Add(item);
}
}
for (int i = 0; i < 4; i++)
{
Random random = new Random();
int randomInt = random.Next(rssItems.Count);
randomRSS.Add(rssItems[randomInt]);
}
return View(randomRSS);
}
}
Without traps in debugger:
With traps in view and controller (debugger mode):
Why do four requests? You can take the items from a single request and display random 4. But in order for Random to work it needs to be outside the for loop.
Random random = new Random();
for (int i = 0; i < 4; i++)
{
int randomInt = random.Next(rssItems.Count);
randomRSS.Add(rssItems[randomInt]);
}
But you could still end up with duplicates if you do not remove the rss from the list since random can create duplicates, see this answer for solutions
Random number generator with no duplicates
I have the following IQueryable object:
var user = from d in _context.Users
join userRole in _context.UserRoles on d.Id equals userRole.UserId
join role in _context.Roles on userRole.RoleId equals role.Id
where role.Name == "Liquidador"
select d;
Which then is send as a ViewBag to the View:
ViewBag.UserID = new SelectList(user.AsNoTracking(), "UserName", "Name", selectedUser);
The Problem:
I need to add a new Item to the result of the IQueryable. So I've proceeded like this:
var UserNameList = user.Select(s => new { s.Name, s.UserName }).ToList();
However, I'm missing something when I'm trying to add the new item:
UserNameList.Insert(0, new *NewWhat?* { Name = "Liquidador", UserName = "--Select--"} );
Usually I declare a new element of a specific model but in this case I don't know which model to declare for this IQueryable. Any recomendations?
Thanks
EDIT:
The IQueryable object goes to the Get Method of the View as part of a function:
public async Task<IActionResult> Management()
{
PopulateUserDropDownList();
var Tiendas = await _context.Stores.ToListAsync();
StoreEmployee model = new StoreEmployee
{
Stores = Tiendas
};
return View(model);
}
This list is then presented in a dropdownlist, inside a table:
<td class="col-md-2">
<div class="form-group" form="#(String.Format("{0}{1}","form",item.StoreID))">
<div>
<select asp-for="#item.Usuario" class="form-control" asp-items="ViewBag.UserId" form="#(String.Format("{0}{1}","form",item.StoreID))"></select>
<span asp-validation-for="#item.Usuario" class="text-danger"></span>
</div>
</div>
</td>
It seems it would be cleaner if you define a class UserDTO (or any other name that likes you more)
public class UserDTO
{
public string Name { get; set; }
public string UserName { get; set; }
}
and then you do
var UserNameList = user
.Select(s => new UserDTO { Name = s.Name, UserName = s.UserName })
.ToList();
UserNameList.Insert(0, new UserDTO { Name = "Liquidador", UserName = "--Select--"} );
OTOH... smells a little to add the empty element as part of the data array, my recommendation is to handle that on razor view and just send UserNameList with real data. Dropdown razor methods contains overloads to specify the empty element text.
If you show your HTML, we may help you to implement a better solution.
So I have this little "Restaurant" webapp going on where I'm trying to construct a View-page where an user can click on a created (restaurant) table (dropdown that refreshes automatically after clicking) and check what dishes are ordered on that table. At the bottom, the user will find the total price.
My view works 100% fine but ONLY if I have 1 table in the database. If I have multiple tables (restaurant tables) (created in my DropCreate-Seed method), the view will only show the dropdown with available tables, not the dishes inside of them.
What could cause this problem?
CODE
TABLE
public class Table
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual List<Dish> Dishes { get; set; }
}
SEED METHOD
context.Tables.Add(new Table { Id = 1 ,Name = "table1", Dishes = context.Dishes.ToList() });
context.Tables.Add(new Table { Id = 2, Name = "table2", Dishes = context.Dishes.ToList() });
context.Tables.Add(new Table { Id = 3, Name = "table3", Dishes = context.Dishes.ToList() });
context.SaveChanges();
TABLE CONTROLLER
public ActionResult Order(int? tableID)
{
//Create a ViewBag variable contained with all the tables (show name)
List<table> tableL = db.tables.ToList();
List<SelectListItem> tableSL = new List<SelectListItem>();
foreach (var table in tableL)
{
TableSL.Add(new SelectListItem { Text = table.Name.ToLower(), Value = table.Name.ToString() });
}
ViewBag.tableL = tableSL;
//At the start or at problems, get the first table and return it
if (tableID == null || db.tables.Find(tableID) == null)
{
return View(db.tables.First());
}
else
{
Table l = db.tables.Find(tableID);
return View(l);
}
}
VIEW
#model VBExamenTEST.Models.Table
#{
ViewBag.Title = "Order";
}
<h2>Order</h2>
#using (Html.BeginForm("Bedien", "Bedien", FormMethod.Post))
{
#Html.DropDownList("tableID", (List<SelectListItem>)ViewBag.TableL, new {onchange = "this.form.submit()" });
}
#if(Model != null)
{
double total = 0;
<table>
<tr>
#foreach(var g in Model.Dishes)
{
total += g.Price;
<td>
#Html.DisplayFor(Model=>g.Name)
</td>
}
</tr>
</table>
<p>Total:#total euro </p>
}
So my code works perfectly if I only have one table added in my DB, whenever I add more, only the dropdown shows up, the dishes are not shown on click, and the total equals 0.
Where can my problem be situated?
I have a SelectList in my action method. The selected value for SelectList is coming from the action method parameter. The action and view are simple like below:
// Recipe Action
public ActionResult Recipe(int? recipeId)
{
ViewBag.RecipeID = new SelectList(_recipsRecipes, "RecipeID", "RecipeName", recipeId);
return View(new Recipe());
}
//Recipe View
#model RecipeDemo.Models.Recipe
#Html.DropDownList("RecipeID", (SelectList)ViewBag.RecipeID, string.Empty)
I'm using ActionLink below to call the Recipe action.
#Html.ActionLink("Recipe", "Recipe", "Home", new { recipeId = 2 }, null)
It works like I expect, the DropDownList is showing the selected value as the No. 2 (recipeId = 2) item.
Problem
When I change the Recipe action parameter by using route id, like below:
//Recipe View
public ActionResult Recipe(int? id)
{
ViewBag.RecipeID = new SelectList(_recipsRecipes, "RecipeID", "RecipeName", id);
return View(new Recipe());
}
//Recipe View (Same View as above)
#model RecipeDemo.Models.Recipe
#Html.DropDownList("RecipeID", (SelectList)ViewBag.RecipeID, string.Empty)
And I'm using ActionLink below to call the Recipe action.
#Html.ActionLink("Recipe", "Recipe", "Home", new { id = 2 }, null)
The DropDownList is NOT showing the selected value, (id = 2) item. The selection is instead empty.
But I have the correct id value in the SelectList. see below:
Why is this, does anyone know the explanation?
Update:
The model is below:
public class Recipe
{
public int RecipeID { get; set; }
public string RecipeName { get; set; }
}
Well that was certainly interesting. After first confirming the issue with the code you provided, I experimented around and believe I have the root cause. Basically, you are using the same variable name way to often and the model binder appears to be getting confused. You have RecipeId in your route, RecipeId in your View Model and RecipeId as the name of your view bag variable. By altering my variable names, the SelectList works as expected.
The primary issue is naming your SelectList RecipeId which matches a property in your model. When you send the new Recipe(), the model binder is attempting to use that value. In your first example, since you have RecipeId defined in the URL, it is getting it from there. In the second example, there is no RecipeId to pull from the URL and it is null in the model.
Controller
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
private List<Recipe> Recipes;
public HomeController()
{
Recipes = new List<Recipe>
{
new Recipe {RecipeId = 1, RecipeName = "Test - 1"},
new Recipe {RecipeId = 2, RecipeName = "Test - 2"},
new Recipe {RecipeId = 3, RecipeName = "Test - 3"},
};
}
public ActionResult Index(int? id)
{
ViewBag.MyList = new SelectList(Recipes, "RecipeID", "RecipeName", id);
return View(new Recipe());
}
}
}
Index View
#model MvcApplication1.Models.Recipe
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#Html.DropDownList("MyRecipeId", (SelectList)ViewBag.MyList)
Basically, vary your parameter names a little bit more to help prevent the model binder from getting confused and/or pulling information from the wrong place.
You can verify this in your second example by sending this in your return statement:
Return View(New Recipe{RecipeId = 3});
The option value with 3 will be selected regardless of what the actual Id sent was.
EDIT
An even better option would be to do what I said to do as an example above. By changing your Action to this:
public ActionResult Index(int? id)
{
ViewBag.MyList = new SelectList(Recipes, "RecipeID", "RecipeName");
return View(new Recipe(RecipeId = id));
}
You can leave your view unchanged. Now, the SelectList will pull from the model that you are sending.
I have a pretty simple scenario and I'm sure I'm just missing something obvious. I'm trying to use a ListBox to grab multiple Id's and add them to my model, but no matter what I do, the collection is always null. Here's the code:
The model collections:
public IEnumerable<Model.UserProfile> TravelBuddies { get; set; }
public IEnumerable<int> SelectedTravelBuddies { get; set; }
I populate the TravelBuddies collection in my controller.
The view code:
<div class="module_content">
#if (Model.TravelBuddies.Count() > 0)
{
#Html.ListBoxFor(m => m.SelectedTravelBuddies, new MultiSelectList(Model.TravelBuddies, "Id", "FullName"))
}
else
{
<span>You don't currently have any travel buddies (people who were with you on this trip). Don't worry, you can add some to this trip later if you'd like.</span>
}
</div>
The select list is populated in my view. No problem there. But once I select multiple items and submit my form, the Model.SelectedTravelBuddies collection is always null. Am I missing something obvious? It's been a long night of coding.
Update: Added Controller Code
[HttpGet]
public ActionResult New()
{
Model.Trip trip = new Model.Trip();
ITripService tripService = _container.Resolve<ITripService>();
IUserAccountService userService = _container.Resolve<IUserAccountService>();
int userProfileId = userService.GetUserProfile((Guid)Membership.GetUser().ProviderUserKey).Id;
trip.TripTypes = new SelectList(tripService.GetTripTypes(), "Id", "Name");
trip.TravelBuddies = userService.GetTravelBuddies(userProfileId);
tripService.KillFlightLegTempStorage();
return View(trip);
}
[HttpPost]
public ActionResult New([Bind(Exclude = "TripTypes")] Model.Trip trip)
{
ITripService tripService = _container.Resolve<ITripService>();
if (!ModelState.IsValid)
{
tripService.KillFlightLegTempStorage();
return View(trip);
}
int tripId = tripService.CreateTrip(trip, (Guid)Membership.GetUser().ProviderUserKey);
tripService.KillFlightLegTempStorage();
return RedirectToAction("Details", "Trip", new { id = tripId });
}
Ok so you are binding to SelectedTravelBuddies. When your list is rendered, what is it's name? It's been a long night for me too :) want to make sure it matches the model. Also are you sure the list is in the form element so they are posted?