Show hide html attribute based on model var in Razor - "#" must be followed by a valid code block - asp.net-core

I am using razor to show/hide page content based on variables in the model:
#if (Model.TicketShown == null)
{
#:<div id="ticket-section">
} else {
#:<div id="ticket-section" style="display:none">
}
//More Code
#:</div>
I have been using it for a while, but today I am getting the error '"#" must be followed by a valid code block' just on the closing tag. I am using the syntax elsewhere and it works fine.
Why and is there a more elegant way of doing this? Thanks

#: is meant to be used inside code blocks (see Explicit line transition), your #:</div> might not be inside one. You could use Html.Raw as alternative (e.g. #Html.Raw("</div>")).
With the help of the ?: operator, you could also rewrite the if as follows:
<div id="ticket-section" style=#(Model.TicketShown == null ? "" : "display:none")>
...
</div>

Related

Blazor conditional if statement for onclick

I have a span which should have an onclick attribute if the IsActive bool is true.
Otherwise the span should have no onclick attribute.
e.g.
#if (IsActive == true)
{
<span #onclick="#(e => Go.DoSomething("please"))">
#s.DisplayText
</span>
}
else
{
<span>
#s.DisplayText
</span>
}
Is there not a way to avoid the repeated code using a ternary operator? e.g.
#(IsActive == true ? "add onclick method somehow?" : "")
A better way to add the condition IsActive == true is in the Go.DoSomething method. But ideally I would have used a button if its clickable because we can add a disabled attribute to a button, in your case you can add the condition inside the onclick method.
Just a tip for the button, you can just add your c# boolean property within that attribute like this:
<button disabled="#IsActive">Save</button>
You can do the following.
<span #onclick="#(e => { if (IsActive) Go.DoSomething("please");})">
#s
</span>
A Lambda Expression is what I think you are really looking for.
Just want to add something for people having a similar problem:
If you have more HTML code than a single span and you would need it twice because of an if-else-statement, I would create a own Blazor component (e.g. MyComponent.razor) and use component parameters.
This way you donĀ“t have much duplicate code in an if-else-statement.
Other answers are kind of wrong. There is a difference between registering an event method as a lambda and not registering an event if not necessary.
If you move the condition to a lambda function, anytime someone click your method will run. It would have a performance impact on your app, especially if it is Blazor Server since the round trip has to happen and the logic happens on your server.
#ondclick=#(Active?() => Go.DoSomething:null)
will not register the event if it is not active so no load on your server.
from Blazor Repository Tests

ASP.net navbar with bootstrap

Good evening every one .
i would like to add an image near a navbar , but i'm not able to imitate the code propose by bootstrap , because ASP.net use helpers of razor while in bootstrap web site there use diretly an html code.
please how could i adapt this in ASP.net
You should try following code instead of the HTML of bootstrap,
where imagepath is your image path.
Razor Syntax Rules for C#:
Razor code blocks are enclosed in #{ ... }
Inline expressions (variables and functions) start with #
C# code is case sensitive
Variables are declared with the var keyword
Code statements end with semicolon
Strings are enclosed with quotation marks
C# files have the extension .cshtml
#model YourProject.Models.ImageModel
#{
imagePath= "xyz/xyz.jpg"
}
#if(imagePath != ""){
<img src="#imagePath" alt="Image Name" width="200px" />
}
If you take image path from model then you try following code:
#model YourProject.Models.ImageModel
#if(Model.Photo != null && Model.Photo != ""){
<img src="#Url.Content(#Model.Photo)" alt="#Model.AlternateText" />
}
If you don't understand then please refer following link:
https://learn.microsoft.com/en-us/aspnet/web-pages/overview/ui-layouts-and-themes/9-working-with-images

Invoke an ASP.NET Core View Component inside a Partial View

