I am trying to dynamically create my top navigation panel in ASP.NET Core MVC 6.
I know it's simple but I cannot figure out how to make it work. Here is what I do (simplified):
My Model:
public class IP_Category
{
public int id { get; set; }
public string DisplayName { get; set; }
}
in my controller:
public IActionResult Index()
{
//This way I dynamically pass data to my View
ViewBag.Categories = _repository.ReturnCategories();
return View();
}
in my cshtml page:
#{
//this info is in the top of the page, here I retrieve data passed from
//controller and save it as a local variable
var categories = (List<IP_Category>)ViewBag.Categories;
}
Then later in the _Layout where I take care of the navigation:
<ul class="nav navbar-nav">
<li><a asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-controller="Home" asp-action="About">About</a></li>
<li><a asp-controller="Home" asp-action="Contact">Contact</a></li>
#foreach (var category in categories)
{
<li><a asp-controller="Home" asp-action="#category.DisplayName">#category.DisplayName</a></li>
}
</ul>
The problem occurs with asp-action="#category.DisplayName" which does not generate appropriate href in my actual page.
So the question is what am I doing wrong? How can I pass category.DisplayName to my asp-action tag so the links work correctly?
Edit 1 - Adding more code:
Here is what was generated (note the missing href tag)
<ul class="nav navbar-nav">
<li>Home</li>
<li>About</li>
<li>Contact</li>
<li>Item1</li>
<li>Item2</li>
</ul>
if the controller and action don't match an existing controller and action then no href will be rendered. I suspect that #category.DisplayName does not match any actual action name on your home controller. Seems more likely that you have an action named Category that expects a parameter corresponding to the #category.DisplayName so it should be passed as a route parameter not as the action name
#foreach (var category in categories)
{
<li><a asp-controller="Home"
asp-action="Category"
asp-route-category="#category.DisplayName">#category.DisplayName</a></li>
}
Related
I have a MyMessages model that I put data into when the user logs in. it includes all the data needed.
for every message that they have I do the following in view
for (int i = 0; i < Model.MyMessagesCount; i++)
{
<li class="list-group-item d-flex align-items-center mt-2">
<a>#Model.MessagesTitles[i]</a>
</li>
When the user clicks on each of the <a>, I want to show them that message in more details in a separate view where I pass MessageID to.
How can I achieve that? How can I have all the <a> call the same action but with different MessageID as a parameter? (Something like this /User/Usermessages?MessageID=20)
You can use anchor tag helper
<li>
<a asp-controller="user"
asp-action="messages"
asp-area=""
asp-route-messageId="#Model.MessagesTitles[i].MessageId">
#Model.MessagesTitles[i]
</a>
</li>
asp-route-{parameter}: the parameter there is the name of the parameter you define in your action.
You can read more on https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/built-in/anchor-tag-helper?view=aspnetcore-5.0
In the Index.cshtml page, you could directly set the a tag href attribute.
Code sample as below:
public IActionResult Index()
{
List<MyMessages> messages = new List<MyMessages>()
{
new MyMessages(){ MessageId=1001, MessageTitile="AA"},
new MyMessages(){MessageId =1002, MessageTitile="BB"},
new MyMessages(){MessageId=1003, MessageTitile="CC"}
};
return View(messages);
}
public IActionResult Details(int messageId)
{
return View();
}
Index.cshtml page:
#model List<SignalRChatSample.Models.MyMessages>
<ul>
#for (int i = 0; i < Model.Count(); i++)
{
<li class="list-group-item d-flex align-items-center mt-2">
#Model[i].MessageTitile
</li>
}
</ul>
Then, the result like this (The url: Https://localhost:5001/Home/Details?messageId=1002):
Besides, as David said, you could also send the parameters via the route.
So I created dropdown menu in _Layout.cshtml.
<ul class="nav navbar-nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-expanded="false"><span>Menu</span></a>
<ul class="dropdown-menu" role="menu">
<li>#Html.ActionLink("FirstAction", "Action", "Controller1")</li>
<li>#Html.ActionLink("Second", "second", "Controller2", new { wszystko = true })</li>
<li>#Html.ActionLink("Third", "Third", "Controller3")</li>
</ul>
</li>
</ul>
On every run I can only once choose position from the menu. When I try to pick different action, application didn't see I want to change Controller. When I want to change action, application always searches in controller I'm currently in.
For example: if I am in Controller1/Action and I want to go to Controller2/Second, program always search for Controller1/Second action result.
Before I created that menu, links work fine. Can somebody tell me why is it happening?
The only overload for ActionLink that takes four parameters is:
HtmlHelper.ActionLink(string linkText, string actionName, object routeValues, object htmlAttributes)
Note there is no controller name. You need to use
HtmlHelper.ActionLink(string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
For example
#Html.ActionLink("Second", "second", "Controller2", new { wszystko = true }, null)
You are using Html.ActionLink method overload incorrectly.
Use this overload. The fifth parameter is to specify any html attributes for the element (Ex : css class name etc). If you do not have any, just pass null
#Html.ActionLink("Second", "second", "Controller2", new { wszystko = true },null)
I am using MVC PagedList to handle pagination in my project. Everything works fine except that in my controller I have to initialize pageNumber parameter with "1" (Default page number). The problem is the blue activated button on page 1 that remains there no matter which page button link you click. Moreover this button is also missing the actionLink.
One last thing I am integrating my search with pagination as you can see in the controller code.
public PartialViewResult List_Items(string keyword, int? page)
{
var newlists = from s in db.TrMs
orderby s.S1
select s;
int pageNumber = (page ?? 1);
int pageSize = 10;
var data = newlists.Where(f => f.S1.ToString().Contains(keyword) && f.S100 == vt).ToPagedList(pageNumber, pageSize);
return PartialView(data);
}
Here is the generated Html for PagedList in my view
<div class="pagination-container">
<ul class="pagination">
<li class="active">
<a>1</a>
</li>
<li>
<a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#searchResult" href="/TrM/Search_Items?keyword=&page=2">2</a>
</li>
<li>
<a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#searchResult" href="/TrM/Search_Items?keyword=&page=3">3</a>
</li>
<li>
<a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#searchResult" href="/TrM/Search_Items?keyword=&page=4">4</a>
</li>
<li class="PagedList-skipToNext">
<a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#searchResult" href="/TrM/Search_Items?keyword=&page=2" rel="next">ยป</a>
</li>
</ul>
</div>
Here is how I am using the pagination helper.
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("List_Items", "TrM", new {keyword="", page }), PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing(new AjaxOptions() { HttpMethod = "GET", UpdateTargetId = "searchResult" }))
Your paging controls are most likely outside of the searchResult container. When you click on a page you're replacing the table but not the paging controls. Move your paging controls inside of your searchResult container!
Hope this helps.
First of all sorry about the bad title but i didn't know how to describe my problem correctly.
Well, i am quite new to asp .net so go on easy on me ^^
I have html file with a structure like the following :
<ul id="Ministries">
<li id="Ministry1"> Ministry1 title</li>
<li id="Ministry2"> Ministry2 title </li>
<li id="Ministry3"> Ministry3 title </li>
</ul>
<ul id="ministryDescriptions">
<li id="Ministry1Description">
<div id="Ministry title" class="x"> Ministry1 description</div>
<li id="Ministry1Services">
<ul id="Ministry1servicesTtiles">
<li id="Ministry1Service1">Ministry1Service1Title</li>
<li id="Ministry1Service2">Ministry1Service2Title</li>
<li id="Ministry1Service3">Ministry1Service3Title</li>
</ul>
<ul id="Ministry1servicesDetails">
<li id="Ministry1Service1Details">
<div id="service1description" > desc service1 of ministry1</div>
<p>whatever here</p>
<ul id="Ministry1Service1RequiredDocs">
<li id="Ministry1Service1RequiredDoc1">Doc1</li>
<li id="Ministry1Service1RequiredDoc2">Doc2</li>
<li id="Ministry1Service1RequiredDoc3">Doc3</li>
</ul>
</li>
<li id="Ministry1Service2Details"></li>
<li id="Ministry1Service3Details"></li>
</ul>
</li>
</li>
<li id="Ministry2Description"> </li>
<li id="Ministry3Description"> </li>
</ul>
I am getting objects from database in a List where Ministrry has attributes like
public class MinistryModel
{
public string MinistryName { get; set; }
public string MinistryMission { get; set; }
public string MinistryVision { get; set; }
public string MinistrySpecialities { get; set; }
public string MinistryUrl { get; set; }
public List<string> MinistryServices { get; set; }
}
I need to find a way to generate this structure in that exact html form and structure with the database objects.
I used to use Asp:ListView bit in this case the ul and li are not (all) nested, this is why i am a bit lost.
I hope you understood my problem and waiting forward for some help.
PS: I can't change HTML structure i must use it as it is
I'm not sure what source your data is coming from so this is general code for use of DataList for your example.
<asp:DataList ID="DataListTitles" runat="server" >
<HeaderTemplate><ul></HeaderTemplate>
<ItemTemplate> DataBinder info for Ministry# title</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:DataList>
<asp:DataList ID="DataListDescriptions" runat="server">
<HeaderTemplate>
<div>DataBinder info for Ministry# Description</div><ul>
</HeaderTemplate>
<ItemTemplate>
-DataBinder info for Ministry# Service# Titles
-DataBinder info for Ministry1servicesDetails
-DataBinder info for Docs
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:DataList>
You might need to use nested Listviews to have the exact output.
Or simply create the HTML code dynamically on codebehind.
I have built an mvc 4 website, and I built it so that the main layout page doesn't refresh if a different section is loaded with jQuery. I put the navigator and jQuery script in _Layout.cshtml:
<ul id="menu" class="menu-items">
<li><a id="Item1" href="#" onclick="loadPage(this.id)">Item1</a></li>
<li><a id="Item2" href="#" onclick="loadPage(this.id)">Item2</a></li>
<li><a id="Item3" href="#" onclick="loadPage(this.id)">Item3</a></li>
<li><a id="Item4" href="#" onclick="loadPage(this.id)">Item4</a></li>
</ul>
</body>
<script>
function loadPage(action) {
$.post("/Home/" + action, function (data) {
$(content).html(data);
});
}
</script>
Then I have my controller:
namespace MyApp.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Item1()
{
if (Request.IsAjaxRequest())
{
return PartialView();
}
return View();
}
[HttpPost]
public ActionResult Item2()
{
if (Request.IsAjaxRequest())
{
return PartialView();
}
return View();
}
Etc, etc.
Everything works fine, except that I don't know how to use just one main content view (which is index.cshtml when the website loads in the browser). I'm forced to put the same content that's in index.cshtml into item1.cshtml so that when I trigger onlick for item1, it will go back to the main content. The only route config I have is for the Default, which initially set to Index:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
What I want, is to be able to use just one main content page, but have the ajax call still get me back to the main content when I click Item1. Does anyone know what I need to do? It seems to be a little overkill to have to update both views when I want to update the main content.
Also, I think other web devs will like this code. Especially if you're building a band's website like I'm doing. It allows me to put the demo song media player in the _layout.cshtml page so that it won't refresh when the user is clicking to the other sections (i.e. if it refreshes, the media player stops). With this design, the user can navigate the whole website while the songs continue to play.
I'm rather new to javascript, so I'm sure I could have made a better onclick handler rather than using anchor tags, so if anyone want to show me a better way, please do. But my main problem is the index.cshtml vs item1.cshtml dilemma.
Correct me if I'm wrong: you want to refresh part of your page when clicking on ItemX link and the controller methods ItemX are only used via Ajax (as you're building a single page app).
In this case you could do something like this:
Cshtml
<ul id="menu" class="menu-items">
<li><a id="Item1" href="#" onclick="loadPage(this.id)">Item1</a></li>
<li><a id="Item2" href="#" onclick="loadPage(this.id)">Item2</a></li>
<li><a id="Item3" href="#" onclick="loadPage(this.id)">Item3</a></li>
<li><a id="Item4" href="#" onclick="loadPage(this.id)">Item4</a></li>
</ul>
<div id="container">
</div>
</body>
<script>
function loadPage(action) {
$.post("/Home/" + action, function (data) {
$("#container").html(data);
});
}
// Will load Item1 via Ajax on page load
loadPage('Item1');
</script>
Home Controller
[HttpPost]
public ActionResult Item1()
{
return PartialView();
}
Your PartialViews should only contain the HTML specific to the current item.
Update
If you wish to avoid the Ajax call you could do this also in your cshml
...
</ul>
<div id="container">
#Html.Partial("Item1PartialView")
</div>
</body>
...