Master Detail not showing details table in modal popup - ASP.NET Core - asp.net-core

I am doing CRUD operations on a Master Detail models Team and TeamMember using modal popup. I followed this post to perform the Create operation and it is ok, now i am doing the Detail operation:
TeamController:
public IActionResult Detail(int id)
{
Team team = _dbcontext.Team
.Include(a => a.TeamMembers)
.Where(e => e.TeamId == id).FirstOrDefault();
return PartialView("_DetailTeamPartialView", team);
}
Index.cshtml detail button:
<button class="btn btn-success" data-toggle="modal" data-target="#("#DetailTeam-"+item.TeamId)" data-url="#Url.Action($"Detail/{item.TeamId}")">Detail</button>
#await Html.PartialAsync("_DetailTeamPartialView", item)
_DetailTeamPartialView.cshtml:
#model Team
#{
ViewData["Title"] = "_DetailTeamPartialView";
}
<div class="modal fade" role="dialog" tabindex="-1" id="#("DetailTeam-"+Model.TeamId)" aria-labelledby="DetailTeamLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog modal-xl modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Detail Team</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="javascript:window.location.reload()">
<span aria-hidden="true">×</span>
</button>
</div>
<div>
<dl class="row">
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.TeamName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.TeamName)
</dd>
.......
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.TeamMembers)
</dt>
<dd class="col-sm-10">
<table class="table table-bordered table-sm">
<thead>
<tr>
<th>Member name</th>
<th>Birth date</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.TeamMembers.Count; i++)
{
<tr>
<td>
<input asp-for="#Model.TeamMembers[i].MemberName" class="form-control-plaintext" readonly />
</td>
<td>
<input asp-for="#Model.TeamMembers[i].BirthDate" class="form-control-plaintext" readonly />
</td>
</tr>
}
</tbody>
</table>
</dd>
</dl>
</div>
</div>
</div>
</div>
This code displays only team details and doesn't show the TeamMember details. Any help??
EDIT
these are the classes:
public class Team
{
[Key]
public int TeamId { get; set; }
[Required]
public string TeamName { get; set; }
public virtual List<TeamMember> TeamMembers { get; set; } = new List<TeamMember>();
}
public class TeamMember
{
[Key]
public int TeamMemberId { get; set; }
[Required]
public string MemberName{ get; set; }
[Required]
public DateTime BirthDate{ get; set; }
[ForeignKey("TeamId")]
public int TeamId { get; set; }
public virtual Team Team{ get; set; }
}
'Model.TeamMembers.Count' in '#for (int i = 0; i < Model.TeamMembers.Count; i++)' return 0 why??

