Razor component tag helper not actually loading the razor component - razor

I've been following the steps in this guide to set up Blazor components in my Razor app. I completed all the steps from the "Prepare the app" section of that guide, modifying the _Layout.cshtml & Startup.cs files and adding the _Imports.razor file. To test this, I'm just trying to implement a basic counter component.
I added the below code to MyApp/Components/Counter.razor:
<p>Current count: #currentCount</p>
<button class="btn btn-primary" #onclick="IncrementCount">Click me</button>
#code {
private int currentCount = 0;
[Parameter]
public int InitialValue { get; set; }
private void IncrementCount() => currentCount++;
protected override void OnParametersSet()
{
currentCount = InitialValue;
}
}
Then in MyApp/Pages/Counter.cshtml i have this:
#page
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#using Microsoft.AspNetCore.Components
#using Microsoft.AspNetCore.Components.Web
#using System.Net.Http
#using Microsoft.AspNetCore.Authorization
#using Microsoft.AspNetCore.Components.Authorization
#using Microsoft.AspNetCore.Components.Forms
#using Microsoft.AspNetCore.Components.Routing
#using Microsoft.JSInterop
#using MyApp
#using MyApp.Components
//This does not work--it appears exactly like this in the HTML when the page loads
<component type="typeof(Counter)" render-mode="ServerPrerendered" />
//this works as expected and loads the razor component
#(await Html.RenderComponentAsync<Counter>(RenderMode.ServerPrerendered))
Note that I copied all the using directives from the _Imports.razor file to see if that fixed things, but it didn't make a difference. My understanding is that the RenderComponentAsync function is outdated and the the "component" tag helper is the current way to use razor components. I'd also prefer to use that syntax since it's easier to pass parameters. Does anyone know what I'm missing to get it to work?

Welp, after messing around with this for hours I realized that my app was on Net Core 3.0 and the tag helper is only available in 3.1+. Updating MyApp.csproj to have 3.1 instead fixed it:
<TargetFramework>netcoreapp3.1</TargetFramework>

Related

Custom Blazor Server Component Not Invoking the OnClick Function

I have created a layout component in the same directory as with the MainLayout component. The CustomLayout #inherits LayoutComponentBase and has #Body which gets the content to be rendered inside the layout.
As obviously expected, the layout component has its own css files and UI display is fine. I am only having a problem with the #onclick function. It cannot be invoked. Is there a way to trigger the function on button click?
The reason I want to do this is that I am creating a navigation bar which will have to show/hide a dropdown. I hope I can get some ideas on this. Appreciated.
I am calling a server function this way: #onclick="SomeFuction" or #onclick="SomeFuction" or #onclick="#(() => SomeFuction())"
LayoutComponent:
#inherits LayoutComponentBase
#Body
Home page referencing a custom layout:
[AllowAnonymous]
[Layout(typeof(CustomLayoutComponent))]
[AllowAnonymous] is just for allowing anonymous access.
I am using Blazor Server and .NET 6
Additional Information:
I have put all the code in one page so that it becomes easier to read and understand.
Here is the LayoutComponent razor component:
#inherits LayoutComponentBase
<div class="navbar" id="custom-navbar">
<div class="wrapper">
<a>Home</a>
<a>Service</a>
<button class="btn btn-primary" #onclick="ToggleProductsUI">Products</button>
</div> </div>
<!--Component to show Products UI Component. Scoped css for styling-->
<ProductsComponent TValue="string" UIState="#ProductsUIState"></ProductsComponent>
#code{
// state of the Products submenu Component
string ProductsUIState { get; set; }
// a control function for toggling the Products UI
// this function somehow is not invoked.
void ToggleProductsUI()
{
if (string.IsNullOrWhiteSpace(ProductsUIState))
{
ProductsUIState = "show-ui";
return;
}
ProductsUIState = string.Empty;
}
}
Here is the ProductsUI component code (I have removed the unnecessary event to avoid confusion. The component can be fully controlled by the parent):
public partial class ProductsComponent<TValue> {
[Parameter]
public string? UIState { get; set; } }
Blazor pages that will use the custom layout component will point to it like this:
[AllowAnonymous]
[Layout(typeof(CustomLayoutComponent))]
public partial class Index
{
}
This is working fine. The issue is in the CustomLayoutComponent when trying to invoke the ToggleProductsUI() function
I accidentally inluded a <body> element in the layout and as such, the <script src="_framework/blazor.server.js"></script> was not being run hence the click event was not being invoked. I removed the <body> element. I was misled by the default body{} style in the underlining scopped css. Resolved.

