ASP.NET MVC - Html.Action not rendering the partial view - c#

EDIT: Problem solved! I had no data in my database, so the foreach loop had no model items to iterate through. Upon populating the database, the HTML within the foreach loop is rendering correctly on the view.
My brain is currently hurting due to this problem I have with my partial view not being rendered within my Home/Index view.
I am trying to use Html.Action() helper to call my PhotoGallery action within my Photos controller in order to dynamically populate and return a _PhotoGallery.cshtml partial view.
Here is my PhotoGallery action in my Photos controller:
[ChildActionOnly] //This attribute means the action cannot be accessed from the brower's address bar
public ActionResult PhotoGallery(int num = 0)
{
//In the view, display the latest photos when num is greater than 0
//Otherwise, display all photos
List<Photo> photos;
if (num == 0)
{
photos = db.Photos.ToList();
}
else
{
photos = db.Photos
.OrderByDescending(p => p.createdDate)
.Take(num).ToList();
}
return PartialView("~/Views/Shared/_PhotoGallery.cshtml", photos);
}
Views/Home/Index.cshtml:
#{
ViewBag.Title = "Welcome to PhotoSocial";
}
<p class="lead">Create an account to instantly share your favourite moments with everyone.</p>
<h2>Latest Photos:</h2>
#Html.Action("PhotoGallery", "Photos", new { num = 3 })
Views/Shared/_PhotoGallery.cshtml:
#model IEnumerable<SocialNetwork.Models.Photo>
#{
Layout = null;
}
#foreach (var item in Model)
{
<div class="" id="photo-gallery">
<h3>
#Html.DisplayFor(modelItem => item.title)
</h3>
#if (item.photoFile != null)
{
<div class="photo-display">
<img class="" src="#Url.Action("GetImage", "Photo", new { photoId = item.photoId})" />
</div>
}
<div class="" id="photo-data">
<div>
<div class="" id="display-label">
<p>Uploaded by:</p>
</div>
<div class="display-field">
#Html.DisplayFor(modelItem => item.username)
</div>
</div>
<div>
<div class="" id="display-label">
#Html.DisplayNameFor(model => model.createdDate):
</div>
<div class="display-field">
#Html.DisplayFor(modelItem => item.createdDate)
</div>
</div>
<div>
<div class="" id="display-label">
#Html.DisplayNameFor(model => model.modifiedDate):
</div>
<div class="display-field">
#Html.DisplayFor(modelItem => item.modifiedDate)
</div>
</div>
</div>
#Html.ActionLink("Details", "Details", new { id = item.photoId }) |
#Html.ActionLink("Delete", "Delete", new { id = item.photoId })
</div>
}
Here is the HTML source code that is rendered upon loading up Home/Index:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to PhotoSocial</title>
<link href="/Content/bootstrap.css" rel="stylesheet"/>
<link href="/Content/site.css" rel="stylesheet"/>
<script src="/Scripts/modernizr-2.8.3.js"></script>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">PhotoSocial</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>Home</li>
<li>About</li>
<li>Contact</li>
<ul class="nav navbar-nav navbar-right">
<li>Login</li>
<li>Register</li>
</ul>
</ul>
</div>
</div>
</div>
<div class="container body-content">
<p class="lead">Create an account to instantly share your favourite moments with everyone.</p>
<h2>Latest Photos:</h2>
<hr />
<footer>
<p>© 2019 - Thomas Dam</p>
</footer>
</div>
<script src="/Scripts/jquery-3.3.1.js"></script>
<script src="/Scripts/bootstrap.js"></script>
</body>
</html>
As you can see in the final output, my Home/Index.cshtml and _Layout view have correctly rendered, however my _PhotoGallery partial view has not been rendered.
I have tried Html.RenderAction() but I need the model to map a photo to the view. I have also tried Html.RenderPartial() but I need to return a Model object. One thing I've noticed, though, is that when I place HTML outside of the #foreach loop, it appears on my view!
What is it that I am doing wrong? Thanks guys.

Related

How to Display Descriptive List Group in .NET core?

