views:

506

answers:

6

I've been doing C# for years but ASP.NET for not so long and this has me stumped.

In my troubleshooting example I have a dropdownlist in an ASP.NET page, it has four items in it, I have a serverside event that fires on selectedindexchanged, it all works great in this scenario.

However, if (as i have in my evolved code) I set a Javascript handler for the "onchange" event, (which launches an alert) the alert works fine, but the server side event no longer fires... I'm sure I'm missing something obvious.

Important notes: Autopostback is set to true on the dropdownlist control, viewstate is enabled, the Javascript event handler returns true

Anyone?

It's not that I have to manually wire up the __doPostBack is it?

Any help greatly appreciated.

A: 

It sounds to me like you have two simultaneous asynch postbacks happening at the same time and by default, the most recent postback, takes precedence, which you have to change. You can force the postbacks to each finish before allowing the next one to proceed with scripting found here

Or you could handle the alert serverside in your onselectedindex changed event, with something like:

    ScriptManager.RegisterClientScriptBlock(Page, Page.GetType(), 
Guid.NewGuid().ToString(),"alert('Person was added 
successfully.');location.replace('people.aspx');",true);
GregD
A: 

If your Javascript event handler cancels the event bubbling, the event handler inserted by asp.net that calls your serverside code will not run.

I'm not familiar with asp.net auto-inserted-things, and you haven't posted the code for your event handler, so I cannot tell you exacly how to fix the problem. My recommendation is to use jQuery to attach your event handler, and not to return false or cancel the event bubbling in a more verbose way.

svinto
A: 

ok here is the code first the codebehind

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text;

namespace TestEvents
{
public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected override void OnPreRender(EventArgs e)
    {

        ClientScriptManager csm = Page.ClientScript;
        if (!csm.IsClientScriptBlockRegistered("NotesChangeScript"))
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("\r\n <script type=\"text/javascript\"> \r\n");
            sb.Append(" //<![CDATA[ \r\n");
            sb.Append(" var changesCount = 0; \r\n");

            sb.Append(" function selection_handler()\r\n");
            sb.Append("{ \r\n");
            sb.Append(" changesCount += 1;\r\n");
            sb.Append(" alert('i changed on the client!'); \r\n");
            sb.Append(" return true; \r\n");
            sb.Append(" } \r\n");

            sb.Append(" function SetUpNotesHandler() \r\n");
            sb.Append("{ \r\n");
            sb.Append("          var ctrls = document.getElementsByTagName(\"SELECT\");\r\n");
            sb.Append("          for(i=0;i<ctrls.length;i++)\r\n");
            sb.Append("                  {\r\n");
            sb.Append("                     ctrls[i].onchange = selection_handler; \r\n");
            sb.Append("                 }\r\n");
            sb.Append("}\r\n");


            sb.Append(" //]]> \r\n");
            sb.Append("</script>");

            csm.RegisterClientScriptBlock(this.GetType(), "NotesChangeScript", sb.ToString(), false);

            StringBuilder initScript = new StringBuilder();
            initScript.Append("<script type=\"text/javascript\" >\r\n");
            initScript.Append(" //<![CDATA[\r\n");
            initScript.Append("  SetUpNotesHandler(); \r\n");
            initScript.Append(" //]]> \r\n");
            initScript.Append("</script> \r\n");
            csm.RegisterStartupScript(this.GetType(), "StartUpKey", initScript.ToString(),false);
            base.OnPreRender(e);
        }

    }
    protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
    {
        Response.Write("i hit the server event");
    }
}

}

and here is the markup for the page

<%@ Page Language="C#" AutoEventWireup="true"     CodeBehind="Default.aspx.cs"    Inherits="TestEvents._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>problem</title>
</head>
<body>
<form id="form1" runat="server">
<div>
    <asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged">
        <asp:ListItem>Numero Uno</asp:ListItem>
        <asp:ListItem>Numer Deux</asp:ListItem>
        <asp:ListItem>Number Three</asp:ListItem>
        <asp:ListItem>Nomina Quatros</asp:ListItem>
    </asp:DropDownList>
    <asp:HiddenField ID="hdnFieldChange" runat="server" />
</div>
</form>
</body>
</html>

thanks for looking

Matt
A: 

Assign your script to onchange event like that :

DropDownList1.Attributes["onchange"] += "alert('alert');";

do not use return true; after alert.

EDIT :

problem is in here, you disabling postback script by assigning your script over it, so postback script is not working because it's not exist anymore :

sb.Append("                     ctrls[i].onchange += selection_handler; \r\n");

hope this helps !

Canavar
could you explain why things arent working in my case ?
Matt
is there a way to add the event on the client side without overwriting the postback script?
Matt
you're assigning a function to onchange event, and the postback reference is replaced by your code, just do a string concatenation at the related line.
Canavar
hmm, i tried that with my code and it didnt work ...
Matt
I see, in javascript I don't know how to do this. but you can do it in server side by this way : DropDownList1.Attributes["onchange"] += "selection_handler();";
Canavar
ok, thanks for your help :)
Matt
your welcome, if you find how we add event reference, please post here :)
Canavar
A: 

ok, firstly, thanks to ScarletGarden for making it clear what the problem was, i had assumed as much but its nice when someone confirms your suspicions.

Secondly, apologies to those who see this as some sort of n00b question and find the whole premise of this question stupid, i really couldnt find any articles clarifying this specific problem...

Thirdly, i have now worked out how to do this in Javascript (although scarlet gardens solution is a lot simpler in pretty much every case) although the attributes.add approach (as scarletGarden suggested) may suffer if you had multiple handlers and needed them to fire in some sort of sequence.

Having had a little dig in reflector, Attributes.Add adds event references by semi colon separating them, so this clearly works as it preserves any handlers that are already declared and semi-colon separates the one(s) you add.

In javascript this kind of chaining (multicasting of a sort) requires that DOM level 2 functionality is used (the javascript bible was useful for identifying this), it should be no surprise that Mozilla and IE have a different way of achieving the same thing and so, in order to add a js handler and preserve the event handling in codebehind, the line in my example above that says

ctrls[i].onchange = selection_handler; \r\n

needs to be replaced by the following (before people get precious about this example i do have a big caveat for this, further down)

sb.Append("                 if (ctrls[i].addEventListener) ctrls[i].addEventListener(\"change\",selection_handler,false);");
sb.Append("                 else if (ctrls[i].attachEvent) ctrls[i].attachEvent(\"on\" + \"change\", selection_handler, false);");
sb.Append("                 else return false;");

attachEvent works in IE, addEventListener in Firefox (note the different names for the events, Mozilla preferring to drop the "on"

Adding events like this works in a LIFO (last in First Out) manner, there are many alternatives to sequencing events in this manner using more elaborate javascript, covered in an excellent, if slightly confusing thread (because of the way it starts) here http://codingforums.com/showthread.php?t=154673

I hope this stuff enlightens others as much as me, this is the thread i was looking for when i first hit the problem and now i feel a bit stupid, but hey ho

Matt
A: 

Hi

I have the same issue with the Textbox OnChange Event. I have to validate the textbox content through javascript and then have to call the server side TextChanged eventhandler. I am adding the textbox dynamically in an update panel. Either the javascript event is fired. Please Help!!!!!!!!!

Farnena