Blazor - Razor markup in c# class file - c#

I'm splitting code in a Blazor file into a .cs file but am having issues with leftover markup.
Example from https://blazor.radzen.com/dialog
Using the dialogue where the markup is mixed into the code:
async Task ShowInlineDialog()
{
var result = await DialogService.OpenAsync("Simple Dialog", ds =>
#<div>
<p class="mb-4">Confirm Order ID <b>#orderID</b>?</p>
<div class="row">
<div class="col">
<RadzenButton Text="Ok" Click="() => ds.Close(true)" class="me-1" Style="width: 80px;" />
<RadzenButton Text="Cancel" Click="() => ds.Close(false)" ButtonStyle="ButtonStyle.Light" class="me-1" />
<RadzenButton Text="Refresh" Click="(() => { orderID = 10249; ds.Refresh(); })" ButtonStyle="ButtonStyle.Light" class="me-1 float-end" />
</div>
</div>
</div>);
console.Log($"Dialog result: {result}");
}
When attempting to move this snippet into the code file (.cs), the markup is failing.
Cursory searching has yield nothing, but my google-fu could be weak.
Any hints appreciated, thank you.

You can't put Razor markup in a C# class file. It must be in a Razor file so the Razor compiler can compile it.
You can define markup blocks as RenderFragments like this:
#MyButtonRow
\\....
#code {
\\...
async Task ShowInlineDialog()
{
var result = await DialogService.OpenAsync("Simple Dialog", MyDialogContent);
Console.Log($"Dialog result: {result}");
}
private RenderFragment MyDialogContent => __builder => {
<div>
<p class="mb-4">Confirm Order ID <b>#orderID</b>?</p>
<div class="row">
<div class="col">
<RadzenButton Text="Ok" Click="() => ds.Close(true)" class="me-1" Style="width: 80px;" />
<RadzenButton Text="Cancel" Click="() => ds.Close(false)" ButtonStyle="ButtonStyle.Light" class="me-1" />
<RadzenButton Text="Refresh" Click="(() => { orderID = 10249; ds.Refresh(); })" ButtonStyle="ButtonStyle.Light" class="me-1 float-end" />
</div>
</div>
</div>);
};
}

Related

Use Javascript addEventListener within Blazor component

I have a Blazor component which is rendered server-side. And I would like to have some collapsible divs inside of it. However since the code is server rendered the Javascript is not executed therefore the parts cannot collapse.
Here is the code inside my script.js file :
var coll = document.getElementsByClassName("collapsible");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = this.nextElementSibling;
if (content.style.maxHeight){
content.style.maxHeight = null;
} else if(window.matchMedia("(max-width:1440px)")){
// content.style.maxHeight = content.scrollHeight + "px";
content.style.maxHeight = "20vh";
}
else {
content.style.maxHeight = "50vh";
}
});
}
Here is my main.cshtml file :
<component type="typeof(Main)" render-mode="Server" />
<script src="~/js/script.js" type="text/javascript"></script>
And finally my Main component with the collapsible parts :
#using Microsoft.AspNetCore.Components;
#using Microsoft.AspNetCore.Components.Web;
<div class="collapsible">
<label for="tutu">HEADER</label>
<div id="mybtn" class="btn-rch"></div>
</div>
<div class="tutu content flex-column">
<p>CONTENT HIDDEN IN COLLAPSE</p>
</div>
<div class="collapsible">
<label for="tutu">HEADER</label>
<div id="mybtn" class="btn-rch"></div>
</div>
<div class="tutu content flex-column">
<p>CONTENT HIDDEN IN COLLAPSE</p>
</div>
<div class="collapsible">
<label for="tutu">HEADER</label>
<div id="mybtn" class="btn-rch"></div>
</div>
<div class="tutu content flex-column">
<p>CONTENT HIDDEN IN COLLAPSE</p>
</div>
#code {
}
If I use render-mode="Static" instead of render-mode="Server" it works, but since my component will have event inside of it is not a possibility for me. How can I, with the use of JSInterop for example, call my JS script to make my div collapse ?
You can do all this in Blazor. Below is a simplistic working example of what I think you are trying to achieve.
This is a collapsible div component.
CollapseDiv.razor
<div #onclick="Collapse" style="cursor:pointer;" >
<h2>#Label</h2>
</div>
#if (!Collapsed)
{
<div>#ChildContent</div>
}
#code {
[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public RenderFragment Label { get; set; }
bool Collapsed;
void Collapse(MouseEventArgs e)
{
Collapsed = !Collapsed;
}
}
And this is the page to demo it:
Collapse.razor
#page "/collapse"
<h3>Collapse Test Page</h3>
<CollapseDiv>
<Label>I'm Collapsible</Label>
<ChildContent>
I'm the collapsed content!
</ChildContent>
</CollapseDiv>
<br />
<br />
<CollapseDiv>
<Label>I'm Collapsible Too</Label>
<ChildContent>
More collapsed content!
</ChildContent>
</CollapseDiv>
#code {
}
The key here is: Forget manipulating the DOM with Javascript, build components.
You should be able to adopt this to fit your needs.

