Customizing Asp.net menu control to use jQuery,Superfish and CSS Friendly Control Adapters

I have used Asp.net menu controls in a lot of applications earlier but now a days with so many new things and controls asp.net menu control seems to lag in many basic functionalities, there are various other options available to be used as a replacement of the asp.net menu control. But what i loved with the asp.net menu control was its seamless integration with the sitemap datasource and with no hassle i could display whole of my site’s navigation in the menu control by just configuring them in the sitemap file. What i disliked most was that the menu control by default is rendered as a table structure and not as div structure. So to fight this abnormality Microsoft released CSS Friendly Control Adapters so that most of the controls which are rendered as tables can be rendered as a simple and clean div structure. But today i was experimenting with other available options and i found a really cool Superfish jQuery plug-in which we can attach with the asp.net menu control to achieve very cool affects. In this article i will share the steps on how to hook up the Superfish jQuery Menu plug-in into your asp.net website to beautify your asp.net menu control. Also please check various option available with the Superfish plug-in on how it can be customized from the Superfish plug-in website. http://users.tpg.com.au/j_birch/plugins/superfish/#examples Now let’s look at the steps to integrate superfish menu with asp.net menu

Main JavaScript file which is required is superfish.js along with jQuery any version.js rest files are optional and are used if we use some advanced features and customizations with the superfish menu. Main CSS file is superfish.css and for this demo we will modify this file only.

  • After downloading the superfish menu files now we should download the CSS Friendly Adapter from http://cssfriendly.codeplex.com/
  • Place the CSSFriendly.dll into your website bin folder and the CSSFriendlyAdapters.browser in your App_Browser folder.Also remember to comment out the unwanted code from the CSSFriendlyAdapters.browser file as we are dealing only with the menu.
 <controlAdapters>
      <adapter controlType="System.Web.UI.WebControls.Menu"
               adapterType="CSSFriendly.MenuAdapter" />
      <!--adapter controlType="System.Web.UI.WebControls.TreeView"
               adapterType="CSSFriendly.TreeViewAdapter" />
      <adapter controlType="System.Web.UI.WebControls.DetailsView"
               adapterType="CSSFriendly.DetailsViewAdapter" />
      <adapter controlType="System.Web.UI.WebControls.FormView"
               adapterType="CSSFriendly.FormViewAdapter" />
      <adapter controlType="System.Web.UI.WebControls.DataList"
               adapterType="CSSFriendly.DataListAdapter" />
      <adapter controlType="System.Web.UI.WebControls.GridView"
               adapterType="CSSFriendly.GridViewAdapter" />
      <adapter controlType="System.Web.UI.WebControls.ChangePassword"
               adapterType="CSSFriendly.ChangePasswordAdapter" />
      <adapter controlType="System.Web.UI.WebControls.Login"
               adapterType="CSSFriendly.LoginAdapter" />
      <adapter controlType="System.Web.UI.WebControls.LoginStatus"
               adapterType="CSSFriendly.LoginStatusAdapter" />
      <adapter controlType="System.Web.UI.WebControls.CreateUserWizard"
               adapterType="CSSFriendly.CreateUserWizardAdapter" />
      <adapter controlType="System.Web.UI.WebControls.PasswordRecovery"
               adapterType="CSSFriendly.PasswordRecoveryAdapter" /-->
    </controlAdapters>

 

  • Also download the latest version of jQuery, otherwise there is already a version of jQuery in the Superfish package.
  • Now start creating your pages and once you are done , just create a sitemap file to list your whole website.
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    <siteMapNode url="" title=""  description="">
        <siteMapNode url="Default.aspx" title="Home" description=""/>
        <siteMapNode url="AboutUs.aspx" title="About Us"  description="" />
        <siteMapNode url="Services.aspx" title="Services"  description="" >
            <siteMapNode url="Services/Service1.aspx" title="Service1" description="">
                <siteMapNode url="Services/SubService1.aspx" title="SubService1" description="" />
                <siteMapNode url="Services/SubService2.aspx" title="SubService2" description="" />
                <siteMapNode url="Services/SubService3.aspx" title="SubService3" description="" />
                <siteMapNode url="Services/SubService4.aspx" title="SubService4" description="" />
            </siteMapNode>
            <siteMapNode url="Services/Service2.aspx" title="Service2" description=""/>
            <siteMapNode url="Services/Service3.aspx" title="Service3" description=""/>
            <siteMapNode url="Services/Service4.aspx" title="Service4" description=""/>
        </siteMapNode>
        <siteMapNode url="ContactUs.aspx" title="Contact Us" description=""/>
    </siteMapNode>
