Thursday, September 27, 2012

Calling ASP.NET Page Methods with jQuery (Revealing Module Pattern)


This section describes an brief overview of "Revealing Module Pattern" and how can be call a Page Method using Ajax with jQuery (Revealing Module Pattern) without polluting global namespace (window).

What is Revealing Module Pattern ?

The Revealing Module Pattern actually uses the concept of the Self-Executing Anonymous Function as well, but in this case we save the result into a variable. This pattern introduces the concept of a Closure. A closure is a way to keep variables alive after a function has returned. The Mozilla Developer Network has a great page explaining closures. In it they provide a core definition:

“A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created.”

Example:

(function (Alerts, $) {
    var test = " My first pattern";
    function Func() {
        alert(test);
    }
    Alerts.publicFun = function () {
        alert("My public Function");
    }
    Alerts.FirstPublicProp = "1233444";

    Alerts.PageMethodCall = function () {

        PageMethods.TestCall(OnRequestComplete, OnRequestError);
    }

    OnRequestComplete = function (result, userContext, methodName) {

        alert(result);
   }

    OnRequestError = function (error, userContext, methodName) {

        if (error != null) {
            alert(error.get_message());
        }
    }
    //return myobj;
} (window.Alerts = window.Alerts || {}, jQuery));

Here, you will surprise following terms :

1. What is meant by window.Alerts=window.Alerts || {}

The code checks to see if Alerts exists in the global namespace i.e. window. If it does not exist, then windows.Alerts is assigned an empty object literal. Using this approach we can build a library across JavaScript files. If another script uses the same technique, then it will pass in the existing instance and append logic to it. Inside the Anonymous Function, if we want something to be public, then we append it to the skillet object. Any other properties or methods will be considered private.

2.The second argument passed in jQuery. The benefit of this is that the named parameter is referenced as $, which allows us to refer to jQuery as $ within the Anonymous Function without having to worry that it will conflict with the $ declared in other JavaScript libraries. This is a common practice that you will most likely run across when looking at well written jQuery code. 

Page Methods :

Page Methods is a new mechanism in ASP.NET applications where the server code can be bound to ASP.NET pages. It is an easy way to communicate asynchronously with the server using ASP.NET AJAX technologies. It is an alternate to calling the page which is reliable and carries a low risk. It is basically used to expose the web methods to the client script.

This tutorial assumes you have some familiarity with Page Method concept of ASP.NET and basic knowledge of jQuery.

Lets take a case, on click of Button of ASPX page, we need to invoke "PageMethodCall" of Alerts module defined above. Lets see, How to do that.

1. Create an .aspx page:


<%@ Master Language="C#" AutoEventWireup="true" CodeFile="Site.master.cs" Inherits="SiteMaster" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head runat="server">
    <title></title>
    <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
    <asp:ContentPlaceHolder ID="HeadContent" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form runat="server">
    <asp:ScriptManager runat="server" EnablePageMethods="true" AsyncPostBackTimeout="5000">
        <Scripts>
            <asp:ScriptReference Path="~/Scripts/jquery-1.4.1.min.js" />
            <asp:ScriptReference Path="~/Scripts/Module.js" />
        </Scripts>
    </asp:ScriptManager>
    <input type="button" title="click here" onclick="Alerts.PageMethodCall()" />
    <div class="main">
        <asp:ContentPlaceHolder ID="MainContent" runat="server" />
    </div>
    <div class="footer">
    </div>
    </form>
</body>
</html>


1. Please note ScriptManager tag. It has two properties assigned:
 a) EnablePageMethods = "true" which means, it allows to call "web page" method directly from JS.
 b) AsyncPostBackTimeout property is set to specify timeout limit to get results.

2. We added ScriptReference tag to assign scripts referenced for same. Please note, we have created a new file called "Module.js" and copied jQuery method defined on top.

3. See the below line carefully : 

<input type="button" title="click here" onclick="Alerts.PageMethodCall()" />

onclick of button, we are calling Page Method of Alert Module. Here we need to add "Module Name" just before "Page Method" to be invoked as Page Methods are defined in scope of "Alerts" module only.

Using same, we are avoiding to pollute global namespace of JavaScript which is one of the best practice of defining JS methods.Page methods are much more openly accessible than it may seem at first. The relative unimportance of EnablePageMethods is a nice surprise.To demonstrate the mechanism with minimal complications, this example has purposely been a minimal one. 

-Thanks!
Tarun

Found a good link: Good and Bad habits of Javascript