List validation(data annotation) not working on the client side

I have a Groups list which has a custom attribute method associated with it. It does not seem to catch the validation error on the screen. However on the controller, it gives ModelState.Valid as false. Is there a way to catch it in the view instead of it having to go to the server side and I then catch and display it?
Other validations are working, so its not the case of missing jquery files.
Model:
[RequiredList(ErrorMessage = "The {0} field is required.")]
[Display(Name = "Selected Organization(s)")]
public List<OrganizationDTO> Organizations { get; set; }
Custom Attribute:
public class RequiredListAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
var list = value as IList;
if (list != null)
{
return list.Count > 0;
}
return false;
}
}
View:
<div class="form-group">
<div class="controls">
<label class="control-label" for="Selected Groups">Selected Group(s)</label>
<div class="panel panel-default">
<div class="panel-body" style="overflow-y: auto; max-height: 100px; min-height:50px" id="divSelGroups">
#for (int i = 0; Model.Groups!= null && i < Model.Groups.Count(); i++)
{
var group= Model.Groups[i];
var checkedAttr = (group.Id != Guid.Empty) ? "checked='checked'" : "";
<div class="row">
<input type="hidden" name="Groups.Index" value="#i" />
<input type="hidden"name="Groups[#i].Name" value="#group.Name" />
<input type="hidden" name="Groups[#i].Data" value="#group.Data" />
<div class="col-xs-1">
<input type="checkbox" name="Groups[#i].Id" value="#group.Id" #checkedAttr data-org-selected="true" />
</div>
<div class="col-xs-11" data-toggle="tooltip" data-placement="top" title="#group.Data">#group.Name</div>
</div>
}
</div>
</div>
#Html.ValidationMessageFor(m => m.Groups)
</div>
</div>
I had to include a workaround to get it working, though does not answer my original question still gets the requirement of the question resolved. I had to introduce a hidden textbox which contains the number of list items and put a range validator on it.
Model:
[Range(1, double.MaxValue, ErrorMessage = "Atleast one organization needs to be selected.")]
public int OrgCount { get; set; }
View:
#Html.TextBoxFor(m => m.OrgCount, new { style="visibility:hidden;height:0"})
#Html.ValidationMessageFor(m => m.OrgCount)
JS script:
var orgCount = $(".panel-body input[name='Organizations.Index']").last().val();
if (isNaN(orgCount))
orgCount = -1;
$("#OrgCount").val(parseInt(orgCount) + 1);
So basically if there are no elements I make it 0 and hence they fail the validation and so the range validator error message is displayed.
As per above information when the validation is working fine in the controller but it is not working in the view then problem may regarding the jquery validation files .
So in your view if you havent reference the jquery files , then reference it like below:
<script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
Also make sure you have below entry in your webconfig file:
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
Hope above information will be useful , kindly let me your thoughts or feedbacks
Thanks
karthik

How to access for each loop html properties to code behind?