Master Detail not showing details table in modal popup - ASP.NET Core
I have gone through your shared code snippet between the line altough, you haven't shared your index page's code that certainly playing important role here. Nontheless, I tried to visualize what you are trying to achieve.
Expected Behaviour:
From the shared code, I have managed to build above output therefore, the expected behaviour might be while clicking on details button on the team's list which is the index page should display the details list of all the team member of that particular team. If that is the business scenario, then I would say, your approach were wrong and you are doing mess of course here thus, follow the steps below which will help to resolve your issue.
Database:
Note: Models would be same as yours. So not repeating that part.
Controller:
public class TeamController : Controller
{
private readonly ApplicationDbContext _context;
private readonly IWebHostEnvironment _environment;
public TeamController(IWebHostEnvironment environment, ApplicationDbContext context)
{
_environment = environment;
_context = context;
}
public IActionResult Index()
{
var teamList = _context.Teams.Include(a => a.TeamMembers).ToList();
return View(teamList);
}
}
Note: You are doing the mess here as you are using another details action for the _DetailTeamPartialView which is complete Irelevant here. Only Index action is capable here what you are trying to achieve. Just need to use Include(a => a.TeamMembers) which the action.
View Of Index()
#model IEnumerable<DotNet6MVCWebApp.Models.Team>
#{
ViewData["Title"] = "Index";
}
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.TeamId)
</th>
<th>
#Html.DisplayNameFor(model => model.TeamName)
</th>
<th>
Member Details
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.TeamId)
</td>
<td>
#Html.DisplayFor(modelItem => item.TeamName)
</td>
<td>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#("#DetailTeam-"+item.TeamId)">Detail</button>
#await Html.PartialAsync("_DetailTeamPartialView", item)
</td>
</tr>
}
</tbody>
</table>
_DetailTeamPartialView
Though, your _DetailTeamPartialView is alrigh and no vital issue has not seen,
#model DotNet6MVCWebApp.Models.Team
#{
ViewData["Title"] = "_DetailTeamPartialView";
}
<div class="modal fade" role="dialog" tabindex="-1" id="#("DetailTeam-"+Model.TeamId)" aria-labelledby="DetailTeamLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog modal-xl modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Detail Team</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="javascript:window.location.reload()">
<span aria-hidden="true">×</span>
</button>
</div>
<div>
<dl class="row">
<div style="margin-left:10px">
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.TeamName)
</dt>
<dd class="col-sm-10">
#Html.DisplayFor(model => model.TeamName)
</dd>
.......
<dt class="col-sm-2">
#Html.DisplayNameFor(model => model.TeamMembers)
</dt>
<dd class="col-sm-10">
<table class="table table-bordered table-sm">
<thead>
<tr>
<th>Member name</th>
<th>Birth date</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.TeamMembers.Count; i++)
{
<tr>
<td>
<input asp-for="#Model.TeamMembers[i].MemberName" class="form-control-plaintext" readonly />
</td>
<td>
<input asp-for="#Model.TeamMembers[i].BirthDate" class="form-control-plaintext" readonly />
</td>
</tr>
}
</tbody>
</table>
</dd>
</div>
</dl>
</div>
</div>
</div>
</div>
Output
Takeaways:
As you are using HTML Tag helper class that is #await Html.PartialAsync("_DetailTeamPartialView", item) so you don't need to use below Detail action on your controller. Index action would handled the _DetailTeamPartialView autometically.
public IActionResult Detail(int id)
{
Team team = _dbcontext.Team
.Include(a => a.TeamMembers)
.Where(e => e.TeamId == id).FirstOrDefault();
return PartialView("_DetailTeamPartialView", team);
}

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; }
}

asp-validation-for not working under foreach due to same name issue