</siteMap>
  • After building all this your solution architecture should be like this.

  • Now just the master page configuration is left and you are ready to go then
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="Default.master.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>

    <script src="Scripts/jquery-1.3.1.js" type="text/javascript"></script>

    <script type="text/javascript" src="Scripts/superfish.js"></script>

    <link type="text/css" href="~/Styles/superfish.css" rel="stylesheet" media="screen"
        runat="server" />
    <link href="Styles/stylemain.css" rel="stylesheet" type="text/css" />

    <script type="text/javascript">
        $(document).ready(function() {
            $('ul.AspNet-Menu').superfish();
        }); 
    </script>

    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="form1" runat="server">
    <div id="outerWrapper">
        <div id="header">
            <div id="logo">
                <asp:HyperLink runat="server" NavigateUrl="~/Default.aspx" ID="lnkLogo">    
                </asp:HyperLink>
            </div>
        </div>
        <div id="menu">
            <asp:Menu ID="menuMain" runat="server" DataSourceID="stmpDataSource" Orientation="Horizontal">
            </asp:Menu>
            <asp:SiteMapDataSource ID="stmpDataSource" runat="server" ShowStartingNode="false" />
        </div>
        <div id="mainContent">
            <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
            </asp:ContentPlaceHolder>
        </div>
        <div id="footer">
        </div>
    </div>
    </form>
</body>
</html>
  • Important :- By default the Superfish menu css file contains the settings aligned with the ul name sf-menu but the asp.net menu control renders the ul element as AspNet-menu so the important step is to replace all the occurrences of sf-menu in the superfish.css with AspNet-menu to make this menu work.

You can download the sample project and plug and play with the CSS file customized for the asp.net menu if you find difficulties in customizing by your self.

After embedding this in your master page you are done with the settings and customization and you are ready to go, i got this menu in just 15 minutes so simple and so easy.

Working Demo can be seen here http://www.smallworkarounds.net/demos/superfish.demo/

Download the Demo from http://www.smallworkarounds.net/blog/democode/Superfish/Superfish.Demo.zip

Happy Programming!!!!!!!!!!!!!!!!!!!!


Best and simple approach to deal with JSON Dates problem

It might be very frustrating for the guys who decided to try for the so called great revolution using jQuery and asp.net,WCF and Linq in combination. Their adventure with the code might come to an end first on the WCF configuration step or secondly handling the JSON serialization over the wire. Although its really simple to configure the WCF service for your JSON wire transfer requirement but its certainly a little confusing. Another problem which comes after successful configuration of the WCF services with your application is dealing with “Dates”. This problem arises due to the fact that there no javascript literal called Date.Everytime we need a date we create a new object of the date such as:-

Date myDate = new Date(“28/04/2008”);

 

If you write the date like the below given syntax then its not the actual date but its only ordinary string which is of no use as such and does not solve our purpose.

var  myDate = “28/04/2008”;

So the response which you will receive from the server in the JSON format will contain all the dates in a surprising format which can be easily parsed if you are using Micorosft Ajax. But if you are on your own using direct jQuery $ajax() then your life is in trouble.