I wish to create a UI like this using .NET core MVC framework.
what should my view be like?
i tired looping through each data model and embedding razor code into the same bootstrap tempate but i'm not getting anywhere near the desired functionality.
<div class="container h-100 w-100">
<div class="row w-100 ml-0 mr-0 mt-0 mb-0">
<div class="col-3">
<div class="list-group" id="list-tab" role="tablist">
#{
foreach(var user in Model)
{
<a class="list-group-item list-group-item-action" id="list-#user.FirstName-list" data-toggle="list" href="##user.FirstName" aria-controls="#user.FirstName" role="tab">
#Html.DisplayFor(modelItem => user.FirstName)
</a>
}
}
</div>
</div>
<div class="col-9">
<div class="tab-content" id="nav-tabContent">
#{
foreach(var user in Model)
{
<div class="tab-pane fade show " id="list-#user.FirstName" role="tabpanel" aria-labelledby="list-#user.FirstName-list">
<p>#Html.DisplayFor(modelItem => user.FirstName)</p>
</div>
}
}
</div>
</div>
</div>
</div>
The first part of the list group is getting displayed but when i try clicking on it, i dont get to see the description
First, you are appending "list-" to id of your .tab-pane, while the href for list item does not have that prefix.
Second, you can make the first active selection via JavaScript. Avoid putting fade show in your razor code, or put the condition in loop such that it should add it to only first element.
HTML :
<div class="col-3">
<div class="list-group" id="list-tab" role="tablist">
#foreach (var user in Model)
{
<a class="list-group-item list-group-item-action" id="list-#user.FirstName-list" data-toggle="list" href="##user.FirstName" aria-controls="#user.FirstName" role="tab">
#Html.DisplayFor(modelItem => user.FirstName)
</a>
}
</div>
</div>
<div class="col-9">
<div class="tab-content" id="nav-tabContent">
#foreach (var user in Model)
{
<div class="tab-pane" id="#user.FirstName" role="tabpanel" aria-labelledby="list-#user.FirstName-list">
<p>#Html.DisplayFor(modelItem => user.FirstName)</p>
</div>
}
</div>
</div>
</div>
</div>
JS :
<script>
$(".tab-pane").first().addClass("fade show active");
$(".list-group-item").first().addClass("active");
</script>

How to show loader image until controller method completes in ASP.NET MVC?

I have an Index page like below and on button click I have some code to save data into database and then it goes on details page.
But I the code should go to the details page only after completing the database save operation; I want to show a loader image until then; how can I do this?
Currently I'm using begin post to post method and bind all model not using any ajax call. How can I show loader image and render before process complete to details page?
Index.cshtml
#model Dev.Models.DeviceReg
#using (Html.BeginForm("AddAsync", "Home", FormMethod.Post))
{
<div class="panel panel-primary">
<div class="panel-body">
<div class="row">
<div class="col-md-6">
<h4 id="aa">Name</h4>
<label>Select</label>
<table>
<tr>
<td>
#Html.DropDownListFor(m => m.Name, (SelectList)ViewBag.Name, "---Select Name---")
</td>
</tr>
</table>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4 id="aa">Model</h4>
<label>Select</label>
<table>
<tr>
<td>
#Html.DropDownListFor(m => m.Type, (SelectList)ViewBag.TypeName, "---Select Type---")
</td>
</tr>
</table>
</div>
</div>
<div class="panel-footer" align="left">
<button type="submit" id="save" class="btn btn-success">
<span class="glyphicon glyphicon-arrow-right"></span> save
</button>
</div>
</div>
}
HomeController.cs
public async Task<ActionResult> AddAsync(DeviceReg deviceRegistration)
{
foreach (var deviceId in collection)
{
// save device information into database
Models.Device newDevice = new Models.Device()
{
Id = Guid.NewGuid(),
DeviceTypeId = deviceRegistration.DeviceType,
PlatformId = deviceRegistration.PlatformType,
DeviceId = deviceId,
};
_repository.InsertDevice(newDevice);
_repository.Save();
}
return View("Details", deviceRegistration);
}
Details.cshml
#model Dev.Models.DeviceReg
<body style="background-color:black">
<div class="panel panel-primary">
<div class="panel-heading" align="center">
<h2 class="panel-title">Details</h2>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-6">
<h3><label>Current Data</label></h3>
<br />
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4 id="aa">Name</h4>
<label>#Model.Name</label>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4 id="aa">Type</h4>
<label>#Model.TypeName</label>
</div>
</div>
<hr />
<br />
<label>Your process is running.</label>
<br />
<div class="row">
<div class="col-md-6">
<h3><label>Status</label></h3>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div style="clear: both">
<h2 style="float: left">10</h2>
<h6 style="float: right">Active Number</h6>
</div>
</div>
</div>
</div>
</div>
</body>
Well, if you need to show loader while post form is submitting, you can use javascript functions to show it, like
#using (Html.BeginForm("AddAsync", "Home", FormMethod.Post, new { onsubmit = "showLoader(this);" }))
{
...
}
plus JS
<script>
var showLoader = function(form){
$("<div />").css({
'position' : 'fixed',
'left' : 0,
'right' : 0,
'bottom' : 0,
'top' : 0,
'background' : '#0020ff36',
'z-index' : '99',
'text-align' : 'center'
}).appendTo($("body"))
.append(
$("<img />").attr("src", "https://mir-s3-cdn-cf.behance.net/project_modules/disp/35771931234507.564a1d2403b3a.gif")
);
}
</script>
or by jquery event, like
<script>
$("form").submit(function(){
//show loader
});
</script>
example of this code https://dotnetfiddle.net/gfEVSE
But, regarding to your clarification of the issue in comments, it's impossible to show Details page with progress of saving without Javascript or another additional requests.
Example without ajax but with aditional requests every N seconds
[HttpPost]
public ActionResult AddAsync(SampleViewModel deviceRegistration)
{
Task.Run(()=>
{
//Saving to DB
});
return RedirectToAction("Details", id = deviceRegistration.id);
}
public ActionResult Details(int id)
{
var isObjectExistInDb = checkIfExistInDb(id);
if (!isObjectExistInDb){
return View("ShowLoader", id);
}
return View(object);
}
where in ShowLoader.cshtml you need to reload page every N seconds.
With ajax it will be more clear, pretty code. Please, let me know, if you need example with ajax :)

