How to add parameters in url.content - c#

I try create dynamic menu but i have problem with adding parameters in link to the controller and action, can i add parameter to url.content? or there are the other way please give your insight it will very helpfull
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">Menu Example</a>
</div>
<ul class="nav navbar-nav">
#if (Session["Menu"] != null)
{
var MenuMaster = (List<Accountstatement.Models.MenuModel>)Session["Menu"];
var groupByMenu = MenuMaster.GroupBy(x => x.MainMenuName).ToList();
foreach (var MenuList in groupByMenu)
{
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">#MenuList.Key<span class="caret"></span></a>
<ul class="dropdown-menu">
#foreach (var SubMenuList in MenuList)
{
<li>#SubMenuList.SubMenuName</li>
}
</ul>
</li>
}
}
</ul>
this is the part the url.content is, how can i put the parameter inside url.content?
<li>#SubMenuList.SubMenuName</li>

Use #Html.Raw with Url.Content and pass parameters like below:
#Html.Raw(Url.Content("~/"+#SubMenuList.ControllerName +"/"+ #SubMenuList.ActionName?param=" + param.value))

Related

How to make a dropdown menu in Blazor

I am trying to make a simple dropdown menu in my Blazor app. It is declared in my Header.razor as shown below:
<div class="header-sign">
<div class="dropdown" id="toggleDropdown">
<button class="button-md" type="button">
<i data-feather="user"></i>
<span>Personal cab</span>
</button>
<ul class="dropdown-list">
<li class="dropdown-item">
<a class="dropdown-link" href="">
<p class="text-md">Cabinet</p>
</a>
</li>
<li class="dropdown-item">
<a class="dropdown-link" href="">
<p class="text-md">Sign out</p>
</a>
</li>
</ul>
</div>
</div>
The dropdown can be triggered via JS script like this:
$("#toggleDropdown").on("mouseenter", () => {
$(this).find(".dropdown-list").addClass("is-active");
});
I have my header declared in MainLayout.razor like shown below:
#inherits LayoutComponentBase
<Header></Header>
<main class="main">
#Body
</main>
<Footer></Footer>
And this approach doesn't work.
Everything changes if I replace the above-mentioned Header.razor with razor page Header.cshtml with exactly the same markup and render it in _Layout.cshtml in such a way:
#await Html.PartialAsync("Header")
Looks like the above markup can only work in *.cshtml files but cannot in *.razor and I don't quiet understand the reason. Why does it behave this way?
Huge thanks to Mohammed Alwedaei, I figured out how to solve my question. His remark that the dropdown should be activated on a click and not on a hover really solved it to me.
We should just keep state of a dropdown list and toggle classes of it in a bit tricky way (with a ternary operator #(isActive ? "is-active" : "")). To make the dropdown work as intended, we should define #onclick attribute and also #onblur to disable it when user clicks somewhere else.
The code below works just fine:
<div class="header-sign">
<div class="dropdown" id="toggleDropdown">
<button #onclick="Show" #onblur="Hide" class="button-md" type="button">
<i data-feather="user"></i>
<span>Personal cab</span>
</button>
<ul class="dropdown-list #(isActive ? "is-active" : "")">
<li class="dropdown-item">
<a class="dropdown-link" href="/cabinet">
<p class="text-md">Cabinet</p>
</a>
</li>
<li class="dropdown-item">
<a #onclick="LogOutAsync" class="dropdown-link" href="">
<p class="text-md">LogOut</p>
</a>
</li>
</ul>
</div>
</div>
#code {
private bool isActive = false;
private void Show()
{
isActive = true;
}
private void Hide()
{
isActive = false;
}
private async Task LogOutAsync()
{
}
}

Passing selected item data to controller from Multilevel dropdown

