Cannot Access ViewModel Class member inside razor view - asp.net-mvc-4

I cannot access a member of my class inside the view. All other members are accessible.
The following member "ListOfCategories" is not available in intellisense or at run time inside the view.
Error: There is no ViewData item of type 'IEnumerable' that has the key 'ListOfCategories'
My ViewModelClass
public class ArticleEditViewModel
{
public int ID { get; set; }
[Required]
public string Title { get; set; }
public List<Category> ListOfCategories = new List<Category>();
}
My Razor View
#model rrrr.ViewModels.Article.ArticleEditViewModel
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_LayoutSecure.cshtml";
}
<div>
#Html.ActionLink("Back to Articles", "Index")
</div>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.ID)
<div class="tableHeader">
<h2>Update Article</h2>
</div>
<table id="RegistrationForm">
<tbody>
<tr>
<td>Title</td>
<td>
#Html.TextBoxFor(model => model.Title, new { #class = "registerinput" })
</td>
<td class="leftWarning">
#Html.ValidationMessageFor(model => model.Title)
</td>
</tr>
<tr>
<td>Category</td>
<td>
#Html.DropDownList(model => model.ListOfCategories, Model.CategoryID)
</td>
<td class="leftWarning">
#Html.ValidationMessageFor(model => model.CategoryID)
</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" value="Update Article" class = "css_button_4" />
</td>
</tr>
</tbody>
</table>
}

Use DropdownListFor instead. The code will be something like this:
#Html.DropDownListFor(model => model.CategoryId, Model.ListOfCategories.Select(c => new SelectListItem { Text = c.CategoryName, Value = c.CategoryId }))

Related

How to show contents from other Models in my view using .NET Core 6?

I have an Index view that should display the name of each person's course, however, in the model used there is only the Course Id, the course name is in another model - CursosModel - and in another table in the database. How can I display the course name in my view?
Index view:
#model IEnumerable<FeedbackUnivicosa.Models.Professor>
#{
ViewData["Title"] = "Professores";
}
<h4>#ViewData["Title"]</h4>
<form asp-action="Index" method="get">
<div class="form-actions no-color">
<p>
<input type="text" name="SearchString" class="inputSearch" value="#ViewData["CurrentFilter"]" />
<button type="submit" class="botaoSearch fa fa-solid fa-magnifying-glass"></button>
<a asp-action="Index"><i class="espacoFiltro fa fa-solid fa-filter-circle-xmark"></i></a>
<a asp-action="Create" class="botaoCadastro btn btn-primary btn-sm">Cadastrar</a>
</p>
</div>
</form>
<table class="table">
<thead>
<tr>
<th></th>
<th>
<a asp-action="Index" asp-route-sortOrder="#ViewData["NameSortParm"]">Professor</a>
</th>
<th>
<a asp-action="Index" asp-route-sortOrder="#ViewData["EmailSortParm"]">Email</a>
</th>
<th>
<a asp-action="Index" asp-route-sortOrder="#ViewData["CursoSortParm"]">Curso</a>
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td class="fa-lg">
<a asp-action="Edit" asp-route-id="#item.Id"><i class="espacoIcone fa-solid fa-user-pen"></i></a>
<a asp-action="Delete" asp-route-id="#item.Id"><i class="espacoIcone fa-solid fa-trash-can"></i></a>
</td>
<td>
#Html.DisplayFor(modelItem => item.Nome)
</td>
<td>
#Html.DisplayFor(modelItem => item.EmailProfessor)
</td>
<td>
#Html.DisplayFor(modelItem => item.CursoId)
</td>
</tr>
}
</tbody>
</table>
I am trying to show the course name on the Index view.
From your description of this question, I think you can inject your DBContext into your view and get the value of course name from CursosModel table, Please refer to this simple demo:
Model:
public class CursosModel
{
public int id { get; set; }
public string CursoName { get; set; }
}
public class Professor
{
public int Id { get; set; }
public string Name { get; set; }
public int CourseId { get; set; }
}
Then in the view, You can inject dbcontext into your view then get the course Name by Professor's CourseId.
#using xxxx;
#model IEnumerable<Professor>
#inject ApplicationDbContext dbcontext
#foreach (var item in Model)
{
<tr>
<td class="fa-lg">
<a asp-action="Edit" asp-route-id="#item.Id"><i class="espacoIcone fa-solid fa-user-pen"></i></a>
<a asp-action="Delete" asp-route-id="#item.Id"><i class="espacoIcone fa-solid fa-trash-can"></i></a>
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.CourseId)
</td>
<td>
#dbcontext.cursosModels.Where(x => x.id == item.CourseId).Select(y => y.CursoName).FirstOrDefault();
</td>
<br>
</tr>
}
Demo:
because the Microsoft website teaches Add the model
so after you can reference the Microsoft site.
reference Microsoft website
public class CursosModel
{
public List<CursosModel> CursosModel { get; set; }
public List<Course> Course{ get; set; }
}

