Would someone give a code example how to create and insert HTML at run time?
The HTML is like this:
<div class="row">
<div class="col-md-3">
<img src="example.png" class="profileImage" /> <br />
<span class="name">Name</span>
<div class="ver"></div>
<img class="flag ver" src="star.png" />
<div class="horizontalBar"></div>
</div>
</div>
The close I get was:
public partial class MyPage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
this.Header.DataBind();
ContentPlaceHolder contents = Page.Master.FindControl("MainContent") as ContentPlaceHolder;
Panel row = new Panel() { CssClass = "row" };
Panel col = new Panel() { CssClass = "col-md-3" };
Image profile = new Image()
{
CssClass = "profileImage",
ImageUrl = "example.jpg"
};
row.Controls.Add(col);
col.Controls.Add(profile);
contents.Controls.Add(row);
}
}
It doesn't work (see below error) and isn't full code, for example, what class is equivalent to generate <span>?
I get this error:
The Controls collection cannot be modified because the control
contains code blocks
What's the reason of that error? which are those code blocks and how do I fix this?
I've tested the code here and it's working.
The control equivalent to span is Label, but I think there must be better ways of doing this.
If you really need to dynamically insert HTML code, you can inject it using the LiteralControl, like this:
var html = new LiteralControl(#"<div class=""row"">
<div class=""col-md-3"">
<img src=""example.png"" class=""profileImage"" />
<br />
<span class=""name"">Name</span>
<div class=""ver""></div>
<img class=""flag ver"" src=""star.png"" />
<div class=""horizontalBar""></div>
</div>
</div>");
contents.Controls.Add(html);
Related
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.
I am having difficulty adding a Button control to a specific spot in an .aspx page. I think I can create the button, but I don't know how to add it to the page.
Code is as follows:
<%
var cpus = productItems.FindAll(t => t.Type == "cpu");
foreach (var cpu in cpus)
{ %>
<div class="row product cpu">
<div class="col-md-3">
<img class="center-block" src="Content/images/processor.jpg" />
<span class="price"><%= cpu.Price %></span>
<span class="addtocart">
<% Button b = new Button();
b.ID = "Button" + cpu.ID;
b.CommandArgument = cpu.ID.ToString();
b.Text = "Add to Cart";
b.OnClientClick = "Addtocart_Click";
%>
</span>
<br />
</div>
</div>
<% } %>
I can also create the Button as part of the productItems collection, but still presents the problem of how to render the button on the page.
I'm sure there's a better way to do this, just not sure where to look.
Thanks in advance.
In WebForms, you can make use of listing controls that have a concept of a DataSource (Some listing of objects) and a template which renders how each of those objects appear. In general, you should use these whenever you have a list of items that you want to render on the site.
In this particular case, you will probably want to make use of the ListView control. This allows you to define a layout template and an item template.
Your aspx markup would look like the following:
<asp:ListView ID="lvCpus" OnItemDataBound="lvCpus_ItemDataBound" runat="server">
<LayoutTemplate>
<div class="row product cpu">
<div runat="server" id="itemPlaceholder"></div>
</div>
</LayoutTemplate>
<ItemTemplate>
<div runat="server" class="col-md-3">
<img class="center-block" src="Content/images/processor.jpg" />
<span class="price"><%# Eval("Price") %></span>
<span class="addtocart">
<asp:Button ID="addToCart" Text="Add To Cart" runat="server" />
</span>
</div>
</ItemTemplate>
</asp:ListView>
This defines a ListView control and creates a LayoutTemplate that matches your container. Internally it has a div that must have the id itemPlaceholder which is used to populate the various items that are bound to this control.
The ItemTemplate portion defines what you expect each individual item to look like. In this case, it's a column that contains a CPU for purchase.
Notice that the button is defined as a regular ASP Web Control, but none of the dynamic data is set. That's because if you try to assign a property like CommandArgument with an evaluated item, the server tag will not be well-formed and you'll get the YSOD. To work around this, you need to specify an OnItemDataBound function for the ListView that is called when you bind data to this Web Control. In my case, it's called lvCpus_ItemDataBound.
The ItemDataBound method in this case will look like the following:
protected void lvCpus_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
var cpu = e.Item.DataItem as Cpu;
if (cpu == null)
{
return;
}
var btn = e.Item.FindControl("addToCart") as Button;
if (btn == null)
{
return;
}
btn.CommandArgument = cpu.Id.ToString();
// Set other server-side properties required from code.
}
}
When you bind a data source, it has 0 or more items in it. For every item in the data source, this method is called and will let you specify server-side appropriate values that can't be expressed directly in the template.
In our case, we specify the CommandArgument from the Cpu class, but other values could be specified as well.
Finally, we need to make sure we can fill the list view with data. So in Page_Load perhaps, we can bind data to this ListView like the following:
protected void Page_Load(object sender, EventArgs e)
{
lvCpus.DataSource = GetCpus();
lvCpus.DataBind();
}
private IEnumerable<Cpu> GetCpus()
{
yield return new Cpu { Id = 1, Price = 5 };
yield return new Cpu { Id = 2, Price = 10 };
yield return new Cpu { Id = 3, Price = 15 };
yield return new Cpu { Id = 4, Price = 15 };
yield return new Cpu { Id = 5, Price = 20 };
}
We first set the List View's data source to the CPU list that you have and then call the DataBind() method on the ListView. This triggers the OnItemDataBound function to begin filling in the data, and at the end you are left with, in this case, 5 CPUs displayed on the site.
I have added span as runatserver and add control(i.e. button) into it
Try below code,
<div class="row product cpu">
<div class="col-md-3">
<img class="center-block" src="Content/images/processor.jpg" />
<span class="price"><%= cpu.Price %></span>
<span class="addtocart" id="buttonContainer" runat="server">
<% Button b = new Button();
b.ID = "Button" + cpu.ID;
b.CommandArgument = cpu.ID.ToString();
b.Text = "Add to Cart";
b.OnClientClick = "Addtocart_Click";
buttonContainer.Controls.Add(b);
%>
</span>
<br />
</div>
</div>
In your situation, since you are using inline code, the below approach is the most optimal.
I have place a placeholder control to your original markup, that has an id of placeHolder1 at the location where the button needs to appear. This is what gives you total control over where the button will appear in the rendered page.
You need to use a placeholder control, which is a standard ASP.Net
control for adding controls dynamically at run-time.
You place the placeholder control at the location in your page markup where you would like the dynamically created button to appear.
Then, just use the line of code placeHolder1.Controls.Add(b); to add your button control.
Dynamically add a button at a certain location in your page
<%
var cpus = productItems.FindAll(t => t.Type == "cpu");
foreach (var cpu in cpus)
{ %>
<div class="row product cpu">
<div class="col-md-3">
<img class="center-block" src="Content/images/processor.jpg" />
<span class="price"><%= cpu.Price %></span>
<span class="addtocart">
<% Button b = new Button();
b.ID = "Button" + cpu.ID;
b.CommandArgument = cpu.ID.ToString();
b.Text = "Add to Cart";
b.OnClientClick = "Addtocart_Click";
placeHolder1.Controls.Add(b);
%>
<asp:PlaceHolder ID="placeHolder1" runat="server"></asp:PlaceHolder>
</span>
<br />
</div>
</div>
<% } %>
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);
}
I have a placeholder control within an UpdatePanel, and when the Add Vehicle button is clicked, I need a new "row" of controls to appear (The first "row" is added declaratively). The UserControl however gets added but not displayed. How can I fix this?
protected void AddVehicleButton_Click(object sender, EventArgs e)
{
int count = Convert.ToInt32(VehicleRegistrationCountHiddenField.Value);
var TBId = "VehicleRegistrationEnhancedTextBox" + count;
IList<Panel> oldPanels = (IList<Panel>)Session["VehiclePanels"] ?? new List<Panel>();
//Seperator
Literal hr = new Literal { Text = "<HR/>" };
//Vehicle Registration
UserControl uc = new UserControl(){ID="3"};
uc.LoadControl("~/Controls/ImageUploadAndCrop/ImageUploadAndCrop.ascx");
Label vehicleRegistration = new Label
{
ID = TBId + "_Label",
AssociatedControlID = TBId,
Text = "Vehicle Registration:"
};
EnhancedTextBox vehicleTypeTextBox = new EnhancedTextBox
{
ID = TBId,
Required = true,
RequiredErrorText = "Vehicle Registration is a required field."
};
//Readd previously added panels
foreach (var addedPanel in oldPanels)
{
AddVehiclePlaceholder.Controls.Add(addedPanel);
}
//Add new controls to the form
Panel newPanel = new Panel();
newPanel.Controls.Add(hr);
newPanel.Controls.Add(uc);
newPanel.Controls.Add(vehicleRegistration);
newPanel.Controls.Add(vehicleTypeTextBox);
AddVehiclePlaceholder.Controls.Add(newPanel);
//Increment the ID count
count++;
VehicleRegistrationCountHiddenField.Value = count.ToString();
//Save the panel to the Session.
oldPanels.Add(newPanel);
Session["VehiclePanels"] = oldPanels;
}
The html is below:
<div id="Step2" style="" data-step="2">
<h2> Step 2 (optional): Capture the offender(s) vehicle Information. </h2>
<hr>
<div id="VehicleTypeFields">
<div>
<label for="">Vehicle Registration</label>
<div id="Body_Body_UpdatePanel1">
<div>
<div>
<script type="text/javascript" src="/Controls/ImageUploadAndCrop/Javascript/jquery.Jcrop.min.js">
<link type="text/css" rel="stylesheet" href="/Controls/ImageUploadAndCrop/CSS/jquery.Jcrop.css">
<script type="text/javascript">
<div>
<div id="Body_Body_VehicleRegistrationImageUploadAndCrop_UploadPanel">
</div>
<input id="Body_Body_VehicleRegistrationEnhancedTextBox" type="text" placeholder="CA123-456" name="ctl00$ctl00$Body$Body$VehicleRegistrationEnhancedTextBox">
</div>
</div>
</div>
</div>
<div id="Body_Body_AddVehiclesUpdatePanel">
<input id="Body_Body_VehicleRegistrationCountHiddenField" type="hidden" value="2" name="ctl00$ctl00$Body$Body$VehicleRegistrationCountHiddenField">
<div>
<hr>
<label id="Body_Body_VehicleRegistrationEnhancedTextBox1_Label" for="Body_Body_VehicleRegistrationEnhancedTextBox1">Vehicle Registration:</label>
<input id="Body_Body_VehicleRegistrationEnhancedTextBox1" type="text" name="ctl00$ctl00$Body$Body$VehicleRegistrationEnhancedTextBox1">
<span id="Body_Body_VehicleRegistrationEnhancedTextBox1_RequiredFieldValidator" style="display:none;">Vehicle Registration is a required field.</span>
</div>
</div>
</div>
The problem is your use of LoadControl on a new instance of UserControl rather than the page's implementation. IE rather than this:
UserControl uc = new UserControl(){ID="3"};
uc.LoadControl("~/Controls/ImageUploadAndCrop/ImageUploadAndCrop.ascx");
Do this instead:
Control uc = LoadControl("~/Controls/ImageUploadAndCrop/ImageUploadAndCrop.ascx");
uc.ID = 3;
I think that will fix your immediate problem with nothing displaying but there are still other issues. While it might be possible to store the entire control in session state, my own testing shows there are anomolies in doing so. I would instead make sure you give each instance of your user control a unique ID (not "3" every time), and store those ID's somewhere. Then loop thru those ID's, calling LoadControl for each one, setting the control ID as you loop (this is required in order for the past viewstate to be reapplied to your user control.
I would also move that loop to either Page_Init or Page_Load so that your dynamically created user controls can properly participate in the page's lifecycle. Creating them in that click event is too late for them to catch their own events and they won't be created at all in the case of a postback outside of that click event.
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";