Pagnation not updating target - Asp.Net Core using Ajax

I hope this is straight forward! I have a partial which loads just fine, it uses ajax to apply filters / sorting which works fine. However the pagination links send the correct url, and the response is the desired page, only it doesn't actually update/replace whats there.
Parent View:
#model Sakura.AspNetCore.IPagedList<YaCu_2017.Models.Review>
#{
ViewBag.Title = "Review Dashboard";
#using YaCu_2017.Controllers;
}
<p class="green-text">#ViewBag.StatusMessage</p>
<p class="red-text">#ViewBag.ErrorMessage</p>
<h2>Our Product Reviews</h2>
<div class="row">
<div class="col s2">
<h5>Filter by Product:</h5>
<form method="get">
#{
var product = ReviewController.GetProductListIncId();
var productCount = ReviewController.GetProductCountList();
ViewBag.ProductList = product;
ViewBag.ProductCount = productCount;
}
<select asp-items="#ViewBag.ProductList" id="searchProduct"
class="dropdown-button btn"></select>
<h5>Reviews per page</h5>
<select asp-items="#ViewBag.ProductCount" id="perPage"
class="dropdown-button btn"></select>
</form>
</div>
</div>
<p></p>
<div class="reviewView" id="filter">
#await Html.PartialAsync("ShowReviewDetails", Model)
</div>
Child View:
#model IPagedList<YaCu_2017.Models.Review>
#using System.Globalization
#using Sakura.AspNetCore
#using YaCu_2017.Controllers
#using YaCu_2017.Models
#{
ViewData["Title"] = "Digital Jeeves - Reviews";
}
<form method="post" data-ajax="true">
<div class="row">
<div id="pagerow" class="col s12 center center-align center-block">
<p>Page #(Model.TotalPage < Model.PageIndex ? 1 :
Model.PageIndex) of #Model.TotalPage<pager id="pager" class="pagination"
setting-link-attr-data-ajax-update="filter" setting-link-attr-data-ajax-
mode="replace" setting-link-attr-data-ajax="true" /></></p>
<cs-pager cs-paging-pagesize="#Model.PageSize"
cs-paging-pagenumber="#Model.PageIndex"
cs-paging-totalitems="#Model.TotalPage"
cs-pagenumber-param="page"
asp-route-perPage="#ViewData["Page"]"
asp-route-searchProduct="#ViewData["Product"]"
asp-controller="Review"
asp-action="GetProducts"
cs-ajax-target="filter"></cs-pager>
</div>
</div>
</form>
<hr />
<div id="stuff">
#foreach (var item in Model)
{
var stars = item.Stars.ToString();
var starurl = string.Format("images/stars/{0}_star.jpg", stars);
<div class="container opaque-parent z-depth-5">
<div class="row">
<div class="col s6"><h6 style="border-bottom:thin">Title :
#Html.DisplayFor(model => item.Title)</h6></div>
<div class="col s3"><h6 style="border-bottom:thin">Product :
#Html.DisplayFor(model => item.Product)</h6></div>
<div class="col s3"><h6 style="border-bottom:thin">Rated:
<img src="~/#starurl" class="responsive-img" id="#item.Id" /></h6></div>
</div>
<div class="row" style="">
<div class="col s12" style="border-bottom:inset">
<h6>Comment:</h6>
</div>
</div>
<div class="row" style="border-bottom:inset">
<div class="col s6 offset-s3">
<p class="flow-text">"#Html.DisplayFor(model =>
item.ReviewText)"</p>
</div>
</div>
<div class="row">
<div class="col s3">
<p>Date Created : #Html.DisplayFor(modelItem =>
item.CreatedDate)</p>
</div>
<div class="col s3">
<p>Chosen Display Name: #Html.DisplayFor(modelItem =>
item.DisplayName)</p>
</div>
</div>
</div>
<hr />
}
</div>
I thought that it may be because its a child trying to update a parent, but I cant find any info. I tried to put pagination outside of the target div, all that happend was the pagination never got updated when there were pages >1.
I'm new to this, only having made websites without ajax, until now! I figured the filter/sorting out, but I keep going around in circles here, I even tried a diferent nuget package for pagination Link to git, still no joy! Like I say, the next page is in the response, but it doesn't replace whats there.
Thanks :)
Figured it out... in the data-ajax-update="filter" I needed to add a hashtag infront of the element id e.g. data-ajax-update="#filter"... facepalm

