use code behind to pop aspx confirmation message - c#

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.

Related

How to pass Event Validation when editing a select list from JavaScript

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>

Disable Button after Click whilst maintaining CausesValidation and an OnClick-Method

So I've got this button:
<asp:Button runat="server" ID="btnSubmit" meta:resourcekey="btnSubmit" CausesValidation="true" OnClick="btnSubmit_Click" />
meta:resourcekey is for Localization Resources, doesn't concern us here - as we can see it has got an OnClick-Method and causes Validation.
That works fine, too, but I'd like to disable that button after the user clicked it so he/she can't click it multiple times before the PostBack succeeds, so here's what I did in Page_Load:
btnSubmit.Attributes.Add("onclick", "this.disabled=true;" +
Page.ClientScript.GetPostBackEventReference(btnSubmit, "").ToString());
onclick I'm disabling the button and re-adding the PostBackReference necessary for the OnClick-Method.
Problem: CausesValidation is gone, sadface. How exactly would I re-add that in CodeBehind or alternatively - What's an entirely different solution to this?
My Button has to:
a) disable itself after clicking, yet be enabled after the postback
b) have an OnClick CodeBehind Method
c) cause Validation
Thanks,
Dennis
Just override the Onload event of ur page or master page with
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// prevents form from being submitted multiple times in MOST cases
// programatic client-side calls to __doPostBack() can bypass this
Page.ClientScript.RegisterOnSubmitStatement(GetType(), "ServerForm",
"if (this.submitted) return false; this.submitted = true; return true;");
}
Try the following in Page_Load
VB
Dim postBackOptions As PostBackOptions = New PostBackOptions(btnSubmit)
btnSubmit.OnClientClick = "this.disabled=true;"
btnSubmit.OnClientClick += ClientScript.GetPostBackEventReference(postBackOptionClaim)
C#
PostBackOptions postBackOptions = new PostBackOptions(btnSubmit);
btnSubmit.OnClientClick = "this.disabled=true;";
btnSubmit.OnClientClick += ClientScript.GetPostBackEventReference(postBackOptionClaim);
EDIT
if(Page_ClientValidate()) {this.visibility='hidden';}
If you need to have server side validation before you know whether to hide/disable the button or not you'll probably want to forgo the disabling of the button and just make sure your server-side code doesn't execute more than necessary if a user hammers on the button.
You could put a hidden field and generate a GUID for it in the page_load if(!IsPostBack) then on your btnSubmit_click do something like
if(Session[Page.ToString() + "_spam"] != null && Session[Page.ToString() + "_spam"] == hdnGuid.Value) {
return
} else {
Session[Page.ToString() + "_spam"] = hdnGuid.Value;
//do stuff
}

ASP.NET OnClick not firing in Repeater.ItemTemplate that has a custom control

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.

ASP, Listview conditional Alert

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);
}

Asp.Net ViewState lost with RegisterClientScriptBlock

I am validating a zip code using Javascript that is generated server-side, and injected when a LinkButton is clicked. Then, I retrieve the return value by calling a server-side function when the page loads.
This works nicely, but the problem is that the ViewState is completely lost after PostBack. Below is the code, starting with the page_load event, the button click event, and then the callback called from the page_load event.
Is there a way I can somehow save the ViewState, maybe easily in a session variable? Or is there a workaround I can use?
// In Page_Load
if (Request.Form["__EVENTTARGET"] == "CallFunction") {
GetValidateZipCodeScriptReturnValue(Boolean.Parse(Request.Form["__EVENTARGUMENT"].ToString()));
}
// OnClick for LinkButton
private bool ValidateZipCode(string zip) {
StringBuilder script = new StringBuilder();
script.Append("<script language='javascript' type='text/javascript'>");
script.Append(#"var regex = /^\d{5}$|^\d{5}-\d{4}$/;");
script.Append("__doPostBack('CallFunction', regex.test(" + zip + "));");
script.Append("</script>");
Type t = GetType();
if (!ClientScript.IsClientScriptBlockRegistered(t, "ValidateZipCodeScript")) {
ClientScript.RegisterClientScriptBlock(t, "ValidateZipCodeScript", script.ToString());
}
return false;
}
// Method called on PostBack to get the return value of the javascript
private void GetValidateZipCodeScriptReturnValue(bool valid) {
m_ZipCode = uxZip.Text;
if (valid) {
Response.Redirect(string.Format("~/checkout/overview.aspx?pc={0}&zc={1}",
ProductCode, ZipCode));
}
else {
Alert.Show("The entered zip code is invalid. Please ensure the zip code is a valid zip code.");
SetupPostBackViewState();
ScrollToZipCode();
}
}
Why not just use the OnClick event of the LinkButton? Or, better yet, look into the CustomValidator control, since it looks like all you're trying to do is validate a zip code and that's exactly what a CustomValidator can do (you'll need to look at the ClientValidationFunction, which is where you want to put your regex test).

Categories