i'm trying to access these data in code behind file. if i change these html tag to asp tags i cannot retrieve data from for each loop. here i want actual sales price and the product size which are generated by for each loop to save these properties in database. So is there any possible ways to solve these problem??
aspx page
<%
foreach (Com.Idk.Application.ImaraResPOS.Entities.ProductSize psize in psList)
{
%>
<div class="col-sm-12 text-center type">
<div class="circle bg">
<img src="images/Meal-100.png">
</div>
<div class="btn-align-size">
<button class="btn btn-primary ladda-button cd-add-to-cart" data-price="<%=psize.SalesPrice %>" data-name="<%= psize.SizeDef.Name %>" data-product-image="images/3.jpg" data-style="expand-right" id="Breadtype_btn" data-dismiss="modal" data-toggle="modal" data-target="#bread_type">
<%= psize.SizeDef.Name %>
<img src="images/Buy-30.png" style="height: 30px; width: 30px">
<h3 class="hide">
<%= psize.Id%>
</h3>
</button>
</div>
</div>
<%
}
%>
code behind
private void InsertProductSizeToSale()
{
string sizeID = Request.QueryString["size_id"].ToString();
Com.Idk.Application.ImaraResPOS.Entities.ProductSize prid = new Com.Idk.Application.ImaraResPOS.Entities.ProductSize();
psList.Select(Global.sess, "ProductSize","where Product_ID="+ prid);
if (psList.Count > 0)
{
Hashtable parameterList = new Hashtable();
OfferDetailList odList = new OfferDetailList();
parameterList.Clear();
parameterList.Add("productSizeId", sizeID );
parameterList.Add("comboId", null);
parameterList.Add("currentDate", DateTimeUtil.GetFormattedString(((Sale)index.saleid).Date));
parameterList.Add("currentTime", DateTimeUtil.GetFormatedTimeString(DateTime.Now));
parameterList.Add("day", Const.GetDay(((Sale)index.saleid).Date.DayOfWeek));
odList.SelectUsingSP(Global.sess, "SqlProGetOfferDetail", parameterList);
if (odList.Count == 0)
{
//want to retrive psize properties here
// here i'm getting an error
SqlProInsertProductSizeToSale(prid, sizeID, psize.SalesPrice, psize.SalesPrice);
}
else if (odList.Count > 0)
{ SqlProInsertProductSizeToSale(selectedProduct, selectedProductSize, odSelection.GetSelectedProductSizePrice(), selectedProductSize.SalesPrice);
}
}
}
}
I am not sure why you wish to get the data from the page. Since you are populating the page from some entity objects, why not just get the data from the entity objects directly?
Codebehind
foreach (Com.Idk.Application.ImaraResPOS.Entities.ProductSize p in psList)
{
SqlProInsertProductSizeToSale(p.prid, p.sizeID, p.SalesPrice, p.SalesPrice);
}

Upoladed File Is Corrupt After Upload

I have a problem with my webapplication. I have made an upload-function for uploading documents. one For Answer Paper And Another Is Question Paper. I have No problem In Question Papeer Its Works Fine But When After Upload Answer Paper is Corrupt..
Any Idia
<div >
<label class="control-label" for="fileInput">Attached Question File </label>
<div class="controls">
<asp:FileUpload ID="fuQFile" runat="server" onChange="chngFUvalue(this)" CssClass="input-file uniform_on" />
<asp:Label ID="lblQVfile" runat="server" Text=""></asp:Label></div>
</div>
<div class="control-group">
<label class="control-label" for="fileInput">Attached Answer File </label>
<div class="controls">
<asp:FileUpload ID="fuAFile" runat="server" onChange="chngFUvalue(this)" CssClass="input-file uniform_on" />
<asp:Label ID="lblAVfile" runat="server" Text=""></asp:Label></div>
</div>
///For Question Pappr(Works Fine)////
string VQFile = "", VQFilePath = "";
if (fuQFile.HasFile)
{
VQFile = fuQFile.FileName.ToString();
VQFilePath = "1upload/files/Question/" + VQFile;
fuQFile.SaveAs(Server.MapPath("~/1upload/files/Question/") + VQFile);
}
else
{
VQFilePath = lblQVfile.Text;
}
// For Answer Paper(Facing Problem With That Part)////File Is Corrupt After Upload//////
if (fuAFile.HasFile)
{
VAFile = rndnom + "-" + fuAFile.FileName.ToString();
VAFilePath = "1upload/files/Answer/" + VAFile;
fuQFile.SaveAs(Server.MapPath("~/1upload/files/Answer/") + VAFile);
}
else
{
VAFilePath = lblAVfile.Text;
}
Your are calling fuQFile.SaveAs when saving the answer file, rather than fuAFile.SaveAs.

Insert HTML at runtime?