Space generated in action string

I am building a Asp.Net Core 2.1 EF MVC solution.
Instead of writing separate lines for each CRUD button (Edit, Create, Delete) in each of my Index views, I am trying to generate the buttons dynamically from a partial view as follows.
Models/AdmSchool
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace FACEZ.Models
{
public partial class AdmSchool
{
[Display(Name = "Id")]
public int AdmSchoolId { get; set; }
[Required]
[MaxLength(10)]
[Display(Name = "Code")]
public string AdmSchoolCode { get; set; }
[Required]
[MaxLength(100)]
[Display(Name = "School Name")]
public string AdmSchoolDescr { get; set; }
[MaxLength(100)]
[Display(Name = "Generic Email Principal")]
public string EmailPrincipal { get; set; }
[MaxLength(100)]
[Display(Name = "Generic Email Accounts")]
public string EmailAccounts { get; set; }
[MaxLength(100)]
[Display(Name = "Generic Email Registrar")]
public string EmailRegistrar { get; set; }
[Display(Name = "Obsolete")]
public bool Obsolete { get; set; }
}
}
Views/Shared/_IndividualButtonPartial
#model FACEZ.Models.IndividualButtonPartial
<a type="button" class="btn btn-sm #Model.ButtonType"
href="#Url.Action(Model.Action) #Model.ActionParameters">
<span class="glyphicon glyphicon-#Model.Glyph"></span>
<span class="sr-only">#Model.Text</span>
</a>
Views/Shared/_TableButtonPartial
#model FACEZ.Models.IndividualButtonPartial
<td style="width: 150px;">
<div class="btn-group" role="group">
#await Html.PartialAsync("_IndividualButtonPartial",
new IndividualButtonPartial {
Action="Edit",
ButtonType="btn-primary",
Glyph = "pencil",
Text = "Edit",
Id=Model.Id
})
#await Html.PartialAsync("_IndividualButtonPartial",
new IndividualButtonPartial {
Action="Details",
ButtonType="btn-success",
Glyph = "list",
Text = "Details",
Id=Model.Id
})
#await Html.PartialAsync("_IndividualButtonPartial",
new IndividualButtonPartial {
Action="Delete",
ButtonType="btn-danger",
Glyph = "trash",
Text = "Delete",
Id=Model.Id
})
</div>
</td>
Areas/Adm/Views/AdmSchools/Index.cshtml
#using Microsoft.EntityFrameworkCore.SqlServer.Query.ExpressionTranslators.Internal
#model IEnumerable<FACEZ.Models.AdmSchool>
#{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<div class="form-border">
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.AdmSchoolCode)
</th>
<th>
#Html.DisplayNameFor(model => model.AdmSchoolDescr)
</th>
<th>
#Html.DisplayNameFor(model => model.EmailPrincipal)
</th>
<th>
#Html.DisplayNameFor(model => model.EmailAccounts)
</th>
<th>
#Html.DisplayNameFor(model => model.EmailRegistrar)
</th>
<th>
#Html.DisplayNameFor(model => model.Obsolete)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.AdmSchoolCode)
</td>
<td>
#Html.DisplayFor(modelItem => item.AdmSchoolDescr)
</td>
<td>
#Html.DisplayFor(modelItem => item.EmailPrincipal)
</td>
<td>
#Html.DisplayFor(modelItem => item.EmailAccounts)
</td>
<td>
#Html.DisplayFor(modelItem => item.EmailRegistrar)
</td>
<td>
#Html.DisplayFor(modelItem => item.Obsolete)
</td>
<td>
#await Html.PartialAsync("_TableButtonPartial", new IndividualButtonPartial {Id=item.AdmSchoolId})
#* I am trying to replace the following code with the line above
<a asp-action="Edit" asp-route-id="#item.AdmSchoolId">Edit</a> |
<a asp-action="Details" asp-route-id="#item.AdmSchoolId">Details</a> |
<a asp-action="Delete" asp-route-id="#item.AdmSchoolId">Delete</a>
*#
</td>
</tr>
}
</tbody>
</table>
When I run the app, I can see the school info in the Index view.
However, the action link that is being created, is getting a space in it from somewhere?
like https://localhost:44399/Adm/AdmSchools/Edit /1 instead of
like https://localhost:44399/Adm/AdmSchools/Edit/1
How can i remove the space after the action name.
In your _IndividualButtonPartial you do have a space between #Url.Action(Model.Action) and #Model.ActionParameters. This is what is getting reflected.

