Thursday, August 18, 2011

Jquery calls to ASP.Net Methods in Code-Behind

Here’s our issue.  We want to spice up a menu control with JQuery that allows us to create a context menu (on right mouse click) that will take a menu item from the current menu and add it to a favorites menu.   The problem with that is the fact that JQuery runs on the client.  ASP.Net runs on the server.  So how are we going to get these two technologies to work together?
If you do some looking on the internet, most examples try to use AJAX coupled with a special function called a WebMethod.  Basically, a WebMethod is a really localized Web Service that you are serving from inside a page in your solution.  This will create a lot of overhead for the application, secondly it is possible to use the Web Method for malicious purposes and finally, I simply did not have a lot of luck getting this method to work consistently.
What I have found to work 100% of the time is to use the follow logic:
We’ll create a main menu and a favorites menu.
We’ll use the contextmenu plugin in Jquery to achieve the context menu effect we are looking for.
Upon selection of our Add Link context menu item, we’ll populate a hidden field on the form that utilizes View State.
Through the GetPostBackEventReference method of the Page.ClientScript object we’ll trigger a hidden button that gives us access to an event in ASP.Net which we can then process the request.
Sounds easy right?


The Setup:
So in order to use our logic we will need to setup the application to use JQuery.  You can download JQuery from http:// jquery.com.  You will want the minimized latest version.  The minimized means that it has been truncated (all ‘white spaces’ or unneeded characters have been reduced).  This effectively reduces the file size by half and makes the processing of the page quicker.  However, it is almost impossible to read.  Once you have downloaded JQuery we need to download the contextmenu Plugin.  You can find the plugin at http://abeautifulsite.net/blog/2008/09/jquery-context-menu-plugin/.  You will need both the .js files and the .css files.  This will be used for styling the look of our context menu.


Once you have the files downloaded, we need to reference them on the page that we are building.  To do this we will add the following code to the HEAD of our page (Typically right under the TITLE tag).
         <script src="js/jquery-1.6.2.min.js" 
type="text/javascript"></script>
         <script src="js/jquery.contextMenu.js" 
type="text/javascript"></script>
         <link href="jquery.contextMenu.css" 
rel="stylesheet" type="text/css" />
Now we have JQuery referenced so that our page knows how to use the code. 


The Code:
First we need to add the typical ASP.Net controls we wish to use.  This includes two menus and a ScriptManager.  JQuery does not require the ScriptManager in order to be executed, however if you use a ScriptManager, when you execute the code a single JavaScript file is sent to the client instead of multiple files, thus decreasing processing time (less trips to the file structure).  Together our code will look like:
<asp:Menu ID="menu" runat="Server" 
StaticDisplayLevels="1" ClientIDMode="Static"
            RenderingMode="List" Orientation="Horizontal" Width="630px">
            <DynamicMenuItemStyle BackColor="LightSkyBlue" 
ForeColor="Black" BorderStyle="Solid"
                BorderWidth="1" BorderColor="Black" />
        </asp:Menu>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>


This includes our Menu and ScriptManager.  Now we need a little help getting the value of the menuitem right-clicked into a field so that we can identify which item the user wants to send to their favorites.  Since I have written this method, ASP.Net 4.0 has been released thus deprecating the need for this method as you can directly manipulate the hidden field from JQuery by setting the ClientID to static of the hidden field.  This being said, I’m including the code as I wrote it as I know it to function correctly.
<script language="javascript" type="text/javascript">
            function UpdateValues(id) {
                $("*[id$='hdType']").val(id);
            }
        </script>
The * is a wildcard to find any objects on the page that end with hdType.  We are simply giving the hidden field a value of whatever is passed into the UpdateValues method. 
Next we need to create a hidden field and a hidden button on the form so that we can perform our postback and have access to our value:
         <asp:HiddenField ID="hdType" runat="server" EnableViewState="true" />
        <asp:Button runat="server" ID="btnEditFirm" 
OnClick="btnEditFirm_Click" Style="display: none" />
Finally, we need our JQuery method that will create the contextmenu and move the value to the hidden field and finally, mash the button so that it will trigger a postback and event.  The JQuery code will be the last code on the page before your page end tags (</div></form>….. etc…):
<script type="text/javascript">
            $(document).ready(function () {
                $("#menu UL LI a").contextMenu({
                    menu: 'myMenu'
                },
                                            function (action, el, pos) {
                                               UpdateValues($(el).text());
<%=Page.ClientScript.GetPostBackEventReference(new PostBackOptions(btnEditFirm))%>;
                                            });
            });                    
        </script>
IN THIS EXAMPLE IT IS EXTREMELY IMPORTANT FOR YOUR MENU TO BE OF TYPE LIST FOR THE RENDERINGMODE PROPERTY.
This determines how we get a handle on the element name to pass to the hidden field.  #menu UL LI a is the currently right clicked element and this is how we tell JQuery where we right clicked.  If this were a renderingmode=table then it would resemble something like #menu tr td a.  The menu: myMenu is the menu that we want to present as a context menu.  So we have to create a list of the menu items:
 <ul id="myMenu" class="contextMenu">
            <li class="add"><a href="#add">Add to MyLinks</a></li>
            
        </ul>
myMenu can exist right before the JQuery function.  It will not be seen on the page until we right mouse click the button.  You can additional options by adding more to the li class.  Finally, we have our trigger we just need to add our event to the code behind and then we are finished.
Private Sub EditFirm(ByVal ElementID As String)
        '… code to insert into SQL as a favorite ….
        
    End Sub


Now we will be able to successfully call code behind from a JQuery request.  Remember that this is a form postback and thus the page will be re-rendered as one.

*** UPDATE *** Apparently I missed a method from my original post.  If you notice in the btnEditFirm button there is an OnClick call.  I failed to add that method to this post.  This is that method:
Protected Sub btnEditFirm_Click(ByVal sender As ObjectByVal e As System.EventArgs)
        EditLink(hdType.Value, 1)
    End Sub

Not really sure what to make of the fact with the number of people viewing this post and no one brought it up...
Happy .Netting… Selah

1 comment: