I've got a navbar at the top of my ASP.Net CORE site and I'm trying to create dynamic menu options. So far, I'm just trying to replace some of the options on the _layout page with a ViewComponent like I've done in a few other projects.
<header>
<nav class="navTop">
<a class="logo" asp-controller="Home" asp-action="Index">
<img src="~/Images/logo.svg" />
</a>
#{ await Component.InvokeAsync("MainMenu"); }
#{ await Html.RenderPartialAsync("_LoginPartial"); }
</nav>
</header>
I have my Component View in the folder
Views > Shared > Components > MainMenu > Default.cshtml
Which looks like this:
#model IEnumerable<MyProject.Models.Home.MainMenuItem>
#foreach (var item in Model)
{
#Html.ActionLink(item.DisplayText, item.Action, item.Controller)
}
And the ViewComponent InvokeAsync looks like:
public async Task<IViewComponentResult> InvokeAsync()
{
var x = new DataAccess.Menus.Menu(_context).GetMainMenuItems(User.Identity.Name);
return View(x);
}
And the DataAccess method is simply returning a List of MyProject.Models.Home.MainMenuItem as expected, which has everything populated fine when I step through, but nothing is resulting on the page in the in place of #{ await Component.InvokeAsync("MainMenu"); }!
I've done this before in a few other projects and never had a problem - so I don't know why this could be going wrong. Any ideas?!
It's getting to the view and I can even see it stepping through the foreach loop with the correct populated properties so why does nothing show up on the page?
You should write it like this
#{ #await Component.InvokeAsync("MainMenu") }
Or directly
#await Component.InvokeAsync("MainMenu")
Related
I wanted to implement a simple pagination, and PagedList.MVC NuGet package sounded like the best solution for me. HOWEVER, when I click on generated buttons to go to 2nd, 3rd, etc. page, 1st one remains active, and all that happens is refresh of the first page, but I obviously want it to navigate to the expected page...
I followed these two tutorials to see if I've done everything right:
Github
Microsoft
My controller:
public ActionResult Index(int? pageNumber)
{
var modelList = _employeeService.GetEmployeeViewToPagedList(pageNumber);
return View(modelList);
}
The service method that gets called (I know that "ToPagedList()" is usually called from the controller, but the current state is a result of trying everything, and the fact that I get "DbContext disposed" error if I modify to return something like "View(modelList.ToPagedList(pageNumber, pageSize))" from the controller):
public IPagedList<EmployeeView> GetEmployeeViewToPagedList(int? pageNumber)
{
using (var _unitOfWork = UnitOfWork.GetUnitOfWork())
{
var list = (IQueryable<EmployeeView>)_unitOfWork.context.EmployeeViews.OrderByDescending(x => x.Id);
return list.ToPagedList((pageNumber ?? 1), 10);
}
}
My view:
#model PagedList.IPagedList<Company.DAL.Views.EmployeeView>
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Index";
}
<h2>List of all employees</h2>
<p>
#Html.ActionLink("Add new employee", "AddNewEmployee")
</p>
#if (Model != null && Model.Count() > 0)
{
<table class="table">
... all needed <tr>'s, <th>'s, <td>'s ...
</table>
<br/>
#Html.PagedListPager(Model, page => Url.Action("Index", new { page, pageSize =
Model.PageSize }))
}
I am trying to figure this out for days now, and the closest I got was this question, but I am not sure where to find that JS function, so I could try that as well.
EDIT:
Generated HTML:
<div class="pagination-container">
<ul class="pagination">
<li class="active"><a>1</a></li>
<li>2</li>
<li>3</li>
<li class="PagedList-skipToNext">ยป</li>
</ul>
</div>
I decided to post an answer here, since I solved the problem, and somebody else might find this useful.
So, in the controller, my Index method looks like this:
public ActionResult Index(int? pageNumber)
{
//some logic
}
As you can see, it accepts an int variable named pageNumber as a parameter.
But then there's this on my view:
#Html.PagedListPager(Model, page => Url.Action("Index", new { page, pageSize = Model.PageSize }))
SO, here I am passing a variable named page to my Index method.
That's the mistake! Variable in the method parameter list has to be named page as well.
I am testing if I iterate correctly trough my list of results. To do this i created a PartialView which creates a new Div with the word 'Nice'. As you can see in the image I know for sure that there are 100 results but it seems that the Foreach loop doesn't work. Should I iterate in a different way?
Webresult:
Code:
Controller (FeedController.cs)
public ActionResult Index()
{
return View();
}
public ActionResult _Feed()
{
return PartialView(getStatusses());
}
private List<LinqToTwitter.Status> getStatusses()
{
//Code to get tweets
}
View (Index.cshtml)
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div>
#{
Html.Action("_Feed");
}
</div>
PartialView (_Feed.cshtml)
#model List<LinqToTwitter.Status>
<div id="FeedPosts">
#foreach (var item in Model)
{
<div>
Nice
</div>
}
</div>
When calling Html.Action(), you need to instruct Razor to append the results of the action to the output using the # symbol:
#Html.Action("_Feed");
Otherwise, it simply returns an MvcHtmlString that you don't use.
This applies even when the call is made inside a code block (#{...}):
#{
#Html.Action("_Feed");
}
See MSDN
I just trying to change my usercontrol function to razor function.but the page load time by using razor function is more than usercontrol function can any one know why this time taken.here is my razor code
#inherits RazorFunction
#using System.Linq;
#using Composite.Data;
#using Atc.Data;
#using System.Web.UI.WebControls;
#using System.Collections.Generic;
#functions {
public override string FunctionDescription
{
get { return "Function for footer"; }
}
}
<ul>
<li>##Copyright 2012 </li>
#{
using(DataConnection dCon =new DataConnection())
{
SitemapNavigator sn = new SitemapNavigator(dCon);
PageNode p = sn.CurrentHomePageNode;
List<PageNode> hiddenPages = dCon.Get<Page_Settings>()
.Where(x => x.FooterNavVisibility == true).OrderBy(x => x.Position)
.Select(x => sn.GetPageNodeById(x.PageId))
.ToList<PageNode>();
foreach (var item in hiddenPages)
{
<li>#item.Title</li>
}
}
}
<li>
<!-- AddThis Button BEGIN -->
<div class="addthis_toolbox addthis_default_style ">
<a class="addthis_button_compact"></a>
<a class="addthis_counter addthis_bubble_style"></a>
</div>
</li>
</ul>
<script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid=ra-5008fecf0e8dcc29"></script>
It could be that actual UserControl's execution time was accounted in the line "ASP.NET controls: PageLoad, EventHandling, PreRender", which currently takes 91 ms.
On a side note: now need to create new DataConnection/SitemapNavigator objects -> there are Data, and SitemapNavigator properties on the base class for the razor functions.
If you want to optimize it, you can f.e. cache the "hiddenPages" variable, and clear cache on Page or PageSettings data type changes.
I have a page with a video at the top and a list of videos you can choose from. Currently, clicking a link in the video list will reload the entire page. I need it to only refresh the partial view I have containing the video at the top of the page.
I saw several posts here on SO showing how to reload partial views with JQuery, but couldn't get it to work correctly in my situation. I'm unsure how to pass the correct id of the video along.
Controller:
public ActionResult Videos(int topVideo = 0)
{
VideosModel model = new VideosModel();
model.Videos = StatsVideoService.GetEntityList(new Lookup(TableStatsVideo.IsDeleted, false)).OrderByDescending(x => x.DateCreated).ToList();
if (topVideo == 0)
model.TopVideo = model.Videos.First();
else
{
model.TopVideo = model.Videos.Where(x => x.StatsVideoId == topVideo).FirstOrDefault();
if (model.TopVideo == null)
model.TopVideo = model.Videos.First();
}
return View(model);
}
View:
#model Project.Models.VideosModel
<section class="videos">
<div id="top_video">
#{Html.RenderPartial("StatsVideo", Model.TopVideo);}
</div>
<ul>
#foreach (var item in Model.Videos)
{
<li>
<div class="videoList">
<a href ="#Url.Action("Videos", "Home", new { topVideo = item.StatsVideoId })">
<img src="#Url.Content("~/Content/img/video-ph.png")" />
</a>
<p class="videoTitle">#item.Title</p>
</div>
</li>
}
</ul>
</section>
If there's any more information needed, please let me know.
After several hours of bashing my head against the wall, I got it to work! Just as a reference to anyone else in the future who's viewing this article, here's how I got it to work:
I set the onclick of the link to point to a javascript method, passing in the id of the video as a parameter:
#foreach (var item in Model.Videos)
{
<li>
<div class="videoList">
<a href ="#" onclick="updateTopVideo(#item.StatsVideoId)">
<img src="#Url.Content("~/Content/img/video-ph.png")" />
</a>
<p class="videoTitle">#item.Title</p>
</div>
</li>
}
And then I included this script in the view at the bottom:
<script>
var updateTopVideo = function (itemId) {
var url = '#Url.Content("~/Home/StatsVideo/")';
url = url + itemId;
$.get(url, "", callBack, "html");
};
var callBack = function (response) {
$('#top_video').html(response);
};
</script>
Finally, I added a method to my controller that would return the partial view needed for the video at the top of the screen:
public ActionResult StatsVideo(int Id)
{
IStatsVideo vid = StatsVideoService.GetEntity(new Lookup(TableStatsVideo.StatsVideoId, Id));
if (vid == null)
vid = StatsVideoService.GetEntityList(new Lookup(TableStatsVideo.IsDeleted, false)).OrderByDescending(x => x.DateCreated).FirstOrDefault();
return PartialView(vid);
}
This code should be fairly easy to understand. Basically, the onclick calls the first javascript method, which then calls the controller. The controller builds the partial view and returns it. The first javascript method passes it to the second javascript method which sets the html of the div "top_video" to be the returned partial view.
If anything doesn't make sense, or anyone's having trouble with this in the future, let me know and I'll do my best to offer some help.
I think there may be several confusing and inconsistent elements here.
First, you are returning a full view instead of a partial view. This reloads all containing elements, not just the part that is relevant to your partial view.
Second, you are using Url.Action, which only generates the url. I would recommend using Ajax.ActionLink, which allows you to do fully ajax calls, refreshing the content of your partial div and updating a target div element.
instead of:
<div class="videoList">
<a href ="#Url.Action("Videos", "Home", new { topVideo = item.StatsVideoId })">
<img src="#Url.Content("~/Content/img/video-ph.png")" />
</a>
<p class="videoTitle">#item.Title</p>
</div>
try the more modern solution
<div class="videoList">
#Ajax.ActionLink(
"Videos",
"Home",
"new { topVideo = item.StatsVideoId },
new AjaxOptions {
HttpMethod = "GET",
OnSuccess = "handleSuccess"
}
)
</div>
This way you can be very specific on what you want each link to do, and you can pass along multiple parameters as well as define a callback function. You can also use "UpdateTargetId" in your ajax options to load your newly refreshed partial view into a DOM element.
You can remove the around the image and just store the url generated by the Url.Action in a data-href attribute.
Then you can use the jquery load method to load the data:
$(".videolist>img").click(function () {
$("#content").load($(this).data("href"));
});
I created a fiddle that loads content dynamically here, so you can play with it if you want: http://jsfiddle.net/bTsLV/1/
I am faced with a problem with ASP.NET MVC 3 with the Razor rendering engine (C#). I am using multiple Html.RenderAction() methods within a view and only the layout is rendered.
One important note before continuing: I can't copy any of the code because I do not have the intellectual property rights to do so. :(
Anyway, I noticed that if I used the following syntax #{ RenderSection("SectionName", true); } instead of #RenderSection("SectionName", true) there was a generic exception that simply says that it was unable to render the sections with a stack trace that seemed to say that there might be some asynchronous problem. Between, I am using synchronous controllers so maybe this is a lead, but I don't know much on synchronous/asynchronous controllers and when one should use them for certain situations.
To put everything in context, here is what I am trying to do in code/pseudo code/site structure...
~/View/Shared/_ViewStart.cshtml
(Selects a layout according to certain conditions.)
~/View/Shared/_Layout1.cshtml
<! doctype HTML>
<html>
<head>
<!-- some irrelevant content here... -->
</head>
<body>
<div id="page">
<div id="header">
#RenderSection("Header", true)
</div>
<div id="content">
<div id="main1">
#RenderSection("Table1", true)
#RenderSection("Table2", true)
</div>
<div id="main2">
#RenderSection("Content", true)
</div>
</div>
<div id ="footer">
#RenderSection("Footer", true)
</div>
</div>
</body>
</html>
~/View/Shared/_Layout2.cshtml
(another layout)
~/View/Controller1/Action1.cshtml
#section Header
{
#RenderPage("~/Views/Shared/Sections/Header")
}
#section Footer
{
#RenderPage("~/Views/Shared/Sections/Footer")
}
#section Table1
{
#{ RenderAction("Table1", "Table"); }
}
#section Table2
{
#{ RenderAction("Table2", "Table"); }
}
#section Content
{
#{ RenderAction("Action", "Content"); }
}
~/View/Controller1/Action2.cshtml
(similar to Action1.cshtml)
~/Utilities/ModelManager.cs
public abstract class ModelManager : Controller
{
//Some useful code for controllers here...
}
~/Controller/Controller1.cs
public class Controller1 : ModelManager
{
#region Get Methods
public ViewResult Action1()
{
return View();
}
public ViewResult Action2()
{
return View();
}
#endregion
#region Post Methods
public ViewResult Action1(FormCollection form)
{
return View();
}
public ViewResult Action2(FormCollection form)
{
return View();
}
#endregion
}
~/Controller/Controller2.cs
(another controller similar to Controller1)
~/Controller/Table.cs
(Only important thing to note is that the actions are returning PartialViewResult.)
~/Controller/Content.cs
(Only important thing to note is that the action is returning PartialViewResult.)
~/Model/Entities.edmx
(Generated with Entity Framework Wizard.)
* Edit *
The #Html.Action(...) worked, but I would really like to know why the #Html.RenderAction(...) didn't work. Any suggestions are welcome. :)
As an alternative, I would suggest trying to switch to:
#Html.Action("actionMethod","controller")
This extension helper works similarly to RenderAction, but returns MvcHtmlString, instead of writing directly to the Output buffer (Response stream).
The Html.RenderAction is a method returns void. So you must put a ";" at the end. As for the exception, you might want to try to debug into it and see what the variables are set to etc if you would like to stick with that helper method.
Hopefully that helps.
Try this:
#section Table1
{
RenderAction("Table1", "Table");
}
For RenderAction, you have to put it withing a brace like the one shown bello
#{Html.RenderAction(...);}
Hope this help someone.