How to call a search method in a _Layout.cshtml?

I'm trying to create a search method, that is called in my _Layout.cshtml and when I click on submit button, the user is redirected to "search view".
I' following this tutorial, but the author call your method at index view and I need to call the method at _Layout to be redirect to another view that will give me the return of method.
This is my _Layout, is basic a nav-bar from bootstrap with a textfield and a button, that the user can put what he need to find:
#model IEnumerable<TestTcc2.Models.Musica>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>#ViewBag.Title</title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<meta name="viewport" content="width=device-width" />
#Styles.Render("~/Content/Bootstrap")
#Scripts.Render("~/bundles/modernizr")
#Scripts.Render("~/bundles/jquery")
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">#Html.ActionLink("your logo here", "IndexOuvinte", "Home")</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li>#Html.ActionLink("Home", "IndexOuvinte", "Home")</li>
</ul>
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li>#Html.ActionLink("Manage Account", "Manage", "Account")</li>
<li>#using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm" }))
{
#Html.AntiForgeryToken()
Log off}</li>
</ul>
</div>
<!--/.nav-collapse -->
</div>
</div>
<div class="container">
#RenderSection("featured", required: false)
#RenderBody()
</div>
<!--Fim container -->
</body>
</html>
and this is the method that I want to call at _Layout.cshtml:
public ActionResult Search(string search)
{
var musicas = from m in db.Musicas select m;
if (!String.IsNullOrEmpty(search))
{
musicas = musicas.Where(s => s.Nome.Contains(search));
return RedirectToAction("Search"); //name of view that will return the data
}
return View(musicas);
}
Well, you might consider specifying an action to the form or just use the appropriate helper to generate it:
#using (Html.BeginForm("Search", "SomeController", null, FormMethod.Post, new { #class = "navbar-form navbar-left", role = "search" }))
{
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
}

ASP MVC Submit button not doing anything. At all

I have a (simple) ASP MVC view:
<div class="row">
<div id="dashboard-left" class="col-md-8">
#using (Html.BeginForm("ConfigureOffers", "Offers", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div style="padding-bottom: 10px;">
<p style="font-size: large;"><strong>Available</strong></p>
</div>
<div class="accordion" id="accordion2">
<div class="widget" style="background:#fff !important">
#{
int i = 0;
}
#foreach (var prod in Model.allProducts)
{
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle" data-toggle="collapse" data-parent="accordion2" href="#collapse#(i)">
<h4 class="widgettitle" id="QuickTitle">> #prod.Description_VC</h4>
</a>
</div>
<div id="collapse#(i)" class="accordion-body collapse" style="height: 0px;">
<div class="accordion-inner" style="margin-left: 10px;">
<div style="padding-bottom: 10px;"><strong>Total product:</strong> #{
for (int k = 0; k < Model.OfferHeaders.Count(); k++)
{
if (Model.OfferHeaders[k].Product_ID == prod.Product_ID)
{
#Html.TextBoxFor(o => o.OfferHeaders[k].Amount_DEC);
break;
}
}
}
</div> #*prod div*#
</div> #*accordion-inner*#
#{i++;}
</div>
<div style="clear:both;"></div>
</div>
}
<input type="submit" class="btn btn-default" value="Save Changes" />
</div> #*widget*#
</div> #*accordion*#
}
</div>
<!-- col-md-4 -->
</div>
<!--row-->
The basis of this view was taken from another (working page), but for some reason, clicking the submit button doesn't trigger the server action detailed in the BeginForm element. I get no errors from Visual Studio, nor any JavaScript errors from the browser console, and nothing seems to happen server-side.
One possible reason for Action not happening is mainly when you put
the action in the View and also created the page. but i think you
have forgot mentioning the ActionResult in the controller.
Another possible option is you have to use [HttpPost] above your
method in controller where you specified the ActionResult
[HttpPost]
public ActionResult ConfigureOffers(ModelClass instance)
{
...
}
Other possible reasons
The routes are not correct
The Form Action property is not correct
You are using nested FORM tags

Categories