To workaround this strange Date problem there are few possible ways out of which :-

  1. Parse the response from the server on your own and just use the regex to remove / symbol and then evaluating the date string and converting it to Date($1) and returning this date.Although this method is the so called correct one but still its little too complicated and it seems to be the only standard workaround for solving this problem.Given below is some custom implementation for showing how you can parse and evaluate the response received from the server.Always keep in mind that this code would need some change if you are using some other type of replacer symbols in the JSON,this is just a reference example how to parse the response and then evaluating it to get the correct dates.
  $.ajax({
        type: "POST",
        url: pagePath + "/" + methodName,
        contentType: "application/json; charset=utf-8",
        data: paramList,
        dataType: "text",
        processData: false,
        success: function(msgg) {
            var msg = JSON.parse(msgg, function(key, value) {
                var a;
                if (value != null) {
                    if (value.toString().indexOf('Date') >= 0) {
                        a = /^/Date((-?[0-9]+))/$/.exec(value);
                        if (a) {
                            var dt = new Date(parseInt(a[1], 10));
                            return (dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear();
                        }
                    }
                    return value;
                }
            });
            successFunction(msg);
        },
        error: function(xhr, status, error) {
            errorFunction(xhr, status, error);
        }
    });

Here in this example we are getting the actual response in the variable msgg.After invoking the success we are parsing the response and then we are searching for the Date values in the string where ever found we are removing the unnecessary symbols / and then parsing the 10 digit date and after this step converting it to actual date and finally returning the value.

Although its a little tricky approach but it works fine,you might have to change the parsing method a little bit as according to your needs to make it work for you.

2.Another simple solution is forget about the Date thing on the client side consider every thing as string on the client and also in your business logic and application layer.Although it doesn’t sounds good and many of us don’t agree on this but its the simplest possible workaround to make things work quickly.

So for achieving this no need to make any changes in your database schema just let the dates be dates only in your schema.

What we will do is we will pass date as string from the UI using BusinessObjects to the Service Layer and DataAccessLayer and after reaching the database we will convert these values back to string and while retrieving those dates from the database they should be converted again back to string so that we are not again running into the same old problem.

Converting date to string while retrieving back the date to be displayed somewhere on the page

CONVERT(CHAR(11),datemodified ,106) AS datemodified,
		CONVERT(CHAR(11),datecreated,106) AS datecreated

There are various other choices available with changing the last code part to receive date in various other formats.

By using this mechanism you will never run into this date trouble again


Ext.js 2.2 intellisense in Visual Studio 2008

Today i was playing with ext.js a very nice little java script framework which can give you very stunning UI at the end if you have little patience. Although Visual Studio 2008 provides support for java script intellisense but it is rather bleak or dull so when it comes to jQuery there is a vsdoc file for our rescue. But what about when you are playing with other javascript libraries like ext.js So i found a very good link which talks about getting ext.js 2.2 intellisense in Visual Studio 2008 which i wanted to share with you all http://www.spket.com/ext-intellisense-visual-studio.html I will be doing a series of articles on ext.js in future as i have started playing with it. Happy Programming !!!!!


Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.

If you are getting this error, this means you are conceptually doing wrong somewhere.Ideally ajax scenarios are meant only for small to medium server side calls not for getting tons of data, and if you are getting a lot of data using the asynchronous request then you are asking for trouble.So in such scenarios it is best to go and implement server side logic.But what if you are at a stage where you can't change your application logic now.

1.So for such a situation there are two ways either implement paging in getting your data which is very simple if you are using jQuery with any other server side technology. Here is a quick link which tells you how to enable paging and many other things in your custom code. http://localhost/smallworkarounds/index.php/2009/02/28/jquery-aspnet-how-to-implemen/ 2.If you can't enable paging also then you are left with only one other solution which is not so good but if your service call is failing then it will prevent the service call from failing, but if you are loading large amount of data again if you prevent your service call from failing still your browser will go abrupt and seems like it has hanged, but if you still want to try then just make this entry in your web.config file to increase the max-request length of the json-request

<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="2147483644"></jsonSerialization>
</webServices>
</scripting>
</system.web.extensions>

Important thing to keep in mind is that the maximum value for the integer field is 2147483647 and this limit has to remain inside the bounds of this value.

Happy Programming!!!


jQuery Leaking Memory:-Be careful while using in big applications

jQuery is very small and useful javascript library which is a must for every developer related to web. I also have used jQuery in my applications a lot, but recently i found that jQuery is leaking memory which is causing trouble to my applications,so be careful while using your selectors and creating dynamic DOM elements by using jQuery.In this article i will discuss the simple ways to track the memory leak in your application and comments related to optimizing and reducing the memory leaks using jQuery are always welcome.

How to detect the memory leak in your web application There is a very simple tool available on web known as "Drip" which can help you to test the memory leaks in your web applications You can download drip from http://www.outofhanwell.com/ieleak/Drip-0.5.exe Documentation of drip is available at https://ieleak.svn.sourceforge.net/svnroot/ieleak/trunk/drip/docs/index.html Drip can catch the memory leaks inside the boundary of Internet Explorer but not outside its boundary. A typical run on one of my applications which is fully jQuery dependent gives me these results. What Drip does is that it unloads the page and checks for the memory leaks which remained even after the page was unloaded. Given below is the drip test on jQuery.com As you can see that jQuery.com also have some memory leak which seems to be a bug to me in jQuery code itself. On some research on net i found that commenting out few lines of code in the jQuery itself can reduce some of the memory leaks in your application but still the memory leak is there and doesn't leave you, might be in future we get some bug fix on this memory leak thing from the jQuery team. The lines of code commenting which can do little magic is found inside the jQuery library

if ( div.attachEvent && div.fireEvent ) {
		div.attachEvent("onclick", function(){
			// Cloning a node shouldn't copy over any
			// bound event handlers (IE does this)
			jQuery.support.noCloneEvent = false;
			div.detachEvent("onclick", arguments.callee);
		});
		div.cloneNode(true).fireEvent("onclick");
	}

If any one of you have some other tips and tricks to reduce this memory leaking and any other way to prevent it.Do post comments to help the community and also help a lot of jQuery developers and jQuery itself to be a bug free library.

Happy Programming!!!