Wednesday, July 20, 2011

Force an ASP.NET ImageButton to only call server side code when your Javascript determines it is necessary.

Have you ever needed the ability for an ImageButton to act as an <input type="Image" /> with the javascript most of the time, but under certain conditions fire a server-side event? Well before you start writing custom postback code and putting it into your javascript, consider this.

If you have an OnClientClick --or onclick on the html rendering-- specified for the <asp:ImageButton> element as well as an OnClick event handler, the server-side handler will only be called if your javascript method returns true or void. If you have your OnClientClick handler return false, the server-side event will not be called. This will allow you the ability to make your ImageButton behave client-side until you decide it is necessary to do other wise.

For example:


<div style="float: left; text-align: center;">
                        <h4>Visitor Stations</h4>
                        <asp:DataList ID="dlVisitorStations" runat="server" RepeatColumns="6" CellSpacing="5"
                              OnSelectedIndexChanged="dlvisitorStations_SelectedIndexChanged"
                              DataKeyField="StationID" OnItemDataBound="dlVisitorStations_ItemDataBound" RepeatDirection="Horizontal">
                          <ItemTemplate>                  
                               <asp:ImageButton ID="btnVisitorStation" runat="server" ImageUrl="~/images/status/available.png" OnClick="btnVisitorStation_click" /><br />
                                <asp:Label ID="lblStationID" runat="server" Text='<%# Eval("StationID") %>' ></asp:Label><br />
                                <asp:Label ID="lblStationName" runat="server" Text='<%# Eval("StationName") %>' ></asp:Label><br />
                               <asp:Image ID="imgConnectArrow" Visible="false" ImageUrl="~/Images/greenConnectionArrow.gif"
                                 Width="40px" runat="server" />
                                <asp:Label ID="lblInmateStation" Text='<%# Eval("ConnectedStation") %>' Visible="false" runat="server"></asp:Label>
                           </ItemTemplate>
                           <ItemStyle Width="75px"/>                                                  
                         </asp:DataList>
                    </div>


Pretty self explanatory here. We have a DataList that has an ImageButton inside it amongst other things. Also notice that I have a server-side handler specified.

Here it is in the code-behind:

         //This event handler will only be called if the button is in the connected or paused state.
        //see the javascript btnVisitorStationClick for more information
        protected void btnVisitorStation_click(object sender, ImageClickEventArgs e)
        {
            //irrelevant to post. This code gets called.
        }

Also in the ItemDatabound I do this:

          Image btnVisitorStation = (Image)e.Item.FindControl("btnVisitorStation");
           
             btnVisitorStation.Attributes.Add("onclick", String.Format("return btnVisitorStationClick('{0}', '{1}')",   DataBinder.Eval(e.Item.DataItem, "StationID").ToString(), btnVisitorStation.ClientID));





Notice, that you could also use the OnClientClick, if you don't need to worry with the databinding. Also, see that there is a return statement in the newly generated onclick javascript handler. This is what will do the magic.

Ok, here is the javascript:

      function btnVisitorStationClick(stationID, img) {
           var imgStation = document.getElementById(img);
           var hfVisitorStation = document.getElementById('<%= hfSelectedVisitorStation.ClientID %>');
           var inmateStation = document.getElementById('<%= hfSelectedInmateStation.ClientID %>').value;
           var hfVisitorButton = document.getElementById('<%= hfSelectedVisitorButton.ClientID %>');

           if (imgStation.src.indexOf('offline') == -1 && imgStation.src.indexOf('connected') == -1 && imgStation.src.indexOf('paused') == -1) {
               imgStation.src = 'images/status/selected.png';

               if (hfVisitorStation.value != '') {
                   var stationToDeselect = document.getElementById(hfVisitorButton.value);
                   stationToDeselect.src = 'images/status/available.png';
               }

               if (hfVisitorStation.value != stationID)
                   hfVisitorStation.value = stationID;

               else
                   hfVisitorStation.value = '';

               hfVisitorButton.value = imgStation.id;

               var monitorBtn = document.getElementById('btnMonitor');
               var startButton = document.getElementById('<%= btnRestart.ClientID %>');

               if (inmateStation != '' && hfVisitorStation.value != '') {
                   monitorBtn.src = 'images/controls/monitor.png';
                   startButton.src = 'images/controls/play.png';
                   monitorBtn.disabled = false;
                   startButton.disabled = false;
               }
               else {
                   monitorBtn.src = 'images/controls/monitor_disabled.png';
                   startButton.src = 'images/controls/play_disabled.png';
                   monitorBtn.disabled = true;
                   startButton.disabled = true;
               }

               return false;
           }

           else if (imgStation.src.indexOf('connected') != -1 || imgStation.src.indexOf('paused') != -1) {
              return true;
           }

           return false;
       }


As you can see, most of this code doesn't need a post-back. However, I needed to call a postback if the status of the button was connected or paused, though most of the time it just needed to process client-side.

Happy coding.

No comments:

Post a Comment