I have created a multilevel dropdown which is dynamic. When I am clicking the third level item(new, in progress, resolved which are from the database)it should be selected and only when I am clicking the create button that selected item data should be passed to the controller.
multilevel dropdown code
<div class="dropdown drop">
<button class="btn dropdown-toggle"
type="button"
id="dropdownMenuButton"
data-mdb-toggle="dropdown"
aria-expanded="false">
STATUS
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<li>
<a class="dropdown-item" href="#">
ProjectStatus »
</a>
<ul class="dropdown-menu dropdown-submenu">
#foreach (var i in ViewBag.ProjectStatus)
{
<li>
#*<a id="ProjectStatus" class="dropdown-item" href="#">#i.Text</a>*#
<select asp-for="ProjectStatus" class="form-control" value="#i.Text">#i.Text</select>
</li>
}
</ul>
</li>
<li>
<a class="dropdown-item" href="#">
DevelopmentStatus »
</a>
<ul class="dropdown-menu dropdown-submenu">
#foreach (var i in ViewBag.DevelopmentStatus)
{
<li>
<a class="dropdown-item" href="#">#i.Text</a>
</li>
}
</ul>
</li>
</ul>
</div>
HttpGet create method
public IActionResult Create()
{
ViewBag.ProjectStatus = new SelectList(_context.ProjectStatus, "ProjectStatusID", "Status");
ViewBag.DevelopmentStatus = new SelectList(_context.DevelopmentStatus, "DevelopmentStatusID", "Status");
return View();
}
Need to get the selected list item data to the post method
[HttpPost]
public async Task<IActionResult> Create(Projects ec) {}
You can try to put the selected item value to a hidden input,and then change the background of the <li></li>.Here is a demo:
<div class="dropdown drop">
<button class="btn dropdown-toggle"
type="button"
id="dropdownMenuButton"
data-mdb-toggle="dropdown"
aria-expanded="false">
STATUS
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<li>
<a class="dropdown-item" href="#">
ProjectStatus »
</a>
<ul class="dropdown-menu dropdown-submenu">
#foreach (var i in ViewBag.ProjectStatus)
{
<li>
<a class="dropdown-item" href='#' onclick='return change("#i.Text",this,"ProjectStatus")'>#i.Text</a>
</li>
}
</ul>
</li>
<li>
<a class="dropdown-item" href="#">
DevelopmentStatus »
</a>
<ul class="dropdown-menu dropdown-submenu">
#foreach (var i in ViewBag.DevelopmentStatus)
{
<li>
<a class="dropdown-item" href='#' onclick='return change("#i.Text",this,"DevelopmentStatus")'>#i.Text</a>
</li>
}
</ul>
</li>
</ul>
</div>
<input id="ProjectStatus" name="ProjectStatus" hidden />
<input id="DevelopmentStatus" name="DevelopmentStatus" hidden />
<script>
function change(text, t, type) {
$("li").css("background", "transparent");
if (type == "ProjectStatus") {
$("#ProjectStatus").val(text);
$("#DevelopmentStatus").val("");
} else {
$("#DevelopmentStatus").val(text);
$("#ProjectStatus").val("");
}
$(t).parent().css("background", "#1266f1");
return false;
}
</script>
When select ProjectStatus,the selected value will be put to $("#ProjectStatus"),and the value of $("#DevelopmentStatus") will be "".When select DevelopmentStatus,the selected value will be put to $("#DevelopmentStatus"),and the value of $("#ProjectStatus") will be "".
result:

ASP.NET Core Simple Razor Page WebApp - adding a dynamic dropdown list to the top menu bar