I have a partial view (_FormCustomer) that displays a form for creating a customer. I also have a View Component (Countrylist) that generates a options list of countries. Now I want to show the country list in my form. This is what I do:
Index.cshtml
<partial name="_FormCustomer" for="#Model._Customer" />
_FormCustomer.cshtml
<select asp-for="#Model.Land" class="form-control">
#await Component.InvokeAsync("Countrylist");
</select>
CountrylistViewComponent.cs
public async Task<IViewComponentResult> InvokeAsync()
{
return View(await _countryRepository.GetCountriesAsync());
}
(The function GetCountriesAsync() returns a list of countries; this works fine.)
Pages/Componenst/Countrylist/default.cshtml
#model List<Country>
#foreach (Country country in Model)
{
<option value="#country.code">#country.name</option>
}
Unfortunately, select-box stays empty when I call the partial. When I call #await Component.InvokeAsync("Countrylist"); directly from Index.cshtml, however, it works fine.
So it looks like you cannot use a View Component inside a Partial View. Is this conclusion right? Or am I doing something wrong?
Thanks Phantom2018, found the problem after your post.
#0: I'm using Razor pages
#1: this had no effect
#2: this was a typo in my question, not in my code
#3: the debugger shows me that the vie component gets called, so
My actual code is a little different, I want to pre select a country if it's available:
<select asp-for="#Model.Country" class="form-control">
#if (Model == null)
{
await Component.InvokeAsync("Countrylist");
}
else
{
await Component.InvokeAsync("Countrylist", Model.Country);
}
</select>
And after some testing, I found the solution:
<select asp-for="#Model.Country" class="form-control">
#if (Model == null)
{
#await Component.InvokeAsync("Countrylist");
}
else
{
#await Component.InvokeAsync("Countrylist", Model.Country);
}
</select>
Don't know why, but I had to use #'s before the awaits.
I have now tested this scenario and can confirm that the data loads fine - both, when the view component is directly included on the page or when it is included in a partial View. (I have tested this on Razor pages - but it is likely to work the same when using MVC. You have not mentioned if you are using MVC or Razor pages.)
A couple of things you can try to see if the loading works fine:
1) From all "Select"s and "Partials" remove the "for*" attributes. That way you can first check if the data loads & then you can worry about binding to the selected item. (Also, in your provided code, you have omitted the model variables - so it is not possible to comment on them.)
2) Remove the last ";" in your _FormCustomer.cshtml
<select asp-for="#Model.Land" class="form-control">
#await Component.InvokeAsync("Countrylist")
</select>
Note that I have removed the trailing ";" in the await statement. I noticed that the ";" was added as another "option" in the select !
3) I also noticed that even minor syntax errors (not picked up by Intellisense) can cause the select to not load. Debug to see if your InvokeAsync is actually being called - in a scenario where there was a minor syntax error, the InvokeAsync was not even being called.
Also keep in mind that:
"When a partial view is instantiated, it receives a copy of the
parent's ViewData dictionary. Updates made to the data within the
partial view aren't persisted to the parent view. ViewData changes in
a partial view are lost when the partial view returns."

How do I prevent ASP.NET Core detecting literal text I write as having special significance to the layout engine?

I have the following in a view:
<p>
#if (xyz == abc)
{
Start:
...
}
</p>
The behaviour of Visual Studio seems to indicate that the "Start:" is interpreted as having special significance to the layout engine. It underlines it with a green wavy line and when I mouse over it, it displays a tooltip saying "This label has not been referenced".
The "Start:" is just text I want to be literally spat out onto the page. I don't want to invoke some special functionality. How do I make it understand this?
You can use an explicit line transition, which is simply the #: sequence. In your example, Razor is in a C# block when it meets Start:, so it assumes it's still working with C# code as Start: is valid C# syntax (it's a label for e.g. goto). Using #: explicitly instructs the Razor parser to treat the content as being HTML:
<p>
#if (xyz == abc)
{
#:Start:
...
}
</p>
You can also use Razor's text element, which would give the same result:
<p>
#if (xyz == abc)
{
<text>Start:</text>
...
}
</p>

How can I use #Html.RenderPartial inside Ajax.Beginform?

Is it possible to use #Html.RenderPartial inside #using(Ajax.BeginForm) code block?
It doesn't work if I use #Html.RenderPartial, and it works if I put whole of razor code directly inside #using(Ajax.BeginForm) block.
Could anyone please suggest if that's possible or not?
If the Html.RenderPartial is right after the #using(Ajax.BeginForm(...)) then you don't need to prefix the call to Html.RenderPartial with # as razor understands you are still in the same code block.
So, this works fine:
#using (Ajax.BeginForm(...)) {
Html.RenderPartial("_PartialView", Model);
<p>after partial view inside the ajax form</p>
}
If between the `#using(Ajax.BeginForm(...)) and the render partial you have some html, then razor will end the code block before you call RenderPartial and you will need to do this:
#using (Ajax.BeginForm(new AjaxOptions())) {
<div>
<h3>partial view inside the ajax form</h3>
#{ Html.RenderPartial("_PartialView", Model); }
</div>
}
Also notice that Html.RenderPartial is a method that returns void and internally calls Write, so the syntax for using it is slightly different than when you use Html.Partial, that's why you need to surround it with "#{" (when not in a code block already) and end it with semicolon. See this question