I have a series of asp:textboxes (about 30) which I wanted to validate if they are empty (when the user goes to other textbox), when the users leave them empty (on blur) I have found tutorials on the net however it is specified only to a few textboxes, how can I achieve this?
<form id="form1" runat="server">
<asp:TextBox ID="txtLname" runat="server" placeholder="Last Name" BackColor="White" BorderColor="#C2C4CC" BorderStyle="Solid" Height="28px" Width="135px" title="Enter Your Last Name" onkeypress="return AllowAlphabet(event)" Enabled="False" TabIndex="4"></asp:TextBox>
A little bit of your actual markup would come in handy, but from the information i have:
$('input, textarea').blur(function() {
if ($(this).val() == "") alert("empty!");
});
when the users leave them empty (on blur) I have found tutorials on
the net
How is this a sentence?
Try this code:
function CheckEmptyCheckBox() {
var empty = 0;
$('input[type=text]').each(function(){
if (this.value == "") {
empty++;
$("#error").show('slow');
}
})
alert(empty + ' empty input(s)')
}
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I am making a Canteen Management System using ASP.NET Forms.
So I want a Pop-Up window or box which will take input from dropdown list and textbox to implement Filter option.
So how to make it and how to access collected data from code behind?
Any tutorials links or suggestion are all welcome. Thanks for helping :)
There are quite a few ways to do this. If you using the AjaxControlToolKit, they have a fantastic pop up extender, and it takes no JavaScript.
However, probably the best choice is to use jQuery.UI. It is without a doubt your site and application has jQuery, so, I would add jQuery.UI. You can use nueget to install it, or simply go to the jquery site and download the jQuery.UI files. They are common.
So, the way we do this is you create (usually) a "div" on the page that is a popup. This works great since is responds to a "click" very fast (you don't even have to hit the server for the dialog to pop-up. However, the form you pop up might be to edit data.
The next consideration is that popup form cannot have post-backs. (well, ok, it can have one). So if the form you popup is to have some rich verification code, or code that requires some server side event code to run? You tend to be out of luck. So, you can easy pop a form, the user can edit (or enter data), but then you only allowed ONE post-back button event (say "ok - save"). So in most cases such a popup form is fine, but do keep in mind this limitation. If you do need some things to respond in that dialog, then you in most cases have to write ajax calls - that is extra pain and workload for the developer.
So, lets assume we want to pop up a dialog to filter a grid. The popup will allow the user to type in the first few characters of the hotel name OR WE can select a city from a drop down list to filter the grid by city.
and we toss in a show only "active" records with a check box.
So, how would this work, and look? (and keeping the above considerations in mind (only one post-back allowed in the pop dialog).
Well, we first build the grid. But, we need to add some buttons to the heading. So I have to drop a few of the databound fields, and use a template for that one column. This lets us setup the header with a button, or whatever we feel like.
And I did the same for the city heading.
So, we have this markup:
<div id="HotelGrid" runat="server" style="width:50%">
<asp:GridView ID="GHotels" runat="server" AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table table-hover"
style="vertical-align:middle" ShowHeaderWhenEmpty="true">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:TemplateField>
<HeaderTemplate>
<asp:LinkButton ID="btnSearchCity"
runat="server"
CssClass="btn-default btn-sm"
>City
<span aria-hidden="true" class="glyphicon glyphicon-search"></span>
</asp:LinkButton>
</HeaderTemplate>
<ItemTemplate>
<asp:Label ID="lblCity" runat="server" Text='<%# Eval("City") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Province" HeaderText="Province" />
<asp:TemplateField HeaderStyle-Width="200px">
<HeaderTemplate>
<asp:LinkButton ID="cmdSearchHotel"
runat="server"
CssClass="btn-default btn-sm"
OnClientClick="return mysearch(this);"
OnClick="cmdSearchHotel_Click"
>Hotel
<span aria-hidden="true" class="glyphicon glyphicon-search"></span>
</asp:LinkButton>
</HeaderTemplate>
<ItemTemplate>
<asp:Label ID="lblHotel" runat="server" Text='<%# Eval("HotelName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Description"HeaderText="Description" />
<asp:TemplateField HeaderText="Active" ItemStyle-HorizontalAlign="Center" >
<ItemTemplate>
<asp:CheckBox ID="chkActive" runat="server" Checked='<%# Eval("Active") %>' />
</ItemTemplate>
<ItemStyle HorizontalAlign="Center"></ItemStyle</asp:TemplateField>
<asp:TemplateField HeaderText="Edit">
<ItemTemplate>
<asp:Button ID="cmdEdit" runat="server" Text="Edit"class="btn" OnClick="cmdEdit_Click"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Now, you can see in above, the markup starts to grow - that's due to gridview requiring "template" around each set of controls. (I often suggest using a listview, since you don't need the template(s). But no big deal.
Ok, so we have the above markup.
My page load code to load the grid? Well, we want the heading to dispaly, so we do it this way:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
GHotels.DataSource = MyRst("select * from tblHotels where id = 0")
GHotels.DataBind()
' load the city combo box
cboCity.DataSource = MyRst("SELECT City from tblCity ORDER BY City")
cboCity.DataBind()
cboCity.Items.Insert(0, "") ' allow blank selection
End If
End Sub
Public Function MyRst(strSQL As String) As DataTable
Dim rstData As New DataTable
Using MyCon As SqlConnection = New SqlConnection(My.Settings.TEST3)
Using cmdSQL As New SqlCommand(strSQL, MyCon)
cmdSQL.Connection.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
End Using
Return rstData
End Function
Ok, so we now see/have this:
Now, the two buttions in the grid heading will have TWO parts.
The part to pop the dialog (jQuery.UI), and then the standard code server side.
Ok so, we have to create a div to hold our pop up.
It will be rather simple, and just combo box (for city), a text box for hotel anme, and a check box for "active only" filter.
so, that div is quite simple. and note when we happy with the div layout, we add display:none to hide the div.
so we have this:
<div id="mysearchdiv" style="border:solid;width:300px;text-align:right;padding:15px;font-size:large;display:NONE">
<p>Select City
<asp:DropDownList ID="cboCity" runat="server" width="150px"
DataTextField="City"
DataValueField="City"
></asp:DropDownList>
</p>
<p>
Hotel Name
<asp:TextBox ID="txtSearchHotel" runat="server" Width="150" Height="25"></asp:TextBox>
</p>
<p>
Include Only Active
<asp:CheckBox ID="chkActiveOnly" runat="server" />
</p>
<asp:HiddenField ID="cmdOption" runat="server" ClientIDMode="Static"/>
</div>
Really very simple markup.
Ok, now the hard part, the jQuery UI is a java script routine, and it is this:
<script>
var searchok = false
function mysearch(btn) {
if (searchok) {
return true
}
var myDialog = $("#mysearchdiv");
myDialog.dialog({
title:"Search For Hotels",
modal: true,
width: "320px",
resizable: false,
appendTo: "form",
autoOpen: true,
buttons: {
Ok: function ()
{
searchok = true
btn.click()
},
Clear: function () {
searchok = true
$('#cmdOption').val('c')
btn.click()
},
Cancel: function () {
myDialog.dialog('close')
}
}
});
return false
}
</script>
So, it is a bit of code, but what jQuery.UI is "grabs" that div, and converts it into a nice dialog. So the end result is this:
Now, either the c# tag was added after I started typing this, or I missed it.
but, the c# code is much the same. The first page load code is this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GHotels.DataSource = MyRst("select * from tblHotels where id = 0");
GHotels.DataBind();
// load our search combo box
cboCity.DataSource = MyRst("SELECT City from tblCity ORDER BY City");
cboCity.DataBind();
cboCity.Items.Insert(0,new ListItem("",""));
}
}
public DataTable MyRst(string strSQL)
{
DataTable rstData = new DataTable();
using (SqlCommand cmdSQL = new SqlCommand(strSQL,
new SqlConnection(Properties.Settings.Default.TEST3)))
{
cmdSQL.Connection.Open();
rstData.Load(cmdSQL.ExecuteReader());
}
return rstData;
}
So above will load up the grid (we send it a blank row, since we using the header for searching.
and the buttion click? Well, we pop a jquery dialog. And if it returns true, or false - that determines if the server side buttion will fire.
So, we have this:
<asp:TemplateField HeaderStyle-Width="200px">
<HeaderTemplate>
<asp:LinkButton ID="cmdSearchHotel"
runat="server"
CssClass="btn-default btn-sm"
OnClientClick="return mysearch(this);"
OnClick="cmdSearchHotel_Click"
>Hotel
<span aria-hidden="true" class="glyphicon glyphicon-search"></span>
</asp:LinkButton>
</HeaderTemplate>
<ItemTemplate>
<asp:Label ID="lblHotel" runat="server" Text='<%# Eval("HotelName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
Note very carefull how we have the jQuery search routine return true ,or false.
Ok, so now it is a simple matter to write that code to filter/search the grid based on that popup.
The code is quite simple, and we "cumulative" add up each search option, or simple skip the options if no value in the search box is entered.
And, we added that hidden field, since as you can see, we can now add more buttons to that dialog, but not have to create new code server side - but just use the one button click to handle all options for that dialog.
And the c# code for this filtering is thus:
protected void cmdSearchHotel_Click(object sender, EventArgs e)
{
if (cmdOption.Value == "c")
{
// clear the search option
cboCity.Text = "";
txtSearchHotel.Text = "";
chkActiveOnly.Checked = false;
cmdOption.Value = "";
GHotels.DataSource = MyRst("select * from tblHotels where id = 0");
GHotels.DataBind();
return;
}
// filter the grid
string strWhere = "";
using (SqlConnection con = new SqlConnection(Properties.Settings.Default.TEST3))
using (SqlCommand cmdSQL = new SqlCommand("SELECT * FROM tblHotels",con))
{
if (cboCity.Text != "")
{
strWhere += "City = #City";
cmdSQL.Parameters.Add("#City", SqlDbType.NVarChar).Value = cboCity.Text;
}
if (txtSearchHotel.Text != "")
{
if (strWhere != "")
strWhere += " AND ";
strWhere += "HotelName like #Hotel + '%'";
cmdSQL.Parameters.Add("#Hotel", SqlDbType.NVarChar).Value = txtSearchHotel.Text;
}
if (chkActiveOnly.Checked)
{
if (strWhere != "")
strWhere += " AND ";
strWhere += "Active = 1";
}
if (strWhere != "")
cmdSQL.CommandText += " WHERE " + strWhere;
cmdSQL.CommandText += " ORDER BY HotelName";
con.Open();
GHotels.DataSource = cmdSQL.ExecuteReader();
GHotels.DataBind();
}
So, all in all:
A absoulte min of code.
Not really much more markup then a typical grid.
And I shared a LONG time super cool trick that VERY VERY VERY few have used. That is how to get the one jQuery.UI dialog to NOT fire the server side button if we don't want to. And thus we don't need multiple routines in java, and we don't need multiple routines server side. We simply have the one button call the dialog, and it returns true, or false. But it STILL is running asyncrious as all and most JavaScript widgets should be. (no blocking code allowed!!!).
You can create fied position DIV and show it using JS,JQuery, ... whenever you want to show the dialog.
then you can read input data.
How to generate a simple popup using jQuery
This is my table and on this table I have cells in form of buttons. With my css sheet I have made them green.
<asp:Table ID="Table1" runat="server" BorderWidth="2px" BorderColor="#0033cc" BackColor="#ffcccc" >
<asp:TableRow>
<asp:TableCell CssClass="Table-cell-room" ID="D256">D256<br /></asp:TableCell>
<asp:TableCell><asp:Button runat="server" Width="100px" Text="Boka" ID="R1B1" OnClick="Button_Click_First_Row" CssClass="Buttons"/></asp:TableCell>
<asp:TableCell><asp:Button runat="server" Width="100px" Text="Boka" ID="R1B2" OnClick="Button_Click_First_Row" CssClass="Buttons"/></asp:TableCell>
<asp:TableCell><asp:Button runat="server" Width="100px" Text="Boka" ID="R1B3" OnClick="Button_Click_First_Row" CssClass="Buttons"/></asp:TableCell>
<asp:TableCell><asp:Button runat="server" Width="100px" Text="Boka" ID="R1B4" OnClick="Button_Click_First_Row" CssClass="Buttons"/></asp:TableCell>
<asp:TableCell><asp:Button runat="server" Width="100px" Text="Boka" ID="R1B5" OnClick="Button_Click_First_Row" CssClass="Buttons"/></asp:TableCell>
</asp:TableRow>
I have also a Database table called Room and contains Id, Button_id and CheckIfBooked.
Now I want to use my "colum" CheckedIfBook to see if they are booked, meaning CheckedIfBooked = 1.
All of this work but I have no idea to style my buttons on the table which of those who already have CheckedIfBooked = 1.
Meaning that in my Database table I have R1B1 and it's value CheckedIfBooked = 1. But I have no idea to code this in page load. Also I don't want to use
if(Button_id == R1B2){
CheckedIfBooked == 1
//Do some styling on that button
}
Cause I have ALOT of buttons and in my c# code I use sender as new button to get the correct ID from the button clicked.
Possible Solution #1
When rendering the page, add an additional css class to your button if isBooked = true
if (isBooked) {
/// Render the "isBooked" TableCell Button
<asp:TableCell> ... CssClass="isBooked"/></asp:TableCell>
} else {
/// Render the "not Booked" TableCell Button
<asp:TableCell> ... CssClass="Button"/></asp:TableCell>
}
Then in your css:
.isBooked { /* isBooked Button Styles Here */ }
So when your code gets rendered to HTML, the css classes are already in place:
<!-- Example HTML Output -->
< ... class="Button" ... ></>
< ... class="isBooked" ... ></>
< ... class="Button" ... ></>
Possible Solution #2
On page load, have jQuery look for the booked buttons, and disable them, or style them, etc..
$(document).ready(function(){
$("isBooked").each(function(index){
// each isBooked element is now available via $(this)
$(this).addClass("bookedButton");
$(this).prop("disabled", true);
// ...
});
});
Security note: Simply disabling a form button on the client-side (via javascript) isn't enough, you also need to validate data on the server side. So if you disable form elements on the client, make sure your server also verifies that nothing "booked" is trying to be submitted to your form.
Hope this helps.
An issue has manifested in a particular area of a page I'm working on that utilizes the infamous Repeater. The control is bound to a valid Data Source that does persist through the View State.
The Repeater code is as follows:
<asp:Repeater ID="creditRightItems" runat="server" DataSourceID="sdsOrder">
<HeaderTemplate>
<thead>
<td>Qty Returning:</td>
<td>Price:</td>
</thead>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><asp:TextBox ID="txtQuantity" runat="server" PlaceHolder="0" CssClass="txtQuantity Credit-Check" data-item='<%# Eval("ProductNum") %>' /><span class="creditX">X</span></td>
<td><span id="ProductPrice" class='Credit-Container price<%# Eval("ProductNum") %>'><%# ConvertToMoney(Eval("Price").ToString()) %></span>
<input type="hidden" id="hfPrice" value="<%# Eval("Price") %>" />
<input type="hidden" id="hfProdNum" value="<%# Eval("ProductNum") %>" />
<input type="hidden" id="hfSKU" value="<%# Eval("SKU") %>" />
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
The issue occurs in code behind when I iterate through the Repeater. Essentially the loop only finds two controls, which may be apart of the issue. However, when I attempt to grab those values from code-behind they return null. If I add a runat="server" then it will actually error the Repeater.
foreach (RepeaterItem item in creditRightItems.Items)
{
TextBox inputQuantity = (TextBox)item.FindControl("txtQuantity");
string quantity = inputQuantity.Text;
TextBox inputProduct = (TextBox)item.FindControl("hfProdNum");
string product = inputProduct.Text;
HtmlInputHidden productPrice = (HtmlInputHidden)item.FindControl("hfPrice");
string price = productPrice.Value;
TextBox inputSKU = (TextBox)item.FindControl("hfSKU");
string sku = inputSKU.Text;
if (string.Compare(quantity, "0") != 0 && string.IsNullOrEmpty(quantity))
items.Add(new Items(product, quantity, price, sku));
}
The question is, how can I get a valid value for:
ProductPrice or hfPrice
hfProdNum
hfSku
For the life of me I can't get them to return a valid content. I've tried:
HiddenField productPrice = (HiddenField).item.FindControl("hfPrice");
string price = productPrice.Value;
HtmlInputHidden productPrice = (HtmlInputHidden).item.FindControl("hfPrice");
string price = productPrice.Value;
I know that FindControl requires the runat so I'm trying to either achieve a way to avoid the Repeater breaking when I add a runat or a way to grab the contents of those inputs.
Any thoughts and help would be terrific.
What you have in your source aren't server controls, so FindControl won't find them.
Why can't you just convert the hidden fields to asp:HiddenField tags?
<asp:HiddenField id='hfPrice' value='<%# Eval("Price") %>' runat='server' />
The runat probably isn't breaking your page; I think it's the single vs double quotes on your Eval call. If you alternate them like I have in this sample, it will work.
Well, without knowing where your code is at exactly, I guess that you should consider doing this manipulation on good event.
Try handling ItemDataBound event. And instead of iterating trought every Rows, do something like :
(VB.net code, sorry)
Private Sub myRepeater_ItemDataBound(sender as object, e as RepeaterItemEventArgs) andles myRepeater.ItemDataBound
If (e.Item IsNot Nothing AndAlso (e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem)) Then
' DO STUFF HERE
Dim productPrice As HtmlInputHidden = (HtmlInputHidden).item.FindControl("hfPrice")
Dim price As String = productPrice.Value
End If
End Sub
So the culprit is due to the quotation and single quote, the error exist when:
value="<%# Eval("Price") %>"
The error no longer occurs, if you do:
value='<%# Eval("Price") %>'
Which alleviates the error in the page breaking, which allows me to properly run FindControl. A careless error on my part, but hopefully this helps someone in the future.
Ok so I have a problem. I am currently working on a project using the Telerik framework for ASP.NET AJAX, although that shouldnt matter much as I am bypassing Telerik completely (almost) for this portion of the work.
I'm putting together a facebook-like chat program into our company's CRM system and, while all has gone well up to this point, I've hit a roadblock. The problem is when I try to "create a new chatbox". I'm using the asp control UpdatePanel in conjunction with a jQuery $.ajax call to pass a JSON method name to my code behind file. Here's the JSON logic:
DoubleClick on user in userlist:
$telerik.$(".UserListEntry").dblclick(function () {
var ToName = $telerik.$(this).children(".UserListEntryName").text();
var FromName = $telerik.$("#lkUserGeneralSettings").text();
$telerik.$.ajax({
type: 'POST',
url: 'DefaultHandler.ashx',
data: { "ToName": ToName, "FromName": FromName },
success: CreateChatBox(),
error: function (response) { alert("error: 001"); }
});
});
CreateChatBox callback:
function CreateChatBox() {
$telerik.$.ajax({
type: 'POST',
url: 'Default.aspx',
data: { MethodName: "CreateChatBox" },
success: ForceAsyncPostback,
error: function (response) { alert("error: 002"); }
});
}
Force asyncpostback (shouldn't be necessary, but this doesnt even work either!):
function ForceAsyncPostback() {
var UpdatePanel1 = '<%=Panel3.ClientID%>';
if (UpdatePanel1 != null) {
__doPostBack(UpdatePanel1, '');
}
alert("Success");
}
The UpdatePanel is created through various literals and some hard-coded html good-ole' fashioned divs. The problem is NOT with the dynamic creation of said elements, this works just fine. In fact my code behind (which I will post below) creates and displays everything perfectly fine if I place it into my PageLoad event.
At any rate, here's the .aspx:
<asp:UpdatePanel ID="Panel3" runat="server" OnLoad="Panel3_Load" UpdateMode="Conditional">
<ContentTemplate>
<asp:Literal ID="ChatBoxesLiteralTop" runat="server" />
<asp:Literal ID="ChatBoxesLiteralMid" runat="server" />
<asp:PlaceHolder ID="ChatBoxesPlaceHolder" runat="server" />
<asp:Literal ID="ChatBoxesLiteralBot" runat="server" />
<div id="UserListCorner">
<img id="UserListBtn" src="images/list.png" />
</div>
<div id="UserList" class="UserListHidden">
<div id="UserListView">
<asp:Literal ID="UserListViewLiteral" runat="server" />
</div>
</div>
</ContentTemplate>
</asp:UpdatePanel>
Code Behind:
protected void Panel3_Load(object sender, EventArgs e)
{
#region Ajax methods
if (Request.Form["MethodName"] == "CreateChatBox")
{
CreateChatBox();
}
#endregion
Engine m_engine = new Engine();
string m_sql = #"SELECT FullName FROM Users WHERE RecordDeleted <> 1";
DataTable dt = m_engine.GetObjectsAsDataTable(m_sql);
for (int i = 0; i < dt.Rows.Count; i++)
{
UserListViewLiteral.Text += "<div class='UserListEntry'><span class='UserListEntryStatus'><img src='images/status-online.png' width='10' /></span> <span class='UserListEntryName'>" + dt.Rows[i]["FullName"].ToString() + "</span></div>";
}
RadAjaxManager.GetCurrent(Page).ResponseScripts.Add("ChatAjax()");
}
private void CreateChatBox()
{
ChatBoxesLiteralTop.Text = #"<div id='ChatBox' class='ChatBoxHidden'>
<div class='ChatBoxHeader'>
<img id='ChatBoxStatusBtn' src='Images/status-online.png' />
<span id='ChatBoxUserLabel'>John Doe</span>
<img id='closeBtn' src='Images/close.png' />
<img id='toggleTab' src='Images/up-arrow.png' />
</div>
<div id='ChatBoxMessageOutput'></div><div class='ChatBoxFooter'>";
TextBox txt = new TextBox();
txt.ID = "ChatBoxMessageInput";
txt.Height = 16;
txt.MaxLength = 270;
txt.Width = 250;
txt.AutoPostBack = false;
ChatBoxesPlaceHolder.Controls.Add(txt);
RadButton btn = new RadButton();
btn.ID = "ChatBoxSendButton";
btn.Text = "Send";
btn.AutoPostBack = true;
btn.Height = 22;
btn.Click += ChatBoxSendButton_Click;
ChatBoxesPlaceHolder.Controls.Add(btn);
ChatBoxesLiteralBot.Text = "</div></div>";
Panel3.Update();
RadAjaxManager.GetCurrent(Page).ResponseScripts.Add("ChatAjax()");
}
I'm certainly overlooking something outrageously stupid, but a fresh set of eyes from a seasoned ASP.Net Ajaxer would be really appreciated! Thanks in advance.
Clarification of Issue
What DOES work:
The code runs properly.
The JSON method is passed to the code behind and read.
The CreateChatBox() method runs through and allegedly populates the literals and controls.
All callbacks in the JSON chain are executed successfully.
What DOES NOT work:
The UpdatePanel, even after the redundant postback, does not have
this new HTML after code executes successfully.
To Whom It May Concern
Well I happened to solve this problem the day after posting it. Of course there are now new hurdles to tackle but I am happy to say that my asynchronous chat module is nearly done. Since nobody decided to take on the problem, I am going to post what I did to properly produce dynamic, asynchronous objects based on hard-coded HTML in ASP.NET since, while Googling the matter, this post was the only relevant result popping up.
I'll start by saying I am well aware that this is a very unconventional approach. That being said, the requirements of the project justified the means. While there may be many other ways to accomplish your goal, this does work. I am not going to go into extraneous details with respect to my particular project, but hopefully this will help somebody in the future.
The Wrongs
The primary problem with my original question was the way I was attacking the rendering sequence. A major flaw in my logic was attempting to separate the ASP controls (literals, placeholders, buttons and such) from my HTML too much. My initial approach (from above) looked like this:
<asp:UpdatePanel ID="Panel3" runat="server" OnLoad="Panel3_Load" UpdateMode="Conditional">
<ContentTemplate>
<asp:Literal ID="ChatBoxesLiteralTop" runat="server" />
<asp:Literal ID="ChatBoxesLiteralMid" runat="server" />
<asp:PlaceHolder ID="ChatBoxesPlaceHolder" runat="server" />
<asp:Literal ID="ChatBoxesLiteralBot" runat="server" />
<div id="UserListCorner">
<img id="UserListBtn" src="images/list.png" />
</div>
<div id="UserList" class="UserListHidden">
<div id="UserListView">
<asp:Literal ID="UserListViewLiteral" runat="server" />
</div>
</div>
</ContentTemplate>
</asp:UpdatePanel>
The final result looks more like this:
<asp:UpdatePanel ID="Panel3" runat="server" OnLoad="Panel3_Load" UpdateMode="Conditional">
<ContentTemplate>
<asp:PlaceHolder ID="ChatBoxesPlaceHolder" runat="server" />
<div id="UserListCorner">
<img id="UserListBtn" src="images/list.png" />
</div>
<div id="UserList" class="UserListHidden">
<div id="UserListView">
<asp:Literal ID="UserListViewLiteral" runat="server" />
</div>
</div>
<asp:Label ID="Label42" Font-Bold="true" runat="server" />
<asp:HiddenField runat="server" ID="LatestDisplayTick" />
</ContentTemplate>
</asp:UpdatePanel>
With the code behind (abridged) similar to this:
Literal top = new Literal();
// ...
UpdatePanel UpdatePanel2 = new UpdatePanel();
// ...
top.Text = #"<div id='ChatBox' class='ChatBoxShown'>
<div class='ChatBoxHeader'>
<img id='ChatBoxStatusBtn' src='Images/status-online.png' />
<span id='ChatBoxUserLabel'>" + UserNames[0] + #"</span>
<img id='closeBtn' src='Images/close.png' />
<img id='toggleTab' src='Images/up-arrow.png' />
</div>";
top.ID = "ChatBoxesLiteralTop";
top.Mode = LiteralMode.PassThrough;
// ...
UpdatePanel2.ID = "UpdatePanel2";
UpdatePanel2.UpdateMode = UpdatePanelUpdateMode.Conditional;
UpdatePanel2.ChildrenAsTriggers = false;
UpdatePanel2.ContentTemplateContainer.Controls.Add(top2);
// ...
Panel3.ContentTemplateContainer.Controls.Add(top);
Panel3.ContentTemplateContainer.Controls.Add(UpdatePanel2);
Panel3.ContentTemplateContainer.Controls.Add(mid);
What It Means
All I've done is wrapped the entirety of my chatbox elements inside a single placeholder, dynamically creating HTML elements that wrap ASP controls all from the server and posting it as a "chunk" of dynamic data. This sidesteps some strange behaviors with ASP control placement otherwise, and allows for a quasi-OO approach for the client-side functionality of my project. After creation, I can now make use of some JSON and AJAX calls to dynamically enter data into said dynamically created controls.
An example would be posting a message received from a database notification to my chat window (ChatBoxesLiteralMid control) when it is received.
After Page/Control Load
if(ChatBoxesLiteralMid != null)
ChatBoxesLiteralMid.Text += #"<div class='ChatBoxEntry'><span class='ChatBoxEntryName ChatBoxSelf'>" + AppParameters.Current.AppUser.FirstName + "</span>: <span class='ChatBoxEntryMessage'>" + dy.Rows[dy.Rows.Count - 1]["Message"].ToString() + "</span></div>";
Why Go To The Trouble?
What I have accomplished is for a particular project with needs to go far above and beyond the original scope, started by another developer years prior. This is an unconventional way to teach the old dog some new tricks. I now have near-full control of an indiscriminate amount of real-time chat boxes/sessions on the CLIENT side. It's really pretty freakin' sweet honestly. Please feel free to post questions (or concerns) as I regularly check SO and am happy to respond.
I have been trying to set the value of a hidden input by using Javascript and then access the value from within my C# codebehind. When I run the code that is copied below, the value that is assigned to assignedIDs is "", which I assume is the default value for a hidden input. If I manually set the value in the html tag, then assignedIDs is set to that value.
This behavior suggests to me that the value of the input is being reset (re-rendered?) between the onClientClick and onClick events firing.
I would appreciate any help with the matter. I have spent hours trying to solve what seems like a very simple problem.
html/javascript:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Admin Page - Manage Tasks</title>
<script language="javascript" type="text/javascript">
function PopulateAssignedIDHiddenInput() {
var source = document.getElementById('assignedLinguistListBox');
var s = "";
var count = source.length;
for (var i = count - 1; i >= 0; i--) {
var item = source.options[i];
if (s == "") { s = source.options[i].value; }
else { s = s.concat(",",source.options[i].value); }
}
document.getElementById('assignedIDHiddenInput').Value = s;
// I have confirmed that, at this point, the value of
// the hidden input is set properly
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Panel id="EditMode" runat="server">
<table style="border: none;">
<tr>
<td>
<asp:Label ID="availableLinguistLabel" runat="server" Text="Available"></asp:Label><br />
<asp:ListBox ID="availableLinguistListBox" runat="server" Rows="10" SelectionMode="Multiple"></asp:ListBox>
</td>
<td>
<input type="button" name="right" value=">>"
onclick="Javascript:MoveItem('availableLinguistListBox', 'assignedLinguistListBox');" /><br /><br />
<input type="button" name="left" value="<<"
onclick="Javascript:MoveItem('assignedLinguistListBox', 'availableLinguistListBox');" />
</td>
<td>
<asp:Label ID="assignedLinguistLabel" runat="server" Text="Assigned To"></asp:Label><br />
<asp:ListBox ID="assignedLinguistListBox" runat="server" Rows="10" SelectionMode="Multiple"></asp:ListBox>
</td>
</tr>
</table>
//-snip-
<asp:Button ID="save_task_changes_button" runat="server" ToolTip="Click to save changes to task"
Text="Save Changes" OnClick="save_task_changes_button_click" OnClientClick="Javascript:PopulateAssignedIDHiddenInput()" />
</asp:Panel>
<!-- Hidden Inputs -->
<!-- Note that I have also tried setting runat="server" with no change -->
<input id="assignedIDHiddenInput" name="assignedIDHiddenInput" type="hidden" />
</div>
</form>
</body>
c#
protected void save_task_changes_button_click(object sender, EventArgs e)
{
string assignedIDs = Request.Form["assignedIDHiddenInput"];
// Here, assignedIDs == ""; also, Request.Params["assignedIDHiddenInput"] == ""
// -snip-
}
In javascript you need the value property to be lowercase, like this:
document.getElementById('assignedIDHiddenInput').value = s;
Then it will be set properly :) You can see an example in action here
Though if you alert the .Value it will show your value, you've actually added a new .Value property, but you haven't set the input's .value property which is what gets posted to the server. The example link above illustrates this both ways.
Also you can make it a bit faster especially if you have lots of options by using an array instead of string concatenation, like this:
var source = document.getElementById('assignedLinguistListBox');
var opts = [];
for (var i = 0; i < source.options.length; i++) {
opts.push(source.options[i].value);
}
var s = opts.join(',');
Edit: The above code is updated, CMS is right that the previous method was browser dependent, the above should now behave consistently. Also, if jQuery is an option, there are shorter ways of getting this info still, like this:
var s = $('#assignedLinguistListBox option').map(function() {
return this.value;
}).get().join(',');
$('#assignedIDHiddenInput').val(s);
You can see a working example of this here
I'm assuming ASP.NET here.
If so, your problem is the id of the control in the HTML generated by ASP.NET is not going to be "assignedIDHiddenInput" that you reference in the script. ASP.NET changes those before rendering the HTML from what you specify in the HTML page declaratively. Do a view source on the page and you will see what I mean.
Here is a way around that:
document.getElementById('<%=assignedIDHiddenInput.ClientID %>').value = s;
Update: As noted in the comments, this is only relevant if the control is set to RunAt=Server.
I think ASP.NET is calling the javascript to execute a postback on that control before your javascript function is called to populate that hidden value.
I think it's possible to disable the default postback and handle it yourself but I'm sure others can advise better.
Stick an alert() into your function there to see if it is really getting called before post-back is triggered.