Value of HttpFileCollectionBase Isnull on Postback

I'm curious instead of using HTTPFileWrapper, i created a model with HttpFileCollectionBase type of property.
public class UserLoginModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "password")]
public string Password { get; set; }
public HttpFileCollectionBase Resume { get; set; }
}
My View
#using (Html.BeginForm("", "User", FormMethod.Post, new { enctype = "multipart/form-data", #class = "form-horizontal" }))
{
// #Html.AntiForgeryToken()
<table>
<tr>
<td>
#Html.LabelFor(x => x.UserName)
</td>
<td>
#Html.EditorFor(x => x.UserName)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(x => x.Password)
</td>
<td>
#Html.EditorFor(x => x.Password)
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="login" onclick="return Upload();">
</td>
</tr>
<tr>
<td colspan="2">
#Html.TextBoxFor(x => x.Resume, new { type = "file" })
</td>
</tr>
<tr>
<td colspan="2">
#Html.ValidationSummary(true)
</td>
</tr>
</table>
}
And my Controller for postback
[HttpPost]
public ActionResult Index(UserLoginModel obj)
but when I checked the value of model.Resume on the controller the value was null. what could be the reason for that? thanks
You using the wrong class. Your property needs to be HttpPostedFileBase
public class UserLoginModel
{
....
public HttpPostedFileBase Resume { get; set; }
}

Can't get the binding object in a Form

In a ASP.NET MVC 4 project, I create a Model Class named Task with its CRUD and in the index page wich list the tasks I need to modify each line separatly. So I create a form in each line. But when I submit a line I don't get the object Task in the action in the controller.
Here is the code :
Thanks
Controller
public ActionResult Index()
{
ViewBag.projectVersionList = this.getProjectVersionList();
ViewBag.taskTypeList = this.getTaskTypeList();
ViewBag.durationList = this.getDurationList();
return View(db.Tasks.ToList());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(Task task)//task est instancié mais les propriétées sont vides
{
task.User = db.UserProfiles.Find(WebSecurity.CurrentUserId);
if (ModelState.IsValid)
{
db.Entry(task).State = EntityState.Modified;
db.SaveChanges();
}
return View(task);
}
View
#model IEnumerable<TimeSheet.Models.Task>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<div class="responsive-table-line">
<table class="table table-striped" data-card-view="true">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Date)
</th>
<th>
#Html.DisplayNameFor(model => model.UserId)
</th>
<th>
#Html.DisplayNameFor(model => model.ProjectVersionId)
</th>
<th>
#Html.DisplayNameFor(model => model.TaskTypeId)
</th>
<th>
#Html.DisplayNameFor(model => model.Duration)
</th>
<th>
#Html.DisplayNameFor(model => model.Accomplished)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
#Html.EditorFor(m => item)
}
</tbody>
</table>
</div>
Editor Template :
#model TimeSheet.Models.Task
#using (Ajax.BeginForm(new AjaxOptions
{
HttpMethod = "POST"
}))
{
#Html.AntiForgeryToken()
<tr>
<td data-title="#Html.DisplayNameFor(model => model.Date)">
#Html.HiddenFor(m => m.TaskId)
<div class="form-group">
#Html.TextBoxFor(m => m.Date, new { #class = "datefield form-control", type = "date" })
</div>
</td>
<td data-title="#Html.DisplayNameFor(model => model.UserId)">
#Html.DisplayFor(m => m.User.UserName)
</td>
<td data-title="#Html.DisplayNameFor(model => model.ProjectVersionId)">
<div class="form-group">
#Html.DropDownListFor(m => m.ProjectVersionId, (IEnumerable<SelectListItem>)ViewBag.projectVersionList, new { #class = "form-control" })
</div>
</td>
<td data-title="#Html.DisplayNameFor(model => model.TaskTypeId)">
<div class="form-group">
#Html.DropDownListFor(m => m.TaskTypeId, (IEnumerable<SelectListItem>)ViewBag.taskTypeList, new { #class = "form-control" })
</div>
</td>
<td data-title="#Html.DisplayNameFor(model => model.Duration)">
<div class="form-group">
#Html.DropDownListFor(m => m.Duration, (IEnumerable<SelectListItem>)ViewBag.durationList, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Duration)
</div>
</td>
<td data-title="#Html.DisplayNameFor(model => model.Accomplished)">
#Html.CheckBoxFor(m => m.Accomplished)
</td>
<td data-title="">
<button type="submit" class="btn btn-default glyphicon glyphicon-floppy-disk" aria-label="Left Align"></button>
#Html.ActionLink(" ", "Edit", new { id = Model.TaskId }, new { #class = "btn btn-default glyphicon glyphicon-edit" })
<button type="button" class="btn btn-default" aria-label="Left Align">
<span class="glyphicon glyphicon-align-left" aria-hidden="true"> #Html.ActionLink(" ", "Details", new { id = Model.TaskId })</span>
</button>
<button type="button" class="btn btn-default" aria-label="Left Align">
<span class="glyphicon glyphicon-trash" aria-hidden="true"> #Html.ActionLink(" ", "Delete", new { id = Model.TaskId })</span>
</button>
</td>
</tr>
}
Thanks ! I've found the pb : The fields in each forms are names "items.[propertyName]" instead of "[propertyName]".I replace in the view item by model like this
#foreach (var model in Model)
{
#Html.EditorFor(m => model)
}
And in EditorTemplace m by model
model => model.Accomplished
Thanks!

