I have a ViewModel that displays a list of values in a Razor table. I want to add a dropdownlistfor to filter the table data before the displaying it. I have found various posts on binding a ddl to a list, but they all suggest the format #Html.DropDownListFor(x => Model.field) for the DDL control. Unfortunately, when I type Model. my InteliSense type-ahead list does not show my view model list.
Any help would be greatly appreciated.
My model is:
public class HoursView
{
[Key]
public int HoursID { get; set; }
[Display(Name = "Company ID:")]
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public int EmployeeID { get; set; }
public string EmployeeName { get; set; }
[Display(Name = "Week Ending Date:")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
[Required]
public DateTime? WeekEndingDate { get; set; }
[Display(Name = "Hours Worked:")]
[Required]
public decimal? HoursWorked { get; set; }
[Display(Name = "Tips:")]
[Required]
public decimal? Tips { get; set; }
[Display(Name = "Tips-Cash:")]
[Required]
public decimal? Tips_Cash { get; set; }
public IEnumerable<SelectListItem> Companies { get; set; }
}
My controller "GET" code is:
var requiresHours =
from company in _context.Company
join employee in _context.Employees
on company.CompanyID equals employee.CompanyID
join hours in _context.EmployeeHours
on employee.EmployeeID equals hours.EmployeeID
into hourEmployeees
from subHours in hourEmployeees.DefaultIfEmpty()
where (employee.EmployeeType == "Hourly" || employee.EmployeeType == "Tips") &&
(employee.EmployeeStatus == "Active")
orderby employee.CompanyID, employee.EmployeeID
select new HoursView
{
CompanyID = company.CompanyID,
CompanyName = company.CompanyName,
EmployeeID = employee.EmployeeID,
EmployeeName = employee.EmployeeName,
WeekEndingDate = subHours == null ? dateEndingWeek : subHours.WeekEndingDate,
HoursWorked = subHours == null ? 0 : subHours.HoursWorked,
Tips = subHours.Tips == null ? 0 : subHours.Tips,
Tips_Cash = subHours.Tips_Cash == null ? 0 : subHours.Tips_Cash,
Companies = (from company in _context.Company select new SelectListItem
{
Value = company.CompanyID.ToString(),
Text = company.CompanyName
}).ToList()
};
return View(await requiresHours.ToListAsync());
My Razor code is (including the line that doesn't work):
#model IEnumerable<MvcPayroll.Models.HoursView>
#{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
#using (Html.BeginForm("Index","EmployeeHours",FormMethod.Post))
{
#Html.DropDownListFor(x => Model.
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.CompanyID)
</th>
<th>
#Html.DisplayNameFor(model => model.EmployeeID)
</th>
<th>
#Html.DisplayNameFor(model => model.WeekEndingDate)
</th>
<th>
#Html.DisplayNameFor(model => model.HoursWorked)
</th>
<th>
#Html.DisplayNameFor(model => model.Tips)
</th>
<th>
#Html.DisplayNameFor(model => model.Tips_Cash)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.CompanyName)
</td>
<td>
#Html.DisplayFor(modelItem => item.EmployeeName)
</td>
<td>
#Html.DisplayFor(modelItem => item.WeekEndingDate)
</td>
<td>
#Html.EditorFor(modelItem => item.HoursWorked)
</td>
<td>
#Html.EditorFor(modelItem => item.Tips)
</td>
<td>
#Html.EditorFor(modelItem => item.Tips_Cash)
</td>
</tr>
}
</tbody>
</table>
<p><input type="submit" value="Save" /></p>
<p style="color:green; font-size:12px;">
#ViewBag.Message
</p>
}
Thanks,
David
I never could get this to work. I resorted to using a ViewBag with the collection. This was recommended in a number of posts on saw on the topic of populating drop-down lists on this site.
Related
I want to create a view to return a list of all user with their role. The following is my controller code:
public async Task<ActionResult> Index()
{
var model = await _userManager.Users
.Select(u => new UserViewModel()
{
Id = u.Id,
UserName = u.UserName,
Email = u.Email,
FullName = u.FullName,
Roles = _userManager.GetRolesAsync(u).Result
})
.ToListAsync();
//var model = _context.Users.Include(u => u.Roles).ToList();
return View(model);
}
My view model
public class UserViewModel
{
public string? Id { get; set; }
public string? UserName { get; set; }
[EmailAddress]
public string? Email { get; set; }
[StringLength(50)]
[Display(Name = "Full Name")]
public string? FullName { get; set; }
public IList<string>? Roles { get; set; }
}
My view
#model IEnumerable<WebApp.ViewModels.UserViewModel>
#{
ViewData["Title"] = "Index";
int i = 0, j = 0;
}
<h1>Index</h1>
<a asp-area="Admin" asp-controller="Account" asp-action="Create">Create account</a>
<a asp-area="Admin" asp-controller="Account" asp-action="ResetPwd">Reset Password</a>
<table class="table table-striped">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">UserName</th>
<th scope="col">Full Name</th>
<th scope="col">Roles</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
#foreach (var user in Model)
{
{ i++; j++; }
<tr>
<th scope="row">#i</th>
<td>#user.UserName</td>
<td>#user.FullName</td>
<td>
#string.Join(", ", user.Roles)
</td>
<td class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="actions-dropdown-#j" data-bs-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
Actions
</button>
<div class="dropdown-menu dropdown-menu-end bg-light" aria-labelledby="actions-dropdown-#j">
<a class="dropdown-item text-danger" asp-area="Admin" asp-controller="Account" asp-action="ResetPwd" asp-route-id="#user.Email">
Reset Password
</a>
</div>
</td>
</tr>
}
</tbody>
</table>
The following is Program.cs code:
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebApp.Data;
using WebApp.Models;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddControllersWithViews();
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
await SeedData.Initializer(services, app.Configuration);
}
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
// In general, routes with areas should be placed earlier in the route table
// as they're more specific than routes without an area.
endpoints.MapControllerRoute(
name: "areas",
pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
app.MapRazorPages();
app.Run();
This code is work on local, but when I publish to Azure, an exception occur. I found the problem is related to Roles = _userManager.GetRolesAsync(u).Result of my controller (I posted above). If I remove this line, the exception is disappear.
In ASP.NET Framework, by working with property Roles of 'Users', I can access the user roles easily, but in ASP.NET Core this property is hidden. So, could everyone know a convenient way to resole my problem?
I have a view where I displayed all the records from Requests table. Every record has a save and remove button, so the user can add or remove a request to/from ReqHistory table.
How can I get the data (ID, Title, Description .etc) of each record, from the request view, and pass it to my add/remove actions in ReqHistoryController?
When I submit the form, it won't take the data of the record from the view.
Can anybody help me?
#model IEnumerable<App.Models.Request>
#foreach (var item in Model)
{
<form asp-action="AddReqToHistory" asp-controller="ReqHistory">
<div class="card border-dark mb-3" style="max-width: 30rem;">
<div class="card-header">
#item.Title
</div>
<div class="card-body text-dark">
<img class="imageThumbnail" src="~/images/#item.ImagePath" asp-append-version="true" alt="image" />
<p class="card-text">
<br />
#item.Description
</p>
<a asp-action="Details" asp-route-id="#item.ID" >
Details
</a>
<input asp-action="AddReqToHistory" asp-controller="ReqHistory" type="submit" value="Save" />
<input asp-action="EliminateReqFromHistory" asp-controller="ReqHistory" type="submit" value="Eliminate" />
</div>
</div>
</form>
}
Here are the two actions from ReqHistoryController:
public async Task<IActionResult> AddReqToHistory([Bind("ID, Title,Description,ImagePath")] Request model)
{
var currentUser = await _userManager.GetUserAsync(User);
var userId = await _userManager.GetUserIdAsync(currentUser);
var newReqHistory = new ReqHistory()
{
UserId = userId,
RequestId = model.ID,
Title = model.Title,
Description = model.Description,
CategoryID = model.CategoryID,
PersonID = model.PersonID,
ImagePath = model.ImagePath
};
_context.Add(newReqHistory);
await _context.SaveChangesAsync();
return RedirectToAction("Index", "Requests");
}
// POST
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EliminateReqFromHistory(int requestId)
{
var reqHistory = await _context.ReqHistory.FindAsync(_userManager.GetUserId(User), requestId); //ReqHistory has a composite PK
_context.ReqHistory.Remove(reqHistory);
await _context.SaveChangesAsync();
return RedirectToAction("Index", "Requests");
}
ReqHistory model class:
public class ReqHistory
{
[Key]
public string UserId { get; set; }
[Key]
public int RequestId { get; set; }
public ICollection<Request> Requests { get; set; } //1-M relationship
public string Title { get; set; }
public string Description { get; set; }
public string ImagePath { get; set; }
//one-to-one relationship
public int CategoryID { get; set; }
public Category Category { get; set; }
public int PersonID { get; set; } //FK
public Person Person { get; set; } //nav property
}
Here is the ReqHistory view:
#model IEnumerable<App.Models.ReqHistory>
<table class="table table-condensed table-bordered">
<tr>
<th>
#Html.DisplayNameFor(model => model.RequestId)
</th>
<th>
#Html.DisplayNameFor(model => model.UserId)
</th>
...........................
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#item.RequestId
</td>
<td>
#item.UserId
</td>
..................
</tr>
}
</table>
<a asp-action="AddReqToHistory" asp-controller="ReqHistory" type="submit" value="Save" asp-route-HEREID="#model.ID" />
<a asp-action="EliminateReqFromHistory" asp-controller="ReqHistory" type="submit" value="Eliminate" asp-route-HEREID="#model.ID" />
you can pass id through asp-route by url method.
Scenario
I am going to create a simple interface to insert donations from students using Asp.net Core MVC and EF. According to the App, before entering donation I have to display student information (from Student table) by using student's Admission number (Add_No).
Then I have to insert donation data using the same view but using a different submit button to the table Welfare.
Problem:
I tried it as following ways as shown in my code blocks. Insertion is successful. But I couldn't show student info on the screen even though I retrieve them.
Code for View.cshtml
#model Student_Management.Models.Welfare
#{
ViewData["Title"] = "Wcreate";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h4 align="center">Welfare Donation Entry Form</h4>
<hr />
<table>
<tr>
<td>
#using (Html.BeginForm("getStudentInfo", "Payments", FormMethod.Post))
{
<div class="form-group">
<label asp-for="Add_No" class="control-label"></label>
<input asp-for="Add_No" class="form-control" id="t1" name="A" />
<span asp-validation-for="Add_No" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="getStudentInfo" class="btn btn-primary" id="btngetStudentInfo" />
</div>
}
</td>
<td>
<ul>
#if (ViewBag.students != null)
{
#foreach (var std in ViewBag.students)
{
<li>
#std
</li>
}
}
</ul>
</td>
</tr>
</table>
Code for Controller
public class PaymentsController : Controller
{
private readonly ConnectionString _context;
public PaymentsController(ConnectionString context)
{
_context = context;
}
public IActionResult Wcreate(Welfare welfare, string A)
{
int maxR_No = _context.Welfare.Max(p => p.R_No);
maxR_No = maxR_No + 1;
welfare.R_No = maxR_No;
if (ModelState.IsValid)
{
_context.Add(welfare);
_context.SaveChanges();
ModelState.Clear();
}
return View();
}
public ActionResult getStudentInfo(string A)
{
var items = _context.Students.Where(x => x.Add_No == A)
.Select(x => new
{
P1 = x.F_Name,
P2 = x.Class + "-" + x.ClassNo
});//.ToList();
ViewData["students"] = items;
return RedirectToAction("Wcreate");
}
namespace Student_Management.Models
{
public class Welfare
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int R_No { get; set; }
[Required]
public string Add_No { get; set; }
[Required]
public string Grade { get; set; }
[Required]
public string STClassNo { get; set; }
[Required]
public string Month { get; set; }
[Required]
public string Year { get; set; }
[Required]
public string Rs { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime Date { get; set; }
public string cmt { get; set; }
As hint given by Jasen, I modified my action method and view as follows.
<td>
#using (Html.BeginForm("getStudentInfo", "Payments", FormMethod.Post))
{
<div class="form-group">
<label asp-for="Add_No" class="control-label"></label>
<input asp-for="Add_No" class="form-control" id="t1" name="A" />
<span asp-validation-for="Add_No" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="getStudentInfo" class="btn btn-primary" id="btngetStudentInfo" />
</div>
}
</td>
<p>#TempData["info"]</p>
<p>#(TempData["info2"] +"-" + TempData["info3"])</p>
Action method
public ActionResult getStudentInfo(string A)
{
var items = _context.Students.Where(x => x.Add_No == A)
.Select(x => new
{
P1 = x.F_Name,
P2 = x.Class,
p3=x.ClassNo
}).ToList();
TempData["info"] = items[0].P1;
TempData["info2"] = items[0].P2;
TempData["info3"] = items[0].p3;
return RedirectToAction("Wcreate");
}
I tried write some little system on PostgreSQL and ASP.NET Core. And i need a function of download file, which keeping on database.
Here's code
namespace WebApplication4.Entites
{
public class Documents : BaseEntity
{
public Guid DocumentId { get; set; } = new Guid();
public String DocumentName { get; set; }
public byte[] Contents { get; set; }
public String DocumentIntroNumber { get; set; }
public DateTime DateIntro { get; set; }
}
}
Here's controller
namespace WebApplication4.Controllers
{
public class DocumentsController : Controller
{
private readonly DocumentsRepository dRepository;
private string connectionString;
public DocumentsController(IConfiguration configuration, IConfiguration iconfiguration)
{
dRepository = new DocumentsRepository(configuration);
connectionString = iconfiguration.GetValue<string>("DBInfo:ConnectionString");
}
internal IDbConnection Connection
{
get
{
return new NpgsqlConnection(connectionString);
}
}
public IActionResult Index()
{
return View(dRepository.FindAll());
}
// GET:/Documents/GetFile/1
public FileStreamResult GetFile(string FileID)
{
return GetFile(new Guid(FileID));
}
public FileStreamResult GetFile(Guid id)
{
using (IDbConnection dbConnection = Connection)
{
dbConnection.Open();
DynamicParameters dynamicParameters = new DynamicParameters();
Documents result = dbConnection.Query<Documents>("SELECT * FROM selectdocument(#DocumentId)", new { DocumentId = id }).FirstOrDefault();
Stream stream = new MemoryStream(result.Contents);
return new FileStreamResult(stream, result.DocumentName);
}
}
}
}
And Index.cshtml
model IEnumerable<WebApplication4.Entites.Documents>
#{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Добавить новый документ</a>
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.DocumentName)
</th>
<th>
#Html.DisplayNameFor(model => model.DocumentIntroNumber)
</th>
<th>
#Html.DisplayNameFor(model => model.DateIntro)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.DocumentName)
</td>
<td>
#Html.DisplayFor(modelItem => item.DocumentIntroNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.DateIntro)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.DocumentId">Edit</a> |
<a asp-action="#Url.Action("GetFile","Documents",new {DocumentId = item.DocumentId})">Загрузить файл</a>
</td>
</tr>
}
</table>
But system give a error on web page
Page localhost not found
No address page found
http://localhost:59494/Documents/%2FDocuments%2FGetFile%3FDocumentId%3D00000000-0000-0000-0000-000000000000
Please, help me resolve this problem. Or tell me, where i am making a mistake?
Maybe (actually I'm sure) it's me, but I cannot seem to figure out how to retrieve list items as part of a model object. The post here seems to satisfy everyone but neither answer is relatable in my limited understanding.
I need to get the items that are checked so I can update the Db. Sounds simple.
My Model:
public class UserAdminModel
{
public Guid UserId { get; set; }
public string UserName { get; set; }
public List<UserRole> UserRoles { get; set; }
public string csvAllRolls { get; set; }
}
public class UserRole
{
public Guid RoleId { get; set; }
public string UserRoleName { get; set; }
public bool UserisinRole { get; set; }
}
My View:
<% using (Html.BeginForm("UpdateRoles", "UserAdmin", FormMethod.Post))
{%>
<input type="hidden" id="UserId" name="UserId" value="<%: Model.UserId %>" />
...
<% foreach (var role in Model.UserRoles)
{ %>
<tr>
<td> </td>
<td colspan="2" nowrap="nowrap"><%: role.UserRoleName %></td>
<td> </td>
<td>
<input type="checkbox" id="UserRoles" name="UserRoles" value="<%: role.UserRoleName %>"
<% if (role.UserisinRole) { %>
checked="checked"
<% } %>
/></td>
</tr>
<% } %>
...
<input type="submit" name="Submit" value="Update Roles" /></td>
<% } %>
My Controller:
[HttpPost]
public ActionResult UpdateAllRoles(UserAdminModel model)
{
Guid uid = new Guid( Request["UserId"]);
return RedirectToAction("Index", "MyController");
}
The UserId comes through fine but the rest of the model is null. Any help would be appreciated.
You need to use a for loop so that your form controls have the correct name attributes to bind to your model (I'll leave it to you to convert from razor to aspx)
#using (Html.BeginForm("UpdateRoles", "UserAdmin", FormMethod.Post))
{
#Html.HiddenFor(m => m.UserId) // or add this as a route parameter in BeginForm()
...
for(int i = 0; i < Model.UserRoles.Count; i++)
{
#Html.HiddenFor(m => m.UserRoles[i].RoleId)
#Html.CheckBoxFor(m => m.UserRoles[i].UserisinRole)
#Html.LabelFor(m => m.UserRoles[i].UserisinRole, Model.UserRoles[i].UserRoleName)
}
<input type="submit" name="Submit" value="Update Roles" />
}
When you submit the form, model.UserRoles will contain all roles and you can get the selected roles using
var selectedRoles = model.UserRoles.Where(r => r.UserisinRole);
Side note: Using a <table> does not seem appropriate here.