How to define function that returns html in asp.net core

Basically I need something like old asp.net
#helper MakeNote(string content) {
<p><strong>Note</strong> #content </p>
}
or JSX
MakeNote(note) {
return (<div>Note {note}</div>);
}
A partial view is not an option. I am happy with either a function returning an IHtmlString, or a function writing to the underlying writer.
It also needs to support Razor Syntax (not just string concatenation) inside the function.
Since ASP.NET Core 3.0, we can declare Local Functions containing markup to serve as templating methods, inside Razor Code Blocks:
#{
void RenderName(string name)
{
<p>Name: <strong>#name</strong></p>
}
RenderName("Mahatma Gandhi");
RenderName("Martin Luther King, Jr.");
}
Which renders the following HTML Code:
<p>Name: <strong>Mahatma Gandhi</strong></p>
<p>Name: <strong>Martin Luther King, Jr.</strong></p>
Documentation: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-3.0#razor-code-blocks
(just for sake of completion) In ASP.NET Core 2.0 we can use Templated Razor delegates, which combined with the <text></text> razor tag (Explicit Delimited Transition), allow us to make something similar to an old day's ASP.NET MVC #helper tag:
#{
Func<string, object> RenderName = #<text>
<p>
Name: <strong>#item</strong>
</p>;
</text>;
}
<div>
#RenderName("Victor")
</div>
Which renders the following HTML Code:
<div>
<p>
Name: <strong>Victor</strong>
</p>
</div>
Documentation: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-2.0#templated-razor-delegates
Documentation <text></text>: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-2.0#razor-code-blocks
You might be looking for #functions that use Html.Raw.
Here is an example that shows two function styles. The first uses a traditional block body, the second uses an expression-body.
Both of them have the $# prefix on the string.
The $ enables {interpoloation} in the string.
The # makes a verbatim string, which can span multiple lines.
The third way is somewhat of a hack that lets us parse Razor inside the function. It's as close as we seem to be able to get to the original #helper syntax.
SomeRazorFile.cshtml
#using Microsoft.AspNetCore.Html
#functions
{
IHtmlContent MakeNote(string content)
{
return Html.Raw($#"
<p>
<strong>Note</strong> {content}
</p>
");
}
// an alternative that uses method shorthand
IHtmlContent MakeNoteToo(string content) => Html.Raw($#"
<p>
<strong>Note</strong> {content}
</p>
");
}
#{
// an alternative that parses razor
Func<string, IHtmlContent> MakeNoteThree =
#<p>
<strong>Note</strong> {#item}
</p>;
}
<div>
#MakeNote("Foo")
#MakeNoteToo("Bar")
#MakeNoteThree("Baz")
</div>
Edit: Added an example that parses Razor. See https://github.com/aspnet/Razor/issues/715 for details.
I'm having to convert old Helpers to something as close as possible in .net 5 and I've had good luck with this so far. Not saying it's best, but it works.
Old Helper now as a function...
public static string Helper1(string name) {
string html = null;
html += "<p>Hi, my name is <strong>#name</strong></p>";
html += "<p>It's nice to meet you!</p>";
return html;
}
Include the reference and call on any Page...
<div>
#Html.Raw(Helper1("Josh"))
</div>

ID auto added in the POST url

I have an edit View in my application.This is my Razor syntax for POSTing a form
#using (Html.BeginForm("edit", "person", FormMethod.Post))
{
}
After I run my application, inspect the markup in browser, following markup is generated
<form method="post" action="/person/edit/1">
I want the url to be "/person/edit" in another POST action
This is my action method in Controller
[Route("edit/{person_id}")]
public IActionResult edit(long person_id)
{
//some stuffs
return View();
}
Adding RouteData.Values.Remove("person_id"); in the action before returning the View worked for me.
https://stackoverflow.com/questions/6020253/calling-html-beginform-and-specifying-action

On html.actionlink click, load a partial view below the link

Currently in my view this is what I have
<dt>Credit Saldo</dt>
<dd>#Model.CreditSaldo #Html.ActionLink("Add Credit","AddCredit",routeValues:new{Model.LicenseId})</dd>
<br/>
<dd>
<div id="partialDiv"></div>
</dd>
Whenever User clicks Add Credit, currently it forwards me to new partial view (no surprise).
What I want to do is load that partial view in same view, in the div that has Id as partialdiv.
Here is the method in controller, thats being called when the link is called
[HttpGet]
public ActionResult AddCredit(Guid licenseid)
{
var newCredit = new AddCredits();
return PartialView(newCredit);
}
and this is what I've done in partial view
#model AdminPortal.Areas.Customer.Models.ViewModels.AddCredits
<div class="input-small">#Html.EditorFor(m=>m.CreditToAdd) <button class="btn-small" type="submit">Add</button></div>
How can I load the partial view in same view when the link "Add Credit" is clicked?
Edit 1 : Tried Ajax
<dt>Credit Saldo</dt>
<dd>#Model.CreditSaldo #Ajax.ActionLink("Add Credit","AddCredit",new{Model.LicenseId}, new AjaxOptions {UpdateTargetId = "partialDiv"})
<br/>
<dd>
<div id="partialDiv"></div>
</dd>
Result: Partial View still loads as new view (not in same view)
You can use the ajax helpers for that
#Ajax.ActionLink("Add Credit","AddCredit",routeValues:new{Model.LicenseId}, new AjaxOptions {UpdateTagetId = "partialDiv"}, new {})
In order for these to work, you will need to make sure that you load jquery and jquery.unobtrusive-ajax in your layout.
When including jquery, use a pre 1.9 version or the scripts won't work. If you need a version of jquery 1.9+ add the jquery.migrate package from nuget to your project and load that in your layout too.

Razor output not working in MVC 3 but working in MVC 2

This same code working fine with MVC 2 but not working in MVC 3 Razor. Once page is loaded not loading menu from HTMLHelper called within Razor like below.
Hardcoded menu for testing which is not outputting on the page.
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using myproject.Extensions;
public static class MenuHelper
{
public static string TabbedMenu(this HtmlHelper helper, IEnumerable<MenuTab> tabs)
{
//I have hard coded menu for testing purpose.
return "<div class='menu-image'><img src='/content/Images/common/on-left.gif' alt='' /></div><div class='on'><a class='over' href='/?Length=4'>Home</a></div><div class='menu-image'><img src='/content/Images/common/on-right.gif' alt='' /></div><a href='/Home/About'>About</a><a href='/Home/Contact'>Contact</a>";
}
}
Below is Razor CSHTML code.
#{Html.TabbedMenu
(
new List<MenuTab>
{
MenuTab.Create("Home", "Index", "Home"),
MenuTab.Create("About", "About", "Home"),
MenuTab.Create("Contact", "Contact", "Home")
}
);}
Wrapping code in #{ ... } (like you did) is Razor's equivalent to <% ... %> (without an =).
Therefore, your code calls the function, but doesn't do anything with the result.
You should remove the {} and the ; and simply write #Html.TabbedMenu(...); this is equivalent to <%: Html.TabbedMenu(...) %>.
You'll also need to change the method to return an HtmlString to prevent Razor from escaping the HTML.