model item passed into the dictionary is of type PagedList.PagedList[] but this dictionary requires a model item of type

Im trying to use view models in my project but I have this error:
The model item passed into the dictionary is of type
'PagedList.PagedList1[ContosoUniversity.Models.Course]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[ContosoUniversity.ViewModels.CourseViewModel]'.
Controller:
public ActionResult Index(int? page)
{
int pageNumber = page ?? 1;
var courses = courseService.GetAll();
var coursesViewList = Mapper.Map<IEnumerable<Course>, IEnumerable<CourseViewModel>>(courses);
var model = coursesViewList.ToPagedList(pageNumber, PageSize);
return View(model);
}
View:
#model IEnumerable<ContosoUniversity.ViewModels.CourseViewModel>
#using PagedList.Mvc;
#using PagedList;
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Credits)
</th>
<th>
Students
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Credits)
</td>
<td>
#string.Join(",", item.Enrollments.Select(e => e.Student.FullName))
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.CourseID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.CourseID })
</td>
</tr>
}
</table>
#Html.PagedListPager((IPagedList)Model, page => Url.Action("Index", new { page }))
Could somebody help me to resolve a problem please?
You are passing Model of type PagedList.PagedList1<ContosoUniversity.Models.Course> while your View is strongly typed with IEnumerable<ContosoUniversity.ViewModels.CourseViewModel>.
You need to pass IEnumerable<T> from action or set Model of View to PagedList<T> or you can overcome this issue by wrapping it inside a ViewModel in following way:
public class CoursesVM
{
public PagedList.IPagedList<CourseViewModel> Courses { get; set; }
}
In action:
public ActionResult Index(int? page)
{
int pageNumber = page ?? 1;
var courses = courseService.GetAll();
var coursesViewList = Mapper.Map<IEnumerable<Course>, IEnumerable<CourseViewModel>>(courses);
var model = new CoursesVM();
model.Courses = coursesViewList.ToPagedList(pageNumber, PageSize);
return View(model);
}
and in View:
#model ContosoUniversity.ViewModels.CoursesVM
#using PagedList.Mvc;
#using PagedList;
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Credits)
</th>
<th>
Students
</th>
<th></th>
</tr>
#foreach (var item in Model.Courses) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Credits)
</td>
<td>
#string.Join(",", item.Enrollments.Select(e => e.Student.FullName))
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.CourseID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.CourseID })
</td>
</tr>
}
</table>