I am using asp-validation-for under foreach and facing following issues. suppose 3 text controls generated with foreach. I am using the [required] model annotation. "objGenExaminationTemplateChoicesModel" object is of ICollection in main model.
if first text controls is empty system is showing error message with
all 3 text controls.
if second or third is empty system is not
showing any message but don't proceed to post page due to model
error.
<table id="dtChoices" class="table table-borderless table-striped">
<thead class="bg-primary">
<tr>
<th class="text-left"><label asp-for="#Model.objGenExaminationTemplateChoicesModel.FirstOrDefault().ChoiseDescription" class="control-label"></label></th>
<th style="width:30px"><span class="sidenav-icon icon icon-plus-square pull-right" style="font-size:large"> </span></th>
</tr>
</thead>
<tbody>
#foreach (var objGenExaminationTemplateChoiceModel in Model.objGenExaminationTemplateChoicesModel)
{
iCounter = iCounter + 1;
<tr>
<td class="text-left form-group form-group-sm">
<input type="text" asp-for="#objGenExaminationTemplateChoiceModel.ChoiseDescription" class="form-control">
<span asp-validation-for="#objGenExaminationTemplateChoiceModel.ChoiseDescription" class="text-danger"></span>
</td>
<td>
<a href="#" class="text-warning btnDeleteRow" data-toggle="modal" data-target="#deleteConfirmationModalAlert">
<span class="sidenav-icon icon icon-trash pull-right" style="font-size:large"> </span>
</a>
</td>
</tr>
}
</tbody>
The objGenExaminationTemplateChoicesModel is a list model,so the model binding system would find the name by [i].propertyName.Change your code like below:
#model TestVmodel
<form>
<table id="dtChoices" class="table table-borderless table-striped">
<thead class="bg-primary">
<tr>
<th class="text-left"><label asp-for="#Model.objGenExaminationTemplateChoicesModel.FirstOrDefault().ChoiseDescription" class="control-label"></label></th>
<th style="width:30px"><span class="sidenav-icon icon icon-plus-square pull-right" style="font-size:large"> </span></th>
</tr>
</thead>
<tbody>
#{ var iCounter = 0;}
#for (int i = 0; i < Model.objGenExaminationTemplateChoicesModel.Count(); i++)
{
iCounter = iCounter + 1;
<tr>
<td class="text-left form-group form-group-sm">
<input type="text" asp-for="#Model.objGenExaminationTemplateChoicesModel[i].ChoiseDescription" class="form-control">
<span asp-validation-for="#Model.objGenExaminationTemplateChoicesModel[i].ChoiseDescription" class="text-danger"></span>
</td>
<td>
<a href="#" class="text-warning btnDeleteRow" data-toggle="modal" data-target="#deleteConfirmationModalAlert">
<span class="sidenav-icon icon icon-trash pull-right" style="font-size:large"> </span>
</a>
</td>
</tr>
}
</tbody>
</table>
<input type="submit" value="aa" />
</form>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
My testing model:
public class TestVmodel
{
public List<ObjGenExaminationTemplateChoicesModel> objGenExaminationTemplateChoicesModel { get; set; }
}
public class ObjGenExaminationTemplateChoicesModel
{
[Required]
public string ChoiseDescription { get; set; }
}
Result:

How can i generate downloadable PDF from the items in my Cart

I am using dompdf to generate a downloadable pdf from my multi-vendor eCommerce shopping cart and I am encountering this error even after defining $cartItems in QuotationController. $cartItems is defined in CartController I intend to fetch the items of CartController to the pdf
Here is the error:
Undefined variable: cartItems (View: C:\laragon\www\procure\resources\views\cart\quote.blade.php)
Here is QuoteController code:
<?php
namespace App\Http\Controllers;
use Barryvdh\DomPDF\PDF;
use Darryldecode\Cart\Cart;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class QuotationController extends Controller
{
public function quote(Request $request)
{
$product = DB::table('products')->get();
$cartItems = \Cart::session(auth()->id())->getContent();
$pdf = \PDF::loadView('cart.quote');
return $pdf->download('quotation.pdf');
//return view('cart.quote');
}
}
Heres is CartController:
<?php
namespace App\Http\Controllers;
use App\Product;
use Darryldecode\Cart\Cart;
class CartController extends Controller
{
public function add(Product $product)
{
// add the product to cart
\Cart::session(auth()->id())->add(array(
'id' => $product->id,
// 'img' => $product->cover_img,
'name' => $product->name,
'price' => $product->price,
'quantity' => 1,
'attributes' => array(),
'associatedModel' => $product,
));
return redirect()->route('cart.index');
}
public function index()
{
$cartItems = \Cart::session(auth()->id())->getContent();
view()->share('cartItems', $cartItems);
return view('cart.index', compact('cartItems'));
}
public function destroy($itemId)
{
\Cart::session(auth()->id())->remove($itemId);
return back();
}
public function update($rowId)
{
\Cart::session(auth()->id())->update($rowId, [
'quantity' => [
'relative' => false,
'value' => request('quantity'),
],
]);
return back();
}
public function checkout()
{
return view('cart.checkout');
}
}
And finally the blade file(quote.blade.php):
<section class="shopping-cart">
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="cart-table table-responsive">
<table class="table">
<thead>
<tr>
<th class="t-pro">Product</th>
<th class="t-price">Price</th>
<th class="t-qty">Quantity</th>
<th class="t-total">Total</th>
<th class="t-rem"></th>
</tr>
</thead>
<tbody>
#foreach ($cartItems as $item)
<tr>
<td class="t-pro d-flex">
<div class="t-content">
<p class="t-heading">{{ $item->name }}</p>
</div>
</td>
<td class="t-price">KES {{ $item->price }} </td>
<td class="t-qty">
<div class="qty-box">
<div class="quantity buttons_added">
<form action="{{route('cart.update', $item->id)}}" method="get">
<input name="quantity" type="number" value="{{ $item->quantity }}">
<input class="button" type="submit" value="save">
</form>
</div>
</div>
</td>
<td class="t-total">{{Cart::session(auth()->id())->get($item->id)->getPriceSum()}}</td>
<td class="t-rem"><i class="far fa-trash-alt"></i></td>
</tr>
#endforeach
</tbody>
</table>
</div>
</div>
<div class="col-md-4">
<div class="coupon">
<h6>Discount Coupon</h6>
<p>Enter your coupon code if you have one</p>
<form action="#">
<input type="text" name="zip" value="" placeholder="Your Coupon">
<button type="button">Apply Code</button>
</form>
Print Quotation
</div>
</div>
<div class="col-md-4">
<div class="crt-sumry">
<h5>Cart Summery</h5>
<ul class="list-unstyled">
<li>Subtotal <span>KES {{\Cart::session(auth()->id())->getTotal()}}</span></li>
<li>Shipping & Tax <span>0.00</span></li>
<li>Grand Total <span>KES {{\Cart::session(auth()->id())->getTotal()}}</span></li>
</ul>
<div class="cart-btns text-right">
<button onclick="location.href='{{route('home')}}'" class="up-cart">Update Cart</button>
<button onclick="location.href='{{route('cart.checkout')}}'" class="chq-out ">Checkout</button>
</div>
</div>
</div>
</div>
</div>
</section>
Just visit this https://github.com/arafkarim/HTML-to-PDF i have just applied this thing in my similar project.