I have created a very simple ASP.NET Core 3.1 WebApp that uses Razor pages rather than MVC. I want to add a dynamic dropdown list to the top menu bar which is shared by all other pages. I've added the necessary HTML to _Layout.cshtml so I get a nice dropdown box along with my other menu content (Home, About, etc) - see below.
What are my options for adding the code that populates the dropdown in my _Layout.cshtml file?
<!DOCTYPE html>
<html lang="en">
<head>
...
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-page="/Index"><img src="images/Logo.png" alt="logo" height="50"></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
</li>
<li class="nav-item dropdown ml-auto">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownTZ" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Whisky
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Gin</a>
<a class="dropdown-item" href="#">Vodka</a>
</div>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
#RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
XXX © 2020 - v1.1.30.1 - your use of this website is subject to our <a asp-area="" asp-page="/TermsConditions">Terms & Conditions</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
#RenderSection("Scripts", required: false)
</body>
</html>
A reasonable solution is to create a View Component and then add it to _Layout.cshtml. I found a good step-by-step guide by Peter Kellner (Progress) which helped me on my way. Essentially my solution involved:
Creating a folder under Pages called 'Components'
Creating a subfolder under 'Components' called 'TimeZoneControl'
Adding a class called 'TimeZoneControlViewComponent.cs' in 'TimeZoneControl'
Adding a Razor View called 'Default.cshtm' in 'TimeZoneControl'
Modifying my _Layout.cshtml to include my TimeZoneControl View Component
Adding #addTagHelper *, MyWebApp to the end of _ViewImports.cshtml where MyWebApp is the name of my Visual Studio webapp project.
In terms of code:
TimeZoneControlViewComponent.cs - ViewComponents support dependency injection so it is possible to put code into the constructor to support database access as described in Microsoft Docs
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
namespace C19QuarantineWebApp.Pages.Components.TimeZoneControl
{
public class TimeZoneControlViewComponent : ViewComponent
{
public TimeZoneControlViewComponent() { }
public IViewComponentResult Invoke(string timeZoneId)
{
var timeZones = new List<string>();
timeZones.AddRange(new[] {"GMT", "CET", "IST"});
return View("Default", timeZones.ToArray());
}
}
}
Default.cshtml
#model string[]
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownTZ" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Time zones
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
#foreach(var tz in Model) {<a class="dropdown-item" href="#">#tz</a>}
</div>
_Layout.cshtml - replace the original dropdown (see question) with
<vc:time-zone-control time-zone-id="xxx">
</vc:time-zone-control>
In context this gives:
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/About">About</a>
</li>
<li class="nav-item dropdown ml-auto">
<vc:time-zone-control time-zone-id="xxx">
</vc:time-zone-control>
</li>
</ul>
</div>
I would be interested to receive comments on this solution. Is there an easier and more elegant way to do this?
I would say for a better Razor solution not using view components (MVC) I would create an class and use #inject on your menu page. Fewer steps. See below.
Build your MenuService Class. Here is the example:
public class MenuService
{
private readonly CoreContext _dbContext;
public MenuService(CoreContext dbContext)
{
_dbContext = dbContext;
}
public IEnumerable<tblMenu> GetMenuMaster()
{
return _dbContext.tblMenu.AsEnumerable();
}
public IEnumerable<tblMenu> GetMenuMaster(string UserRole, bool isAdmin)
{
if (isAdmin == false)
{
var result = _dbContext.tblMenu.Where(m => m.UserRole != "Admin" ).ToList();
return result;
}
else
{
var result = _dbContext.tblMenu.Where(m => m.Something == `UserRole).ToList();`
return result;
}
}
}
Then finally, AddTransient to startup.cs:
services.AddTransient<MenuService, MenuService>();
Now in the _Layout.cshtml you can add the menu:
#using System.Security.Claims;
#inject Solution1.Services.MenuService menus
<!DOCTYPE html>
<html>
...rest of your _Layout.cshtml page here
Now within your HTML for the menu...customize as needed.
#foreach (var subMenu in menus.GetMenuMaster(role1.Value, admin))
{
<a class="dropdown-item" asp-page="./pathtopage" asp-page-handler="List" asp-route id="#subMenu.Program"><i class="#subMenu.Class" title="history"></i>#subMenu.DisplayName
</a>
}

Razor-Page: render a complete page (chstml+chstml.cs)

As far as I understand the Partial pages have only the cshtml code, while the ViewComponent have only the cs code.
Perhaps my approach is wrong, but I'm trying to render a complete page (cshtml + cshtml.cs) in another.
Real example.
Visual Studio 2017, ASP.NET Core 2.
NavBar.cshtml:
#page
#model MyProject.NavBarModel
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<ul class="navbar-nav">
<li class="nav-item"><a class="nav-link" asp-page="/Machines">#Resources.Machines</a></li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">#Resources.Orders</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" asp-page="/RunningOrders">#Resources.Running <span class="badge badge-primary">#ViewData["running"]</span></a>
<a class="dropdown-item" asp-page="/OpenOrders">#Resources.Opened <span class="badge badge-primary">#ViewData["running"]</span></a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" asp-page="/SuspendedOrders">#Resources.Suspended <span class="badge badge-danger">#ViewData["running"]</span></a>
</div>
</li>
<li class="nav-item"><a class="nav-link" asp-page="/Tables">#Resources.Lists</a></li>
<li class="nav-item"><a class="nav-link" asp-page="/About">#Resources.About</a></li>
</ul>
</div>
NavBar.cshtml.cs
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using MyProject.Models;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MyProject
{
public class NavBarModel : PageModel
{
private readonly MyContext _context;
public NavBarModel(MyContext context)
{
_context = context;
}
public List<Order> Orders { get; set; }
public async Task OnGetAsync()
{
Orders = await _context.Orders.ToListAsync();
ViewData["open"] = _context.Orders.Where(x => x.State == OrderStates.Open).Count();
ViewData["running"] = _context.Orders.Where(x => x.State == OrderStates.Running).Count();
ViewData["suspened"] = _context.Orders.Where(x => x.State == OrderStates.Suspended).Count();
}
}
}
_Layout.cshtml:
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top mb-2">
<a asp-page="/Index" class="navbar-brand">Production Assistant</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
#Html.Partial("NavBar", new NavBarModel())
</nav>
<div class="container body-content">
#RenderBody()
</div>
</body>
In this example I'm trying to add a Badge in the Navbar. Because the _Layout file has no code behind I had to put that in a separate Page (NavBar).
The problem is that when I try to render the page it asks for the constructor parameters. I'm afraid I've broken the dependency injection in this way.

MVC Razor View - nested foreach displays the correct info but on a different line

In View have the following foreach loop to display links:
#model List<IGrouping<string, FileInfo>>
#{
ViewData["Title"] = "Index";
int i = 0;
}
<div class="container-fluid main-container">
<div class="col-md-3 sidebar">
<ul class="nav nav-pills nav-stacked">
#foreach (var link in #Model)
{
<li>#link.Key <span>(***)</span></li>
foreach(var item in Model[i])
{
#item.Culture;
}
i++;
}
</ul>
</div>
The nested foreach displays the correct info but on a different line - I would like it positioned where the *** is in code listing.
Also I would like a comma ',' placed between each culture.
Any help appreciated.
Current output showing as:
EDIT: updated code to following and still getting same issue
#foreach (var link in #Model)
{
<li>
#link.Key
<span>
#foreach(var item in link)
{
#item.Culture
}
</span>
</li>
}
What about something like this? (untested)
<div class="container-fluid main-container">
<div class="col-md-3 sidebar">
<ul class="nav nav-pills nav-stacked">
#foreach (var link in #Model)
{
<li>#link.Key <span>
#String.Join(", ", link.Select(item => item.Culture).ToArray())
</span></li>
}
</ul>
</div>
Do you mean like this ?
<div class="container-fluid main-container">
<div class="col-md-3 sidebar">
<ul class="nav nav-pills nav-stacked">
#foreach (var link in #Model)
{
<li>#link.Key <span>
foreach(var item in Model[i])
{
#item.Culture;
#:,
}
</span></li>
i++;
}
</ul>
With the power of razor something like this should work.
Edit: just realised you want all cultures so:
#foreach (var link in #Model)
{
var Culture = "";
#foreach( var item in Model[i])
{
Culture += string.format("{0}," #item.culture;)
}
<li>#link.Key <span>(#Culture.trimend(','))</span></li>
i++;
}

Categories