I need to write some code that places one of 3 choices of "blocks" of html in a specified place on the page. How can I do this?
I was thinking I can use single value databinding, but I don't think this is the correct way.
I'm using ASP.NET c#.
Edit: here is what it might look like:
MapPlaceholder.InnerHtml = #"<div class="mapContainer smallMap" id="smallGrid" runat="server" visible="false">
<div id="node1" class="gridBox" runat="server">
</div>
<div id="node2" class="gridBox" runat="server">
</div>
<div id="node3" class="gridBox" runat="server">
</div>
<div id="node4" class="gridBox" runat="server">
</div>
<div id="node5" class="gridBox" runat="server">
</div>
<div id="node6" class="gridBox" runat="server">
</div>
<div id="node7" class="gridBox" runat="server">
</div>
<div id="node8" class="gridBox" runat="server">
</div>
<div id="node9" class="gridBox" runat="server">
</div>
</div>";
and in the .aspx page:
<div id="MapPlaceholder" runat="server"></div>
One more thing, how can I tell C# to actually write the " in the string? It isnt working currently because it stop at the first " it finds.
Edit: I have another problem.
MapPlaceholder.InnerHtml = block1;
HtmlGenericControl smallGrid = (HtmlGenericControl)MapPlaceholder.FindControl("smallGrid");
containerName = "smallGrid";
smallGrid.Visible = true;
smallGrid.Attributes["Style"] = "background-image:url('" + du.getMapBackgroundImage(mapId) + "'); " + "width:300px; height:300px;";
containerName = "smallGrid";
This is what i am trying to do, but the FindControl always returns null. I debugged this and it seems that the html code is being added, but only after the pageload ends. Is there anyway i can tell c# to "render" the div so i can work with it like i need to?
To have double quotes in code, you need to have two of them when using # so it would be:
MapPlaceholder.InnerHtml = #"<div class=""mapContainer smallMap"" id=""smallGrid"" runat=""server"" visible=""false"">
<div id=""node1"" class=""gridBox"" runat=""server"">
</div>
<div id=""node2"" class=""gridBox"" runat=""server"">
</div>
<div id=""node3"" class=""gridBox"" runat=""server"">
</div>
<div id=""node4"" class=""gridBox"" runat=""server"">
</div>
<div id=""node5"" class=""gridBox"" runat=""server"">
</div>
<div id=""node6"" class=""gridBox"" runat=""server"">
</div>
<div id=""node7"" class=""gridBox"" runat=""server"">
</div>
<div id=""node8"" class=""gridBox"" runat=""server"">
</div>
<div id=""node9"" class=""gridBox"" runat=""server"">
</div>
</div>";
To your original question: have three strings with the possible "blocks" then assign the proper string:
string block1 = #"<div class=""mapContainer smallMap"">block 1</div>......";
string block2 = #"<div class=""mapContainer smallMap"">block 2</div>......";
string block3 = #"<div class=""mapContainer smallMap"">block 3</div>.......";
switch (myCond) {
case 1:
MapPlaceholder.InnerHtml= block1;
break;
case 2:
MapPlaceholder.InnerHtml= block2;
break;
case 3:
MapPlaceholder.InnerHtml= block3;
break;
}
Edit: looks like you need different approach. First, put all blocks inside the .aspx under MapPlaceholder control directly:
<div id="MapPlaceholder" runat="server">
<div class="mapContainer smallMap" id="smallGrid1" runat="server" visible="false">
block 1 contents here...
</div>
<div class="mapContainer smallMap" id="smallGrid2" runat="server" visible="false">
block 2 contents here...
</div>
<div class="mapContainer smallMap" id="smallGrid3" runat="server" visible="false">
block 3 contents here...
</div>
</div>
Having this, just show the proper control based on the condition:
switch (myCond) {
case 1:
smallGrid1.Visible = true;
break;
case 2:
smallGrid2.Visible = true;
break;
case 3:
smallGrid3.Visible = true;
break;
}
This way you don't have to mess with strings of raw HTML and can change the layout from the .aspx which is more convenient.
on Page Load you can insert what you need dynamically.
a tip: you can insert with a Label over its Text property an html block, javascript or jquery codes
Label myLabel = new Label();
myLabel.Text = #"html text";
Page.Controls.Add(myLabel);
If the question really is "how to place blocks of HTML onto the page" as a (very basic) example, you might find something like this useful:
ASPX code:
<div runat="server" id="mydiv"></div>
C# code:
mydiv.InnerHtml = "<span>hi</span>";
or
HtmlGenericControl c = new HtmlGenericControl("span");
c.InnerHtml = "hi";
mydiv.Controls.Add(c);
DataBinding is more for pushing dynamic values to page content from, e.g. a database.
The PlaceHolder control may be what you need:
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.placeholder.aspx
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
protected void Button1_Click(object sender, EventArgs e)
{
Label NewLabel = new Label();
NewLabel.Text = "Hello World!";
PlaceHolder1.Controls.Add(NewLabel);
}
You can add HTML tags With concatenation of the string at label text or others
labelc.text="Html tags code here";

Categories

Resources