Confirmation Boostrap modal posting

I'm attempting to take a confirm event and turning it into a modal. Here is the original code:
#page
#model AllCustomerModel
#{
ViewData["Title"] = "AllCustomer";
}
<h2>All Customers</h2>
<p>
<a asp-page="Customer">Create New Customer</a>
</p>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayName("Name")
</th>
<th>
#Html.DisplayName("Address")
</th>
<th>
#Html.DisplayName("Country")
</th>
<th>
#Html.DisplayName("City")
</th>
<th>
#Html.DisplayName("Phone")
</th>
<th>Edit | Delete</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.customerList)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Address)
</td>
<td>
#Html.DisplayFor(modelItem => item.Country)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
#Html.DisplayFor(modelItem => item.Phone)
</td>
<td>
<a asp-page="./EditCustomer" asp-route-id="#item.CustomerID">Edit</a> |
<a asp-page="./AllCustomer" onclick="return confirm('Are you sure you want to delete this item?');" asp-page-handler="Delete" asp-route-id="#item.CustomerID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Code Behind,
public ActionResult OnGetDelete(int? id)
{
if (id != null)
{
var data = _context.CustomerTB.Find(id);
_context.Remove(data);
_context.SaveChanges();
}
return RedirectToPage("AllCustomer");
}
Here is what I've tried/currently trying (for brevity sake, I haven't pasted the MVP)
<button type="button" class="btn btn-primary" data-toggle="modal" data-id="#item.CustomerID" data-target="#myModal">
Delete
</button>
<div class="modal fade" id="myModal">
<form id="myForm" method="post">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Delete Customer</h4>
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
Are you sure you want to delete this customer?
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-danger">Yes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">No</button>
</div>
</div>
</div>
</form>
</div>
Code Behind,
[BindProperty]
public Customer Customer { get; set; }
public void OnPost()
{
Customer customer = Customer;
if (customer != null)
_context.Remove(_context.CustomerTB.Find(customer.CustomerID));
customerList = _context.CustomerTB.ToList();
}
It will hit the OnPost method but the customer object is empty. Is this a proper way to tackle this issue? What more do I need to add in order to pick up the object on the code behind?
You need to pass the selected customerId to modal(with a hidden type) by javascript when click the button,and then bind the Customer.CustomerId in page using asp-for tag helper.
For example:
<button type="button" class="btn btn-primary myButton" data-toggle="modal" data-id="#item.CustomerID" data-target="#myModal">
Delete
</button>
<div class="modal fade" id="myModal">
<form id="myForm" method="post">
<div class="modal-dialog">
<div class="modal-content">
//..
<div class="modal-body">
<input type="hidden" class="hiddenid" asp-for="Customer.CustomerID" />
Are you sure you want to delete this customer?
</div>
//..
</div>
</div>
</form>
</div>
#section Scripts{
<script>
$('.myButton').on('click', function (event) {
var passedID = $(this).data('id');
$(".modal-body .hiddenid").val(passedID);
});
</script>
}

