I am having header in gridview that labels as "xls" and a checkbox, that when selected should select all the checkbox columns in gridview and unchecking the xls column should uncheck all the columns.
I am following two links:
Link-1
Here, the totalChkBoxes variable is coming null (despite my gridview has rows). In fact when debugging the JS, code inside parseInt and below line is coming as ''
Link-2
Here also the GridView2 variable is coming null.
One common change that i am doing in both the JS is replacing the <%=.....%> by <%#....%>
Please guide as to what i am doing wrong. You can also help by giving some suitable link to implement the desired functionality
CODE UPDATED WITH MY WORKING JS
<script type="text/javascript" language="javascript">
function checkAllBoxes() {
var gvControl = document.getElementById("gvSample");
//this is the checkbox in the item template.
var gvChkBoxControl = "chkSelectItem";
//Header Template checkbox.
var mainChkBox = document.getElementById("chkBoxAll");
//Array of Inputs in gridview.
var inputTypes = gvControl.getElementsByTagName("input");
for (var i = 0; i < inputTypes.length; i++) {
//if the input type is a checkbox and the id of it is what we set above
//then check or uncheck according to the main checkbox in the header template
if (inputTypes[i].type == 'checkbox' && inputTypes[i].id.indexOf(gvChkBoxControl, 0) >= 0)
inputTypes[i].checked = mainChkBox.checked;
}
}
GRIDVIEW CODE
<asp:TemplateField>
<HeaderTemplate>
<table style="width: 15px" cellpadding="0" cellspacing="0">
<tr>
<td>
<asp:Label ID="lblXls" runat="server" Text="xls"></asp:Label>
<br />
<input id="chkBoxAll" type="checkbox" onclick="checkAllBoxes()" />
</td>
</tr>
</table>
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox ID="chkSelectItem" runat="server" />
</ItemTemplate>
</asp:TemplateField>
Thanks!
Try changing your parseInt to something like this to see if it helps at all. I know it's only a small change, but small things tend to break JS code:
var totalChkBoxes = parseInt("<%=gvTest.Rows.Count%>");
Secondly, if you have runat="server" on the checkbox in the header, you may need to change this line if your JSFunction:
var mainChkBox = document.getElementById("<%=chkBoxAll.UniqueID%>");
Related
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.
I usually deal with Repeater to generate tables in my asp.net pages, but now I need to handle dynamic columns in my table, so I wonder if there is a common approach to solve this issue using web controls.
I've never used GridView, so I don't know if this is better to render tables with dynamic columns? Can you suggest me wich is the more appropriate approach? Is there a way to achieve this using Repeater?
You could a GridView with AutoGenerateColumns set to true. It would inspect and add the columns in your DataSource
<asp:sqldatasource id="CustomersSource"
selectcommand="SELECT CustomerID, CompanyName, FirstName, LastName FROM SalesLT.Customer"
connectionstring="<%$ ConnectionStrings:AWLTConnectionString %>"
runat="server"/>
<asp:gridview id="CustomersGridView"
datasourceid="CustomersSource"
autogeneratecolumns="True"
emptydatatext="No data available."
allowpaging="True"
runat="server" DataKeyNames="CustomerID">
</asp:gridview>
It is very important to know how you want to handle the situation.
Situation 1:
You have an existing table and from time to time you add columns (which is not very practical though) you can straight away go for the GridView and set the AutoGenerateColumns binding property to true.
Situation 2
You can create your own HTmlHelper Class for handling the tables.
For this you can visit the following post:
How to create MVC HtmlHelper table from list of objects
if you are using MVC.
Here's a quick hack to do this if you must use Repeater:
In the .aspx:
<asp:Repeater ID='rptr' runat='server'>
<HeaderTemplate>
<table>
<thead>
<tr>
<th>
Always visible header col
</th>
<th id='thHidable' runat='server' class='hideable'>
Hideable header col
</th>
</tr>
</thead>
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
Repeated col
</td>
<td id='tdHideable' runat='server' class='hideable'>
Hideable repeated col
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</tbody></table>
</FooterTemplate>
</asp:Repeater>
In the code behind (assuming C# used):
protected override void Page_Init()
{
this.rptr.ItemDataBound += new RepeaterItemEventHandler(rptr_ItemDataBound);
}
void rptr_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
RepeaterItem item = (RepeaterItem)e.Item;
if (item.ItemType == ListItemType.Header)
{
HtmlTableCell thHidable = (HtmlTableCell)item.FindControl("thHidable");
if (hideCondition)
{
// thHidable.Visible = false; // do not render, not usable by client script (use this approach to prevent data from being sent to client)
thHidable.Style["display"] = "none"; // rendered hidden, can be dynamically shown/hidden by client script
}
}
else if (item.ItemType == ListItemType.Item || item.ItemType == ListItemType.AlternatingItem)
{
HtmlTableCell tdHideable = (HtmlTableCell)item.FindControl("tdHideable");
if (hideCondition)
{
// tdHideable.Visible = false; // do not render, not usable by client script (use this approach to prevent data from being sent to client)
tdHideable.Style["display"] = "none"; // rendered hidden, can be dynamically shown/hidden by client script
}
}
}
(optional) If you want to dynamically show column on client side (assuming it was rendered), using jQuery (for brevity):
$(".hideable").show();
I'd like to have the user click the select button of, lets say, the 250th row of a 400 row gridview. When they click that, then another gridview that's 3x12 appears below that row, then the 150 other rows appear below that. Is this at all possible? I guess I could create a whole other div that'll have three gridviews that output depending on being <= and > the index of the selected row.
It starts as:
Gridview rows 1-400
Then after row 350 is selected is it:
Gridview rows 1-350
Gridview of row 350 info
Gridview rows 351-400.
It's definitely possible, but I would use a ListView or DataList as your parent container instead, because with a GridView, you'll have to put the child list in a column, which will look ugly. This should put you on the right path:
<asp:ListView ID="lstOuterList" runat="server" DataKeyNames="ID, OtherColumn">
<LayoutTemplate>
<table width="100%">
<asp:PlaceHolder runat="server" ID="itemPlaceHolder" />
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><asp:LinkButton ID="LinkButton1" runat="server" Text="Expand" OnCommand="LinkButton1_Command" CommandArgument='<%#Container.DisplayItemIndex%>'></asp:LinkButton></td>
<td><%#Eval("Value")%></td>
<td><%#Eval("OtherValue")%></td>
<td><%#Eval("OtherOtherValue")%></td>
</tr>
<asp:PlaceHolder ID="plcInnerList" runat="server">
<asp:ListView ID="lstInnerList" runat="server" Width="100%">
<LayoutTemplate>
<tr>
<td colspan="4">
<div style="padding:20px;background-color:#fffeee;">
<table width="100%">
<asp:PlaceHolder runat="server" ID="itemPlaceHolder" />
</table>
</div>
</td>
</tr>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><%#Eval("Value")%></td>
<td><%#Eval("OtherValue")%></td>
<td><%#Eval("OtherOtherValue")%></td>
</tr>
</ItemTemplate>
</asp:ListView>
</asp:PlaceHolder>
</ItemTemplate>
</asp:ListView>
And when the user clicks the LinkButton/Button in DataList1, do something like this:
protected void LinkButton1_Command(object sender, CommandEventArgs e)
{
//pass index of item in command argument
var itemIndex = Convert.ToInt32(e.CommandArgument);
//find the pnlChildView control
var innerPlaceHolder = lstOuterList.Items[itemIndex].FindControl("plcInnerList") as PlaceHolder;
if (innerPlaceHolder != null)
{
innerPlaceHolder.Visible = !innerPlaceHolder.Visible;
if (innerPlaceholder.Visible)
{
var innerList = innerPlaceHolder.FindControl("lstInnerList") as ListView;
if (innerList != null)
{
//the id to retrieve data for the inner list
int keyValue = (int)lstOuterList.DataKeys[itemIndex]["ID"];
//bind the list using DataList1 data key value
innerList.DataSource = new DataTable("DataSource"); //your datasource
innerList.DataBind();
}
}
}
}
one way is:
on the rowcommand of the main grid:
create c# code for the grid will be inside GridView grd = new GridView();
bind this instance like any other grid
add on the controls from the main grid current line, should be something like
e.Cells[0].Controls.Add(grd);
I don't have VS here right now but I guess you could get the idea, I use this approach all the time
i have a gridview which has a checkbox column. The header is of this column is a checkbox.
When it is checked all the values get checked and vice-verse.
I do this using javascript.
The problem is if i check it and perform any other event on the page which requires a postback the checked values disappear. I dont want them to disappear.
here is my code:
<script type="text/javascript">
function checkAllBoxes() {
//get total number of rows in the gridview and do whatever
//you want with it..just grabbing it just cause
var totalChkBoxes = parseInt('<%= GridView1.Rows.Count %>');
var gvControl = document.getElementById('<%= GridView1.ClientID %>');
//this is the checkbox in the item template...this has to be the same name as the ID of it
var gvChkBoxControl = "Select_CheckBox";
//this is the checkbox in the header template
var mainChkBox = document.getElementById("chkBoxAll");
//get an array of input types in the gridview
var inputTypes = gvControl.getElementsByTagName("input");
for (var i = 0; i < inputTypes.length; i++) {
//if the input type is a checkbox and the id of it is what we set above
//then check or uncheck according to the main checkbox in the header template
if (inputTypes[i].type == 'checkbox' && inputTypes[i].id.indexOf(gvChkBoxControl, 0) >= 0)
inputTypes[i].checked = mainChkBox.checked;
}
}
</script>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<input id="chkBoxAll" type="checkbox" onclick="checkAllBoxes()"/>
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox ID="Select_CheckBox" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<!-- The rest of your rows here -->
</Columns>
</asp:GridView>
Thanks for the help.
Make your checkbox a server-side control that uses the view state by adding runat="server". It will then maintain its value across post backs.
<input id="chkBoxAll" type="checkbox" onclick="checkAllBoxes()" runat="server"/>
And change your JavaScript to select the id that ends in chkBoxAll. I use jQuery in the example below:
//this is the checkbox in the header template
var mainChkBox = $('input[id$="chkBoxAll"]');
However, if you sort your gridview rows or use paging, you will likely come across less friendly behavior.
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.