I am building an Bug Tracker with Asp.Net following a self paced online course. I'm running into an 'Object not set to a reference error" while attemping to list out Tickets assigned to each project in my Project Details View. I know information isn't being passed in, but I'm not sure how to fix that. Any specific solutions to the problem?
Attempted Work Arounds:
Commented out the Ticket Status and Ticket Priority Code and it worked, but it doesn't show everything I'd like.
Youtube Video of Error
Screenshot of Error
Highlighted Code in GitHub Repo
Problem Code:
#model TheBugTrackerProject.Models.Project
#using TheBugTrackerProject.Models.Enums
#using TheBugTrackerProject.Services.Interfaces
#using Microsoft.AspNetCore.Identity
#using TheBugTrackerProject.Models
#inject UserManager<BTUser> userManager
#inject IBTProjectService ProjectService
#inject IBTHistoryService HistoryService
#{
ViewData["Title"] = "Details";
BTUser btUser = await userManager.GetUserAsync(User);
BTUser projectManager = await ProjectService.GetProjectManagerAsync(Model.Id);
}
<h1>Details</h1>
<div>
<div class="container-fluid">
<div class="row gy-2">
<div class="col-md-12 col">
<div class="row col-cols-2 mt-5 bg-secondary">
<div class="card col m-1 p-2">
<div class="body">
#* Project Name *#
<h5>#Model.Name</h5>
#* Project Description *#
<p>#Model.Description</p>
<div class="progress-container progress-info m-b-25">
<span class="progress-badge" style="font-size:small">Project Status</span>
<div class="progress">
#* Razor code block *#
#{
var start = Model.StartDate.DateTime;
var end = Model.EndDate.DateTime;
var today = DateTime.Now;
var percent = today >= end ? 100 : today < start ? 0 : Math.Round((today.Subtract(start)) / (end.Subtract(start)) * 100);
}
<div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: #percent;">
#* Use Progress Bar code variable here *#
<span class="progress-value">#percent%</span>
</div>
</div>
</div>
</div>
</div>
<div class="card col m-1 p-2">
<div class="body">
<ul class=" list-unstyled basic-list">
<li>Start Date: <span class="">#Model.StartDate.ToString("dd MMM, yyyy")</span></li>
<li>Deadline: <span class="">#Model.EndDate.ToString("dd MMM, yyyy")</span></li>
<li>Priority: <span class="">#Model.ProjectPriority?.Name</span></li>
#* if() logic *#
#if (today < end && today >= start)
{
<li>Status:<span class="">Active</span></li>
}
else
{
<li>Status:<span class="">Inactive</span></li>
}
</ul>
</div>
</div>
</div>
</div>
<div class="col-md-4 col mt-5 ">
<div class="bg-secondary">
<div class="card m-1 p-2">
<div class="header">
<h2>Project Manager</h2>
<hr />
</div>
<div class="body" style="overflow-y:auto;height:300px;">
#* if() logic for Avatar/Default etc *#
#if (projectManager != null)
{
<div>
#if (projectManager.AvatarFileData != null)
{
<img class="rounded-circle" src="data:image/*;base64, #(Convert.ToBase64String(projectManager.AvatarFileData))" alt="" />
}
else
{
<img class="rounded-circle " style="width: 60px; height:60px;" src="https://cdn.icon-icons.com/icons2/1378/PNG/512/avatardefault_92824.png" alt="" />
}
<div>
<h5>#projectManager.FullName</h5>
<span>#projectManager.Email</span>
<p class="text-muted m-b-0">Project Manager</p>
#if (User.IsInRole(nameof(Roles.Admin)) || (btUser.Id == projectManager.Id))
{
<a class="btn btn-xs alert-primary" style="font:small;" asp-action="AssignUsers" asp-controller="Projects" asp-route-id="#Model.Id">Manage Team</a>
}
</div>
</div>
}
else
{
<div>
<img class="rounded-circle" style="width:60px;height:60px;" src="https://cdn.icon-icons.com/icons2/1378/PNG/avatardefault_92824.png" />
<div class="wid-u-info">
<h5 class="text-muted m-b-0">Not Assigned</h5>
#if (User.IsInRole(nameof(Roles.Admin)))
{
<span><a asp-action="AssignProjectManager" asp-controller="Home" asp-route-id="#Model.Id" class="btn btn-xs btn-outline-info">Assign PM</a></span>
}
<span><a asp-action="AssignProjectManager" asp-controller="Home" asp-route-id="#Model.Id" class="btn btn-xs btn-outline-info">Assign PM</a></span>
</div>
</div>
}
</div>
</div>
</div>
</div>
<div class="col-md-4 col mt-5 ">
<div class="bg-secondary">
<div class="card m-1 p-2">
<div class="header">
<h2>Project Team</h2>
<hr />
</div>
<div class="body" style="overflow-y:auto;height:300px;">
<ul class="right_chat list-unstyled mb-0">
#* Logic for avatars *#
#foreach (BTUser member in await ProjectService.GetAllProjectMembersExceptPMAsync(Model.Id))
{
<li class="">
<a href="">
<div class="media">
#if (member.AvatarFileData != null)
{
<img class="" src="data:image/*;base64,#(Convert.ToBase64String(member.AvatarFileData))" alt="" />
}
else
{
<img class="" src="https://cdn.icon-icons.com/icons2/1378/PNG/avatardefault_92824.png" />
}
<div class="">
<span class="">#member.FullName</span>
<span class="">#((await userManager.GetRolesAsync(member)).FirstOrDefault())</span>
</div>
</div>
</a>
</li>
}
</ul>
</div>
</div>
</div>
</div>
<div class="col-md-4 col mt-5 ">
<div class="bg-dark">
<div class="card m-1 p-2">
<div class="header">
<h2>Project Activity</h2>
<hr />
</div>
<div class="body" style="overflow-y:auto;height:300px;background-color:antiquewhite">
#* Project Activity loop *#
#foreach (TicketHistory history in await HistoryService.GetProjectTicketHistoryAsync(Model.Id, btUser.CompanyId.Value))
{
<div class="">
<span class="date">#history.Created.ToString("dd MM, yyyy")</span>
<h6>#history.Description</h6>
<span>By: #history.User.FullName</span>
<div class="">
<p>The Ticket <b>#history.Property</b> was edited</p>
<p>#($"Previous {history.Property}: {history.OldValue}")</p>
<p>#($"Current {history.Property}: {history.NewValue}")</p>
<div class="media">
<div class="media-body">
<h6 class="mb-0"></h6>
</div>
</div>
</div>
</div>
}
</div>
</div>
</div>
</div>
<div class="col-md-12 col">
<div class="mt-5 bg-secondary">
<div class="card m-1 p-2">
<div class="header">
<h2>Tickets</h2>
</div>
<div class="body">
<div class="table-responsive" style="overflow-y:auto;height:600px;">
<table class="table table-hover">
<thead class="">
<tr>
#* Table header *#
<th>Title</th>
<th>Developer</th>
<th>Status</th>
<th>Priority</th>
<th>Date</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#* Table body *#
#foreach (var ticket in Model.Tickets.OrderByDescending(d => d.Created))
{
<tr>
<td><a asp-action="Details" asp-controller="Tickets" asp-route-id="#ticket.Id" style="color:black"><strong>#ticket.Title</strong></a> </td>
<td>
#if (ticket.DeveloperUserId != null)
{
#ticket.DeveloperUser?.FullName
}
else
{
if (User.IsInRole(nameof(Roles.Admin)) || User.IsInRole(nameof(Roles.ProjectManager)))
{
<a class="btn btn-xs btn-info" asp-action="AssignDeveloper" asp-controller="Home" asp-route-ticketId="#ticket.Id">Assign Dev</a>
}
}
</td>
#if (ticket.TicketStatus.Name == "New")
{
<td><span class="badge-success">#ticket.TicketStatus.Name</span></td>
}
else
{
<td><span class="badge-success">#ticket.TicketStatus.Name </span></td>
}
<td><span class="badge-warning">#ticket.TicketPriority.Name </span></td>
<td>#ticket.Created.ToString("MM-dd-yyyy")</td>
<td>
<a class="btn btn-sm btn-outline-info" asp-action="Details" asp-controller="Tickets" asp-route-id="#ticket.Id"><i class="fs-5 bi-justify"></i></a>
#if (ticket.DeveloperUserId == btUser.Id || ticket.OwnerUserId == btUser.Id || (projectManager?.Id == btUser.Id) || User.IsInRole(nameof(Roles.Admin)))
{
<a class="btn btn-sm btn-outline-secondary" asp-action="Edit" asp-controller="Tickets" asp-route-id="#ticket.Id"><i class="fs-5 bi-pencil"></i></a>
}
#if (User.IsInRole("Admin") || (projectManager?.Id == btUser.Id))
{
<a class="btn btn-sm btn-outline-danger"><i class="fs-5 bi-archive"></i></a>
}
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Thanks in advance.
P.S. My code is a mess; but looking forward to working with other's on here and possibly in the future.
In your project service, you aren't Include-ing the ticket status so it will be null. Try something like this instead:
Project project = await _context.Projects
.Include(p => p.Tickets)
.ThenInclude(t => t.TicketStatus) // <-- add this line
.Include(p => p.Members)
.Include(p => p.ProjectPriority)
.FirstOrDefaultAsync(p => p.Id == projectId && p.CompanyId == companyId);
Related
I am working on an ASP.Net Core MVC website where I have a page with datatable which has a button for every record which leads to further details of that record. When I click that details button, it works fine but when I refresh the details page, I encounter the above mentioned error. There are no any debugging errors as per my knowledge. Please help me out!!
Here is the code for the page with the datatable :
#model Derawala.Models.ViewModels.ParentForApply
#{
Layout = "_Layout";
}
<form method="post">
<div class="container p-3">
<div class="row pt-4">
<div class="col-6">
<h2 class="text-success">Application List</h2>
</div>
</div>
<br /><br />
#if (Model.AppList.Any())
{
<table id="myTable" class="table table-hover align-middle table-bordered table table-striped" style="width:100%">
<thead>
<tr>
<th class="text-center">
Applicant Name
</th>
<th class="text-center">
Contact No
</th>
<th class="text-center">
Institute Name
</th>
<th class="text-center">
Institute Contact
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var obj in Model.AppList)
{
<tr>
<td class="text-center text-primary" style="font-weight:bold;">#obj.FirstName</td>
<td class="text-center text-primary" style="font-weight:bold;">#obj.Contact</td>
<td class="text-center text-primary" style="font-weight:bold;">#obj.Institute</td>
<td class="text-center text-primary" style="font-weight:bold;">#obj.InstCnt</td>
<td class="text-center">
<div class="w-75 btn-group" role="group">
<button type="submit" asp-action="Details" asp-route-Id="#obj.Id" class="btn btn-primary mx-2">
<i class="fas fa-list"></i>
</button>
<a asp-action="Delete" asp-route-Id="#obj.Id" class="btn btn-danger mx-2">
<i class="fas fa-trash-alt"></i>
</a>
</div>
</td>
</tr>
}
</tbody>
</table>
}
else
{
<p>No Application Exists!</p>
}
</div>
</form>
This is the view of page with the datatable
When I click on the Details button(blue button), it leads to the details page shown below :
Here is the code for the Details Page :
#model Derawala.Models.ViewModels.ParentForApply
#{
ViewData["Title"] = "Details";
Layout = "_Layout";
}
<form method="post">
<input asp-for="#Model.Apply.PofId" hidden />
<div class="container backgroundWhite pt-4">
<div class="card" style="border:1px solid #000000; ">
#*<div class="card-header bg-dark text-light ml-0 row container" style="border-radius: 0px;">*#
<div class="card-header" style="background-color:black;">
<div class="row">
<div class="col-12 col-md-6 align-self-start">
<h1 class="text-white">#Model.Apply.FirstName #Model.Apply.LastName</h1>
</div>
<div class="col-12 col-md-6 align-self-end">
<h1 class="text-warning">Application Id :#Model.Apply.AppId</h1>
</div>
</div>
</div>
<div class="card-body">
<div class="container rounded p-2">
<div class="row">
<div class="col-12 col-lg-4 p-1 text-center">
<img src="#WC.ImagePath[0]#Model.Apply.Photo" class="rounded w-25" />
</div>
<div class="col-12 col-lg-8">
<div class="row pl-3">
<div class="col-12">
<span class="badge p-3 border" style="background-color:lightpink">#Model.Apply.Qualification</span>
<span class="badge p-3 border" style="background-color:lightskyblue">#Model.Apply.BankName</span>
<h3 class="text-success"></h3>
<p class="text-secondary">#Model.Apply.Description</p>
</div>
</div>
<div class="row pl-3">
<div class="col-12">
Download Id Proof : <button type="submit" class="btn-primary" asp-route-id="#Model.Apply.PofId" asp-action="DownloadFile">Download</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer bg-dark">
<div class="row">
<div class="col-12 col-md-6 ">
<a asp-action="RemoveFromCart" class="btn btn-primary btn-square form-control btn-lg" style="height:50px;">Donate Now <i class="fas fa-hand-holding-medical"></i></a>
</div>
<div class="col-12 col-md-6">
<button type="submit" asp-action="" class="btn btn-danger form-control btn-lg" style="height:50px;">Delete This Application <i class="fas fa-trash-alt"></i></button>
</div>
</div>
</div>
</div>
</div>
</form>
This is the view of details page :
and when I refresh this details page it gives me this HTTP 405 error :
Your Details action probably has [HttpPost] attribute and you call it using your submit button. But when you are trying to refresh the browser calls Get method. So you have to remove [HttpPost] from the details action, or create another one with [HttpGet].
I have created a tab where one adds their products and automatically it will add it on the tab. But now my issue is that it repeats the same thing on the tab view "header" whenever I have uploaded the same database. I want it to categorize it and not repeat it. Below is the code I have created.
The picture below shows the database.
Controller
public ActionResult Index()
{
return View(db.Products.ToList());
}
View
#model IEnumerable<tkkkk.Models.Product>
#{
ViewBag.Title = "Home Page";
int counterHeader = 0;
int counterBody = 0;
}
<br />
<ul class="nav nav-tabs">
#foreach (var product in Model)
{
if (counterHeader == 0)
{
<li class="active"><a data-toggle="tab" href="##product.ProductId">#product.ProductName</a></li>
}
else
{
<li><a data-toggle="tab" href="##product.ProductId">#product.ProductName</a></li>
}
counterHeader++;
}
</ul>
<br />
<div class="tab-content">
#foreach (var item in Model)
{
if (counterBody == 0)
{
<div id="#item.ProductId" class="tab-pane fade in active">
<div class="col-lg-4 col-md-6 mb-4" style="width:200px;">
<div class="card h-100">
<img class="card-img-top" src="http://placehold.it/700x400" alt="" width="200">
<div class="card-body">
<h4 class="card-title">
#item.ProductItem - #item.ProductName
</h4>
<h5>R #item.ProductPrice</h5>
</div>
</div>
</div>
</div>
}
else
{
<div id="#item.ProductId" class="tab-pane fade">
<div class="col-lg-4 col-md-6 mb-4" style="width:200px;">
<div class="card h-100">
<img class="card-img-top" src="http://placehold.it/700x400" alt="" width="200">
<div class="card-body">
<h4 class="card-title">
#item.ProductItem - #item.ProductName
</h4>
<h5>R #item.ProductPrice</h5>
</div>
</div>
</div>
</div>
}
counterBody++;
}
</div>
im new to umbraco and c#, I made a blog list in umbraco razor but how can i make a load more button funcionality?
i want when the user click the button load more 5 items to the list.
One way is the the users click the button update the query, but i would need to refresh the page.
Any Help would be great since im stuck on this one, and have no clue how to do this in umbraco.
#{
var selection = Model.Content.Children().Where(x => x.IsVisible()).Take(5).ToList();
}
<div class="container-fluid" style="padding-left: 117px;">
<div class="row" style="margin-top: 5em;">
<div class="col-lg-9 col-md-9 col-sm-9">
<!-- BLOG START -->
#while(selection.Any()){
var oneItem = selection.First();
selection.Remove(oneItem);
<div class="row">
<div class="col-md-4 col-sm-12" onclick="location.href='#oneItem.Url'" style="cursor:pointer">
<div class="card">
<img src="#Umbraco.TypedMedia(oneItem.GetPropertyValue<int>("imagemPublicacaoBlog")).Url" style="height: 15em;">
</div>
</div>
<div class="col-md-6 col-sm-12" onclick="location.href='#oneItem.Url'" style="cursor:pointer">
<span class="card-text qs-blog-direcao">#oneItem.GetPropertyValue("tipoDeDirecao")</span><br><br>
<span class="qs-blog-date-1page" id="qs-datetime">#(oneItem.GetPropertyValue<DateTime>("dataDePublicacaoBlog").ToString("dd MMMM yyyy",new CultureInfo("pt-PT")))</span>
<br>
<span class="qs-blog-publicado-por">#oneItem.GetPropertyValue("publicadoPorBlog") - OPINIÃO </span>
<span class="qs-blog-titulo-1page">#oneItem.GetPropertyValue("tituloBlog")</span>
</div>
<div class="col-md-12 col-sm-12 onclick="location.href='#oneItem.Url'" style="cursor:pointer"" style="margin-top:2em;">
<span class="qs-blog-resumo d-flex justify-content-start">#oneItem.GetPropertyValue("resumoBlog")</span>
<span class="d-flex justify-content-end"><a><img src=" /media/1027/icon_inf_verde.png"></a></span>
</div>
</div>
var twoItems = selection.Take(2).ToList();
if(twoItems.Any()){
<div class="row">
#foreach (var item in twoItems){
selection.Remove(item);
<div class="col-md-6 col-sm-12" onclick="location.href='#item.Url'" style="cursor:pointer">
<span class="card-text qs-blog-direcao-double">#item.GetPropertyValue("tipoDeDirecao")</span><br>
<img src="#Umbraco.TypedMedia(item.GetPropertyValue<int>("imagemPublicacaoBlog")).Url" style="height: 10em;margin-top: 2em;">
<div class="qs-blog-sideByside">
<span class="qs-blog-date-1page-double" id="qs-datetime">#(item.GetPropertyValue<DateTime>("dataDePublicacaoBlog").ToString("dd MMMM yyyy",new CultureInfo("pt-PT")))</span><br>
<span class="qs-blog-publicado-por-double"> #item.GetPropertyValue("publicadoPorBlog") - OPINIÃO </span>
</div>
<div class="qs-blog-titulo-1page-double">#item.GetPropertyValue("tituloBlog")</div>
<div class="qs-blog-resumo-blog d-flex justify-content-start">#item.GetPropertyValue("resumoBlog")</div>
<span class="d-flex justify-content-end"><a><img src=" /media/1027/icon_inf_verde.png"></a></span>
</div>
}
</div>
<br>
}
}
<!-- BLOG END -->
</div>
It could be something like this:
#{
int page = int.TryParse(Request["page"], out page) ? page : 0;
int pageSize = 5;
var selection = Model.Content
.Children()
.Where(x => x.IsVisible())
.Skip(page * pageSize)
.Take(pageSize)
.ToList();
}
<div class="container-fluid">
...
</div>
<a href="#Request.RawUrl.Split('?')[0]?page=#(page + 1)">
Load next #pageSize results
</a>
Here's my problem, I have a Book that contains List<Page> that contains List<Line> and I'm trying to create a view that will edit my book. This view contains all the lines from the book. I've made an MVVM for List<Page> that calls smaller MVVM for List<Line>. The problem is that MVVM is not counting all Line as one single form, so this happens:
<form>
<h1>Page one</h1>
<input type="hidden" name="[0].lineContent" value=""/>
<input type="hidden" name="[1].lineContent" value=""/>
<h1>Page one</h1>
<input type="hidden" name="[0].lineContent" value=""/>
<input type="hidden" name="[1].lineContent" value=""/>
<input type="hidden" name="[2].lineContent" value=""/>
</form>
Each time my for loop for page iterates, my for loops in lines get reset to 0, this creates duplicate name entries.
There are multiple ways to correct this, the easiest:
Build input by hand with unique name id instead of using HTML helpers
My question is the following: how can I achieve a clean razor that can be reused, and that will not duplicate name entries in my form?
UPDATE:
Context:
Just like the book exemple up, my models have the same structure.
in my case I have a Submission that contains a list of Section that contains a list of SubSection that contains a list of SubmissionLine.
Here's my main view:
#model
QuotingPlus.Models.Submission
#{
ViewData["Title"] = "Edit";
}
<form id="submission-form" asp-action="Edit">
<div>
<p class="d-inline-block">
<a class="btn btn-primary" data-toggle="collapse"
href="#multiCollapseExample1" role="button" aria-expanded="false" aria-controls="multiCollapseExample1">Edit submission details</a>
</p>
<nav aria-label="breadcrumb" class="d-inline-block">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/Clients/Details/#(Model.IdProjectNavigation.IdClientNavigation.IdClient)">#Model.IdProjectNavigation.IdClientNavigation.FirstName
#Model.IdProjectNavigation.IdClientNavigation.LastName</a>
</li>
<li class="breadcrumb-item">
#Model.IdProjectNavigation.Name
</li>
<li class="breadcrumb-item active" aria-current="page">#Model.Number</li>
</ol>
</nav>
</div>
<div class="row">
<div class="col mb-3">
<div class="collapse multi-collapse" id="multiCollapseExample1">
<div class="card card-body">
<h1>Submission details</h1>
<hr/>
<div class="row">
<div class="col-md-4">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="IdSubmission"/>
<div class="form-group">
<label asp-for="IdTypeSubmission" class="control-label"></label>
<select asp-for="IdTypeSubmission" class="form-control" asp-items="ViewBag.IdTypeSubmission"></select>
<span asp-validation-for="IdTypeSubmission" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="IdProject" class="control-label"></label>
<select asp-for="IdProject" class="form-control" asp-items="ViewBag.IdProject"></select>
<span asp-validation-for="IdProject" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Number" class="control-label"></label>
<input asp-for="Number" class="form-control"/>
<span asp-validation-for="Number" class="text-danger"></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="save-warning" style="display: none;" class="alert alert-info alert-dismissible fade show" role="alert">
<strong>WARNING!</strong> Make sure you save before leaving.
<button type="button" class="close" data-dismiss="alert" aria-label="Close" onclick="SetWarningDisplayPreferenceCookie();">
<span aria-hidden="true">×</span>
</button>
</div>
<div id="carouselIndicators" style="height: 100% !important;" class="carousel slide pb-5 mb-5" data-interval="false">
<div class="carousel-inner">
#{
Html.RenderPartial("SubmissionSectionEditor", Model.SubmissionSection.ToList());
}
</div>
<nav class="navbar navbar-light bg-secondary mb-0 pt-2 fixed-bottom">
<div>
<button type="submit" value="Save" class="btn btn-default text-white">
<i class="material-icons" style="font-size: 2em;">
save
</i>
</button>
</div>
<a class="col text-center mh-100 pt-2 pb-2" href="#carouselIndicators" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="false"></span>
</a>
<a class="col text-center mh-100 pt-2" href="#carouselIndicators" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="false"></span>
</a>
<div>
<a asp-action="Index" class="btn text-white">
<i class="material-icons" style="font-size: 2em;">
cancel
</i>
</a>
</div>
</nav>
</div>
</form>
Here's SubmissionSectionEditor.cshtml
#model List<SubmissionSection>
#{
var isFirstCarouselItem = true;
}
#for (var indexSection = 0; indexSection < Model.Count(); indexSection++)
{
<div class="carousel-item #((isFirstCarouselItem) ? "active" : "")">
#{
isFirstCarouselItem = false;
}
<h1>#Model[indexSection].IdSectionNavigation.Name</h1>
<div id="#(Model[indexSection].IdSection + "accordion")">
#{
var submissionSubSections = M odel[indexSection].SubmissionSubSection;
}
#if (submissionSubSections != null)
{
Html.RenderPartial("SubmissionSubSectionEditor", submissionSubSections.ToList());
}
</div>
</div>
}
Here's SubmissionSubSectionEditor.cshtml
#model List<SubmissionSubSection>
#for (var indexSubSection = 0; indexSubSection < Model.Count; indexSubSection++)
{
<div class="card">
<div class="card-header" id="#(Model[indexSubSection].IdSubSection + "SubSectionHeader")">
<h2 class="mb-0">
<button type="button" class="btn btn-link collapsed" data-toggle="collapse" data-target="#("#" + Model[indexSubSection].IdSubSection + "SubSectionCollapse")" aria-
expanded="true" aria-controls="#(Model[indexSubSection].IdSubSection + "SubSectionCollapse")">
#Model[indexSubSection].IdSubSectionNavigation.Name
</button>
</h2>
</div>
<div id="#(Model[indexSubSection].IdSubSection + "SubSectionCollapse")" class="collapse" aria-labelledby="#(Model[indexSubSection].IdSubSection +
"SubSectionHeader")" data-parent="#("#" + Model[indexSubSection].IdSubmissionSectionNavigation.IdSection + "accordion")">
<div class="card-body">
<table class="table w-100">
<thead class="thead-dark">
<tr>
<th>Quantity</th>
<th>Article</th>
<th>Total Material</th>
<th>Unit Price Material</th>
<th>Total Sub Contractor</th>
<th>Unit Price Sub Contractor</th>
<th>Total Workforce</th>
<th>Unit Price Workforce</th>
<th>Display</th>
</tr>
</thead>
<tbody>
#{
Html.RenderPartial("SubmissionLineEditor", Model[indexSubSection].SubmissionLine.ToList());
}
</tbody>
</table>
</div>
</div>
</div>
}
Here's SubmissionLineEditor.cshtml
#model List<SubmissionLine>
#for (var indexLine = 0; indexLine < Model.Count; indexLine++)
{
<tr>
#Html.HiddenFor(x => Model[indexLine].IdSubmissionLine)
#Html.HiddenFor(x => Model[indexLine].IdArticle)
#Html.HiddenFor(x => Model[indexLine].IdSubmissionSubSection)
<td>#Html.TextBoxFor(x => Model[indexLine].Quantity, new {#type = "number", #step = "0.5", #min="0"})</td>
<td>#Model[indexLine].IdArticleNavigation.Designation</td>
<td>#Model[indexLine].TotalMaterial</td>
<td>#Model[indexLine].IdArticleNavigation.UnitPriceMaterial</td>
<td>#Model[indexLine].TotalSubContractor</td>
<td>#Model[indexLine].IdArticleNavigation.UnitPriceSubContractor</td>
<td>#Model[indexLine].TotalWorkforce</td>
<td>#Model[indexLine].IdArticleNavigation.UnitPriceWorkforce</td>
<td>#Html.CheckBoxFor(x => Model[indexLine].IsDisplayed, new {#class = "checkbox"}).
</td>
</tr>
}
I only want to know how I can keep this structure with MVVM and avoid the input name duplicate issue?
RE-UPDATE:
I'm not quite sure why this would be useful since I get name duplicate input, but here's my save action:
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Admin, SuperAdmin, Employe")]
public ActionResult Edit(int id, Submission submission, [FromForm] List<SubmissionLine> lines)
{
var test = Request.Form;
if (id != submission.IdSubmission)
{
return NotFound();
}
if (ModelState.IsValid)
{
SubmissionUpdateHelper.SaveSubmissionModifications(_context, submission, lines);
return RedirectToAction(nameof(Index));
}
ViewData["IdProject"] = new SelectList(_context.Project, "IdProject", "Name", submission.IdProject);
ViewData["IdTypeSubmission"] = new SelectList(_context.TypeSubmission, "IdTypeSubmission",
"TypeSubmission1", submission.IdTypeSubmission);
return View(submission);
}
For showing sub-list properties in View, Try code below:
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="BookName" class="control-label"></label>
<input asp-for="BookName" class="form-control" />
<span asp-validation-for="BookName" class="text-danger"></span>
</div>
<div class="form-group">
#for (int i = 0; i < Model.Pages.Count; i++)
{
<div class="form-group">
<label asp-for="Pages[i].PageName" class="control-label"></label>
<input asp-for="Pages[i].PageName" class="form-control" />
<span asp-validation-for="Pages[i].PageName" class="text-danger"></span>
</div>
<div class="form-group">
#for (int j = 0; j < Model.Pages[i].Lines.Count; j++)
{
<div class="form-group">
<label asp-for="Pages[i].Lines[j].LineContent" class="control-label"></label>
<input asp-for="Pages[i].Lines[j].LineContent" class="form-control" />
<span asp-validation-for="Pages[i].Lines[j].LineContent" class="text-danger"></span>
</div>
}
</div>
}
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
Finally, I've just added the input by hand so I could keep my MVVM pattern. I've also used an increment variable in TempData so I could keep track of the input
in Edit.cshtml
#{
TempData["submissionLineCount"] = 0;
}
here's the new version of SubmissionLineEditor.cshtml
#model List<SubmissionLine>
#for (var indexLine = 0; indexLine < Model.Count; indexLine++)
{
<tr>
<input name="[#(TempData["submissionLineCount"])].IdSubmissionLine" value="#(Model[indexLine].IdSubmissionLine)" type="hidden"/>
<input name="[#(TempData["submissionLineCount"])].IdArticle" value="#(Model[indexLine].IdArticle)" type="hidden"/>
<input name="[#(TempData["submissionLineCount"])].IdSubmissionSubSection" value="#(Model[indexLine].IdSubmissionSubSection)" type="hidden"/>
<td>#TempData["submissionLineCount"]</td>
<td>
<input name="[#(TempData["submissionLineCount"])].Quantity" value="#(Model[indexLine].Quantity)" type="number" step="0.5" min="0"/>
</td>
<td>#Model[indexLine].IdArticleNavigation.Designation</td>
<td>#Model[indexLine].TotalMaterial</td>
<td>#Model[indexLine].IdArticleNavigation.UnitPriceMaterial</td>
<td>#Model[indexLine].TotalSubContractor</td>
<td>#Model[indexLine].IdArticleNavigation.UnitPriceSubContractor</td>
<td>#Model[indexLine].TotalWorkforce</td>
<td>#Model[indexLine].IdArticleNavigation.UnitPriceWorkforce</td>
<td>
<input type="checkbox" name="[#(TempData["submissionLineCount"])].IsDisplayed" class="checkbox" value="#(Model[indexLine].IsDisplayed)"/>
</td>
</tr>
{
TempData["submissionLineCount"] = (Convert.ToInt32(TempData["submissionLineCount"]) + 1);
}
}
This is clearly not the best way, I hope there will be more documentation on how to apply MVVM in AspNet.Core in the future...
If this answer gets deprecated, make sure to post your own!
My Controller which calls the View:
public ActionResult Excel()
{
myClass arg = new myClass(string arg1, object arg2);
return View(arg);
}
My View:
#model myClass
#using (Html.BeginForm("createXML", "Excel", new { arg = Model }))
{ { #Html.ValidationSummary(true)
<div class="container-full" style="background-color:aliceblue">
<h3 class="= container">Einstellungen:</h3>
<div class="container">
<div class="row">
<div class="col-md-3">
<div class="panel-group">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#collapse1">nk</a>
</h4>
</div>
<div id="collapse1" class="panel-collapse collapse">
<ul class="list-group">
<li class="list-group-item">
<form action="select.html">
<label>
Anzahl:
<select name="decimal">
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
<option>10</option>
</select>
</label>
</form>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="panel-group">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#collapse2">sign</a>
</h4>
</div>
<div id="collapse2" class="panel-collapse collapse">
<ul class="list-group">
<li class="list-group-item">
<form action="select.html">
<label>
left:
<select name="decimal">
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
<option>10</option>
</select>
</label>
</form>
</li>
<li class="list-group-item">
<form action="select.html">
<label>
right:
<select name="decimal">
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
<option>10</option>
</select>
</label>
</form>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="panel-group">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#collapse3">Optionen</a>
</h4>
</div>
<div id="collapse3" class="panel-collapse collapse">
<form>
<fieldset>
<ul class="list-group">
<li class="list-group-item">
<label>
#Html.CheckBoxFor(m => m.P5_VerkBesch)
#*<input type="checkbox" name="verkBesch" value="1">*#
Verk
</label>
</li>
<li class="list-group-item">
<label>
#Html.CheckBoxFor(m => m.P5_SpezBesch)
#*<input type="checkbox" name="sFonds" value="1">*#
spezbesch
</label>
</li>
<li class="list-group-item">
<label>
<input type="checkbox" name="kgpr" value="1">
kgpr
</label>
</li>
<li class="list-group-item">
<label>
#Html.CheckBoxFor(m => m.P5_AD)
#*<input type="checkbox" name="Ad" value="1">*#
ad
</label>
</li>
<li class="list-group-item">
<label>
<input type="checkbox" name="md" value="1">
md
</label>
</li>
<li class="list-group-item">
<label>
<input type="checkbox" name="beschText" value="1">
beschtxt
</label>
</li>
<li class="list-group-item">
<label>
#Html.CheckBoxFor(m => m.P5_Uni)
#*<input type="checkbox" name="uni" value="1">*#
uni
</label>
</li>
</ul>
</fieldset>
</form>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="panel-group">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#collapse4">Weitere Einstellungen</a>
</h4>
</div>
<div id="collapse4" class="panel-collapse collapse">
<ul class="list-group">
<li class="list-group-item">
<div>
<label>Anzahl Dateien pro:</label>
<br />
#*<small>123</small>*#
#Html.TextBoxFor(i => i.P5_ANZAHL, new { #type = "number", #style = "max-width: 100%" })
</div>
</li>
<li class="list-group-item">
<div>
<label>Datum ändern:</label>
<br />
<p>
#Html.TextBoxFor(m => m.P5_DATUM, new { #id = "datepicker", #type = "text", #style = "width: 100%" })
#*<input type="text" id="datepicker" style="width:100%">*#
</p>
</div>
</li>
<li class="list-group-item">
<div>
<label>Fds:</label>
<br />
#Html.TextAreaFor(m => m.P5_Fundstelle, new { #rows = "4", style = "width: 100%" })
#*<textarea style="max-width:100%;" rows="4"></textarea>*#
</div>
</li>
<li class="list-group-item">
<div>
<label>Anhaltspunkte :</label>
<br />
#*<small>123</small>*#
#Html.TextBoxFor(m => m.P5_Anhaltspunkte, new { style = "width: 100%" })
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<h2>Excel</h2>
<div>
<form id="myForm" method="post"
enctype="multipart/form-data"
action="">
<div>
<h1>File Upload</h1>
#if (!IsPost)
{
#FileUpload.GetHtml(
initialNumberOfFiles: 2,
allowMoreFilesToBeAdded: true,
includeFormTag: true,
addText: "Add another file",
uploadText: "Upload")
}
<span>#message</span>
</div>
</form>
<input type="submit" value="Submit" />
</div>
</div>
</div>
}
Controller Function which should be called:
public ActionResult createXML(myClass arg)
{
//Code here...
return View("~/Views/Excel/Excel.cshtml");
}
My Problem is that "arg" is passed as null to createXML. I can't figure out why. One has to say that I am normally a WPF/WinForms Programmer.
UPDATE
I updated my code a bit, to make it clearer maybe.
UPDATE 2
I found out a part of the problem. My Object has only one constructor, where i need some paramateres. This generates somehow an error. I created a constructor without any parameter and it works, but it somehow creates a new object when I start my form and does not use the object i passed on to the view.
change view like this
#using (Html.BeginForm("createXML", "Excel", FormMethod.Post))
and
add this above createxml
[HttpPost]
UPDATE
I tried your codes and worked. Here is codes
HomeController codes. You can place this methods in your ExcelController
public ActionResult Excel()
{
myClass arg = new myClass();
arg.p = 5;
return View(arg);
}
[HttpPost]
public ActionResult createXML(myClass arg)
{
int a = arg.p;
return View();
}
Home/Excel.cshtml codes
#model Identity.Controllers.myClass
#{
Layout = null;
}
#using (Html.BeginForm("createXML", "Home", FormMethod.Post))
{ #Html.ValidationSummary(true)
<div class="container-full" style="background-color:aliceblue">
<h3 class="= container">Einstellungen:</h3>
<div class="container">
#Html.TextBoxFor(x => x.p)
<input type="submit" value="Submit" />
</div>
</div>
}
You are using wrong overload.
You can use this overload. BeginForm(
this HtmlHelper htmlHelper,
string actionName,
string controllerName,
Object routeValues,
FormMethod method,
Object htmlAttributes)
#Html.BeginForm("createXML", "Excel", new { arg = Model },FormMethod.Post,null)
or remove the argument and use hidden field within the form:
#using(Html.BeginForm("createXML", "Excel",FormMethod.Post))
{
.....
#Html.Hidden("arg", Model)
}