Reloading of layout causes Model to go empty (MVC4)

I'm trying to show a table of results in my view by use of HttpPost, but my view always turns up empty.
I have found out by now that the httpPost action works and returns a result, but before completing the action, the layout is called again, where the RenderBody is called again. Once the RenderBody is done, the view contains an empty model again and results in the page showing up empty.
Looking for advice how to solve this issue! I broke my head on this for hours and don't seem to see the light...
The View code:
#using MovieRental.DAL.Entities; #model List
<Movie>
#{ ViewBag.Title = "MyRentedMovies"; }
<h2>MyRentedMovies</h2>
<div class="container">
<div class="col-md-12 column">
<form id="frmmymovies" class="col-md-12">
<input id="currentuserid" type="hidden" name="userid" value="#ViewBag.user.UserId">
</form>
<div id="mymovies" class="btn btn-primary">Show my rented movies</div>
</div>
</div>
<div>
#ViewBag.cost;
</div>
#if (Model != null) {
<div class="container">
<div class="row clearfix">
<div class="col-md-12 column">
<table id="" class="table table-striped table-bordered">
<thead>
<tr>
<th>Action</th>
<th>Movie Title</th>
<th>Release Date</th>
<th>Storyline</th>
<th>Location</th>
<th>Movie Genre</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Action</th>
<th>Movie Title</th>
<th>Release Date</th>
<th>Storyline</th>
<th>Location</th>
<th>Movie Genre</th>
</tr>
</tfoot>
<tbody>
#foreach (var item in Model) {
<tr>
<td><i class="glyphicon glyphicon-plus" movieId="#item.MovieId"></i>
</td>
<td>#item.MovieName</td>
<td>#item.ReleaseDate</td>
<td>#item.Storyline</td>
<td>#item.Location.LocationName.ToString()</td>
<td>#item.MovieGenre.GenreName.ToString()</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
} else {
<div class="container">
<div class="row clearfix">
<div class="col-md-12 column">
<div class="alert alert-info" role="alert">
You currenty don't have any rented movies in your possession.
</div>
</div>
</div>
</div>
}
The Controller code:
public ActionResult MyRentedMovies()
{
return View();
}
[HttpPost]
public ActionResult MyRentedMovies(int userid)
{
var myrentdetails = rentrep.GetAll().Where(e => e.UserId == userid);
List<Movie> mymovies = new List<Movie>();
foreach (var item in myrentdetails)
{
Movie movie = movierep.FindById(item.MovieId);
mymovies.Add(movie);
}
return View(mymovies);
}
The JS script:
$(function () {
$('#mymovies').click(function () {
//var user = $('#currentuserid').val();
console.log('gethere');
$.post('/useronly/myrentedmovies', $('#frmmymovies').serialize(), function (data) {
if (data) {
console.log(data);
document.location = '/useronly/myrentedmovies';
}
else {
console.log('error');
}
});
});
});