I'm currently working with a listview in which I want an htmltablecell to possess the onclick property which is driven by the codebehind rather than a javascript.. However I'm guessing that's pretty much a dream getting it to obey the C# code... Anyways this is what I want it to run:
protected void show_anm(object sender, EventArgs e)
{
Label hiddenc = (Label)listview1.FindControl("hidden");
Alert.Show(hiddenc.Text);
}
and here's the Alert class
public static class Alert
{
public static void Show(string message)
{
string cleanMessage = message.Replace("'", "\\'");
string script = "<script type=\"text/javascript\">alert('" + cleanMessage + "');</script>";
Page page = HttpContext.Current.CurrentHandler as Page;
if (page != null && !page.ClientScript.IsClientScriptBlockRegistered("alert"))
{
page.ClientScript.RegisterClientScriptBlock(typeof(Alert), "alert", script);
}
}
}
The point is creating a listview with a two conditional tablecells, one which appears only when a certain condition is met and the other appears every other time (that's alredy sorted out). Where the one demanding a condition is Clickable, and upon clicking it it'll display an Alertbox with Data from a specific DB cell...
Sorry if my language and the question seemes off, English isn't my native language and I haven't doused myself in Coffe yet.
Any help on the matter would be most appritiated
EDIT1*
<asp:Listview ................
<ItemTemplate>
<tr ......>
<td id=default .....>
<asp:label ........ Text='<%# eval("stuff") %> />
</td>
<td id=conditional onclick=alert()..........>
<asp:label ......... Text='<%# eval("stuff") %> />
</td>
<td id=hidden visible=false ...........>
<asp:label ......... Text='<%#eval("stuff i want in alert") %>' />
.....
<script tyupe="text/javascript">
function alert()
{
var msg = document.getElementById("tried with label id and tablecell id nothing seemingly worked").value;
alert(msg);
}
</script>
I recently made a workaround that shows the data I want to display in the labels tooltip but I'd still prefer the alertbox to work properly as it feels more natural to click something.
Edit2 In case anyone is wondering I used the ItemDataBound event to bind the visibility of cells default and conditional within an if clause to make sure the control exists and the conditions are met.
I am confused as to why you're doing what you're doing. Why do you want the codebehind to handle an onclick event of a htmltablecell when you are pumping out javascript to show an alert anyway?
Why not just handle the whole logic within Javascript?
A postback from a htmltablcell will also require javascript
Set your tablecell to call a javascript function which would obtain the alert text from the hidden value and display that;
function ShowAlert()
{
var message = document.getElementbyId("hidden").value;
alert.show(message);
}
Related
I have two select lists in my ASP.NET site that are filled by the server with some elements.
// .aspx
<asp:dropdownlist id="abc" runat="server"></asp:dropdownlist>
<asp:dropdownlist id="def" runat="server"></asp:dropdownlist>
// .aspx.cs
abc.Items.Add(new ListItem("element1", "value1"));
def.Items.Add(new ListItem("element1", "value1"));
Due to too complicated reasons to explain right now, I also need to modify the options of the select lists with JavaScript, adding some values.
// In the <head> of the .aspx page
var abcList = document.getElementById("abc");
var defList = document.getElementById("def");
var newAbcElement = new Option("element2", "value2", false, false);
var newDefElement = new Option("element2", "value2", false, false);
abcList.options[abcList.length] = newAbcElement;
defList.options[defList.length] = newDefElement;
Of course, this will mess up Even Validation as soon as I send the form back to the server (be it by submitting or as a PostBack from some other form elements with AutoPostBack="true").
Invalid postback or callback argument. Event validation is enabled using in configuration or <%# Page EnableEventValidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.
Now, I don't have the resources and budget to completely overhaul the whole page design, so: What is the fastest and easiest way to change the dropdownlist that does not mean I have to rewrite the whole thing?
So that the values added via JavaScript are recognized by my CodeBehind file when submitting the form?
Ok, here is one more option for you. You can add those items to your lists using AsyncPostBackTrigger.
Some hidden fields:
<asp:TextBox ID="newItemsForAbc" runat="server" style="display:none;"></asp:TextBox>
<asp:TextBox ID="newItemsForDef" runat="server" style="display:none;"></asp:TextBox>
<asp:Button ID="addNewItems" runat="server" OnClick="addNewItems_Click"
style="display:none;" />
The Update Panel:
<asp:UpdatePanel runat="server" ID="UpdatePanel" UpdateMode="Conditional">
<ContentTemplate>
<asp:dropdownlist id="abc" runat="server"></asp:dropdownlist>
<asp:dropdownlist id="def" runat="server"></asp:dropdownlist>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="addNewItems" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
JS Function for doing an async post back:
<script type="text/javascript"> function UpdateStuff(value1, value2)
{
var abcItems = document.getElementById("<%= newItemsForAbc.ClientID %>");
var defItems = document.getElementById("<%= newItemsForDef.ClientID %>");
abcItems.value=value1;
defItems.value=value2;
__doPostBack("<%= addNewItems.ClientID %>","");
}
</script>
Server-side function that handles button click:
protected void addNewItems_Click(object sender, EventArgs e)
{
string[] n1 = newItemsForAbc.Text.Split(';');
string[] n2 = newItemsForDef.Text.Split(';');
foreach(string i in n1)
{
abc.Items.Add(new ListItem(i, i));
}
foreach(string i in n2)
{
def.Items.Add(new ListItem(i,i));
}
}
To Update Your Lists:
var newAbcElements = "Element1;Element2;Element3";
var newDefElements = "Element4;Element5";
UpdateStuff(newAbcElements, newDefElements);
Final note:
This piece of code probably will not do the job for you as it is. You may need to change the way you store new items in a string, thus splitting/parsing would change too. You may even need different strings for displaying a list item and its actual value. But I believe you get the basic idea.
You can disable the ViewState entirely for the DropDownList.
<asp:dropdownlist id="abc" runat="server" EnableViewState="false"></asp:dropdownlist>
To your question update:
This changes the question quite a lot. The new question is answered here: Invalid postback or callback argument. Event validation is enabled using '<pages enableEventValidation="true"/>'
You have a few options.
First, you might rewrite your code so that the server side generates all possible items for the DropDownList and then in your JavaScript remove the unneeded items instead of adding new ones.
Second option is to create a custom class derived from System.Web.UI.WebControls.DropDownList. The class should contain the one method shown below. The important piece is that your custom class will not have the System.Web.UI.SupportsEventValidationAttribute added to it - so DropDownList base methods will skip the event validation automatically. Now replace the usage from <asp:dropdownlist> to your method.
In case you can't modify the .aspx code (or you have a ton of dropdownlists to replace) you might use tag mapping in your configuration.
namespace Project.MyWebControls
{
public class MyDropDownList : System.Web.UI.WebControls.DropDownList
{
protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
if (base.LoadPostData(postDataKey, postCollection))
return true;
// this means that the value selected was not present in the .Items collection
string[] values = postCollection.GetValues(postDataKey);
if (values == null || values.Length == 0)
return false;
// add the value to the Items collection so that it can be processed later on.
this.Items.Add(new ListItem("Custom value created by JavaScript", values[0]));
this.SetPostDataSelection(this.Items.Count - 1);
}
}
}
Note that depending on your code you might want to remove these custom values from the Items collection before rendering.
Sample for the .aspx file:
<%# Register TagPrefix="my" Namespace="Project.MyWebControls" Assembly="Project" %>
<my:MyDropDownList runat="server" ...></my:MyDropDownList>
I m using two list items with link. Now I want to check which link was clicked from the client side. Here is my code:
<ul id="navtabs">
<li id="basic" runat="server" class="cat-item cat-item-6 current-cat">new</li>
<li id="new" runat="server" class="cat-item cat-item-8">old</li>
</ul>
I want to check which item am click whether basic or new
if(this.basic.clicked ==true)
{
do something
}
else
{
do something
}
How can I do this?
If you are suing Web forms then,
The the control which are suing must be server control
If it is a link the put runat="server" and id of the control
Create on click event of every link.
But what is the purpose of those link is not clear.
What action do you want to take on the click must be clear.
I have a trick for it. You can do this with help of jQuery, one hidden field & one hidden asp button.
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Hidden Button" />
<asp:HiddenField ID="hdnLIClicked" runat="server" />
Now jQuery part, in ready event
$().ready(function() {
$("#Button1").hide();//hiding the button through jQuery
$("#basic").click(function(){
$("#hdnLIClicked").val("basic");
$("#Button1").click();
});
$("#new").click(function(){
$("#hdnLIClicked").val("new");
$("#Button1").click();
});
});
Or you can give a common class to all your list items, if there are more list items, like you already have a common class for both of your list items. i.e "cat-item".
$().ready(function() {
$("#Button1").hide();//hiding the button through jQuery
$(".cat-item").click(function(){
$("#hdnLIClicked").val($(this).attr("id"));
$("#Button1").click();//this will fire the hidden button event on server side.
});
});
And you'll have which 'li' was clicked in the hiddenfield.
On backend, handle the button click event like this.
protected void Button1_Click(object sender, EventArgs e)
{
if (hdnLIClicked.Value == "basic")
{
//handle your logic for basic here...
}
else if (hdnLIClicked.Value == "new")
{
//handle your logic for new here...
}
}
Hide the button through jQuery, don't set its property Visible="false", or the button won't get rendered on client side.
Enjoy ;)...
I need to return a confirmation message to OnClientClick event. The problem is I have to get the message from stored procedure, and I don't seem to call my function right.
<asp:ImageButton
OnClientClick="return confirm(<%# GetConfirmExportMessage()%>);"
OnClick="btnExportRed_Click"
runat="server"
ImageUrl="~/Images/excel_red.gif"
ID="btnExportRed"
AlternateText="Export all records!"/>
My code behind:
public string GetConfirmExportMessage()
{
string xmlFilterForExport = Parameters.ToString().Split('+')[4].Trim();
string alertMessage = companiesSearcher.GetAlertMessage(xmlFilterForExport, 1, null, null, IdSegment, 1, Convert.ToInt32(RoDB2004.BLL.clsUsers.UserID));
return alertMessage;
}
Try using equal sign instead of pound (and don't forget your single quotes).
OnClientClick="return confirm('<%= GetConfirmExportMessage()%>');"
However, if you're ImageButton is located inside a DataGrid or GridView, the server-side code will not be evaluated and will yeield an alert saying <%= GetConfirmExportMessage()%> instead of the real message.
To get around this problem (and to increase performance, throughput, etc.), output your message once to a variable, then alert the contents of the variable.
<script language="JavaScript">
var myMessage = '<%= GetConfirmExportMessage()%>';
</script>
Later, in the GridView...
OnClientClick="return confirm(myMessage);"
You save throughput by repeating a small variable name like "myMessage" and avoid repeating some big message. Also note, that the method GetConfirmExportMessage isn't called dozens of times increasing performance.
If your message is specific to data within a current row and not static like "Are you sure?", then I suggest you perform this operation inside the GridView's RowDataBound event. You'll have full access to the ImageButton and to the data the current row is binding to, which makes it very easy to setup server-side. Check out the FindControl() method, or if you know the exact location, just reference it and unbox the object.
protected void gvMyGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
ImageButton ibtn = (ImageButton)e.Row.FindControl("btnExportRed");
if(ibtn != null)
{
ibtn.ClientClick = "return confirm('" + GetConfirmExportMessage() + "');";
}
}
}
As an alternative solution, maybe you should look into WebMethods, AJAX and jQuery. This solution is probably the better one because the data is not sent to the client and only retrieved when necessary.
you need to wrap your confirm in '
<asp:ImageButton
OnClientClick="return confirm('<%# GetConfirmExportMessage()%>');"
OnClick="btnExportRed_Click"
runat="server"
ImageUrl="~/Images/excel_red.gif"
ID="btnExportRed"
AlternateText="Export all records!"/>
You probably want
OnClientClick="return confirm('<%= GetConfirmExportMessage()%>');"
Note that this will be populated when the page is rendered, not when the button is clicked, so you may as well use
btnExportRed.OnClientClick = "javascript:return confirm('" + GetConfirmExportMessage() + "');"
in your code behind.
So I have a user control that displays links and I want to change the color of the link that is currently active.
This is the code inside my ListView of my usercontrol ascx file.
<asp:ListView ID="sidebarListView" runat="server" DataKeyNames="Id" DataSourceID="SqlDataSourceSidebar" OnItemCommand="sidebarListView_ItemCommand">
<ItemTemplate>
<div id="sidebarItemID" class="sidebarItem" runat="server">
<div>
<asp:LinkButton ID="NameLabel" runat="server" Text='<%# Eval("Name") %>' CommandName="Select" CommandArgument='<%# Eval("Id") %>' />
</div>
</div>
</ItemTemplate>
....
I need to change the sidebarItemID class when the linkbutton is clicked.
My default.aspx code behind looks like this:
private void SideBar1_ItemCommand ( object sender , EventArgs e ) {
Int32 facId = Sidebar1.FacultyId;
SqlDataSource1.SelectCommand = "SELECT [Id], [Name], [Faculty_Id], [User_Id], [Author], [Picture], [Location] FROM [Books] WHERE [Faculty_Id]=" + facId + " ORDER BY [DateAdded] DESC";
HtmlGenericControl htmlDivControl = (HtmlGenericControl) FindControlRecursive( Sidebar1 , "sidebarItemID" );
htmlDivControl.Attributes.Add("class", "sidebarItemActive");
string newClass = htmlDivControl.Attributes["class"];
//Response.Write( String.Format( "<script>alert('{0}');</script>" , newClass ) );
}
This correctly changes the sqlDataSource based on the ID of the link clicked in the user control. However the class doesn't change.
If I uncomment the Response.Write(...) section it correctly gives an alert that says "sidebarItemActive" so it correctly finds the control from my page and assigns its class attribute as "sidebarItemActive" but nothing changes on the page if I view the page source in the browser it says the class is still "sidebarItem".
What is going on here that the change does not come into effect?
The actual <div>s on your page are generated during the Render state of the ASP.NET Page Life Cycle. This happens after the Control event handling stage, thus any changes you make to the HTML during your handler function are effectively undone during Render, as the control's HTML is regenerated from the template. To have the control change its internal HTML in this case, you may put your update code in an overridden Render function for your control. The MSDN has an example of how to write the render function.
So I solved the problem by defining the ListViews ItemDataBound event handler and assigning the css class in there. The problem previously was, that since my controls were inside updatePanels the ItemDataBound event was not firing. I had to manually call "DataBind()" inside the click method.
Inside my default.aspx
// Exposed click event, updates RecentBooks control sqlDataSource.
private void SidebarItems1_Clicked ( object sender , EventArgs e ) {
RecentBooks1.updateDataSource( SidebarItems1.FacultyId.ToString() );
SidebarItems1.DataBind();
}
Inside my user control.ascx
protected void sidebarListView_ItemDataBound ( object sender , ListViewItemEventArgs e ) {
LinkButton button = e.Item.FindControl( "NameLabel" ) as LinkButton;
if (FacultyName != null && button != null) {
if ( button.Text == FacultyName ) {
button.CssClass = "sidebarItemActive";
}
}
Title is a bit of a mouthful, but I'm a bit stuck on this issue.
I have a search result page with has a custom control that has a Repeater. The ItemTemplate in the repeater is a PlaceHolder so I can construct the Item in a particular format; more specifically, I have a string of 'diseases' that come in the form of Disease1|disease2|disease3 and need to be given links for each disease.
Now for some code:
The following is the SearchResultControl.ascx
<asp:Panel ID="SearchResultPanel" runat="server" ScrollBars="Auto">
<asp:Repeater ID="Repeater1" runat="server"
onitemcreated="Repeater1_ItemCreated"
onitemcommand="Repeater1_ItemCommand">
<ItemTemplate>
<asp:PlaceHolder ID="ItemTemplatePlaceHolder" runat="server">
</asp:PlaceHolder>
</ItemTemplate>
<SeparatorTemplate>
<tr>
<td colspan="6"><hr /></td>
</tr>
</SeparatorTemplate>
</asp:Repeater>
</asp:Panel>
The code behind: SearchResultControl.ascx.cs
protected void Repeater1_ItemCreated(object sender, RepeaterItemEventArgs e)
{
if (e.Item.DataItem != null)
{
PlaceHolder placeHolder = e.Item.FindControl("ItemTemplatePlaceHolder") as PlaceHolder;
Control searchResultItem = Page.LoadControl("SearchResultItem.ascx");
DataRow row = (e.Item.DataItem as DataRowView).Row;
if (row != null)
{
string diseaseState = row["DiseaseStates"] as string;
searchResultItem.GetType().GetProperty("DiseaseStates").SetValue(searchResultItem, diseaseState, null);
placeHolder.Controls.Add(searchResultItem);
}
}
}
(Full disclosure, I got this idea from this question)
The SetValue calls the DiseaseStates property in SearchResultItem which in turn calls the following method to build the links, set the text, and the events:
private void BuildDiseaseStateLabels(string diseaseStates)
{
PlaceHolder placeHolder = FindControl("DiseaseStatePlaceHolder") as PlaceHolder;
string[] diseaseStateSplit = diseaseStates.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
int count = diseaseStateSplit.Length;
foreach (string diseaseState in diseaseStateSplit)
{
LinkButton diseaseStateLink = new LinkButton();
diseaseStateLink.Text = diseaseState;
//diseaseStateLink.Click += new EventHandler(OnDiseaseStateLinkClick);
diseaseStateLink.CommandArgument = "<%# Eval(\"PatientID\")+ \";\" + Eval(\"PatientStatus\")+ \";\" + Eval(\"Age\")+ \";\" + Eval(\"DiseaseStates\")%>";
diseaseStateLink.CommandName = "OnDiseaseStateLinkClick";
//diseaseStateLink.Command += new CommandEventHandler(OnDiseaseStateLinkClick);
placeHolder.Controls.Add(diseaseStateLink);
if (count != 0)
{
Label splitLabel = new Label();
splitLabel.Text = "|";
placeHolder.Controls.Add(splitLabel);
}
}
}
This is the layout for the SearchResultItem
<div id="SearchResultItemDiv" class="MainSearchResultItem">
<asp:PlaceHolder ID="DiseaseStatePlaceHolder" runat="server">
</asp:PlaceHolder>
</div>
Initially I tried setting the Click event, but that doesn't work at all. I then set the CommandArgument and CommandName but that didn't seem to do the trick. I figured the Command event might need to be set, but again, no luck. I should note that when a link is clicked the Repeater1_ItemCreated in SearchResultControl.ascx.cs is called. But since there is no data in e.Item.DataItem is null and I lose the results.
In one of the questions regarding the same issue, it was suggested that the OnItemCommand be added, but even that doesn't get called.
I also read A Stumper of an ASP.NET Question and A Stumper of an ASP.NET Question: SOLVED!, to no avail.
What could I possibly be doing wrong? All of the correct event hookups seem there, I'm checking for IsPostBack and not doing DataBind() again. blaaargharaggh
Help is always greatly appreciate.
I believe you're running into this issue because the LinkButton controls are recreated too late in the page lifecycle. You have to remember that when the page is posted back, the control technically does not exist anymore, so the event handler cannot be fired.
If you can recreate the LinkButton controls somewhere before the Page_Load event is reached, like OnInit for example, everything should work fine.
For simple pages the above usually works very well, but there are circumstances where recreating controls during OnInit requires a lot of overhead, such as storing counters or arrays in ViewState so you can keep track of the controls that need to be recreated after postback. In these situations I would suggest taking a look at the DynamicControlsPlaceHolder by Denis Bauer. This control is capable of persisting dynamic controls without any addtional code required, which is pretty awesome.
Here's a link to the latest version:
http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx
The problem might be that you're not doing the DataBind() again.
Because you're building the buttons on the fly, when the page post backs, the buttons haven't been created and are unable to work out which click event it should be firing.
Try getting rid of the IsPostBack check, so each time the page loads, you're re-build the repeater.