RAM: Chrome or Firefox?

Just a quick snap comparison:

ram-chrome-vs-firefox

RAM: Chrome vs Firefox

Firefox has 13 tabs open, Chrome has 3 plus the “about:memory”.

Firefox has 36 add-ons of which 1 is disabled, Chrome has 14, of which 6 are disabled.

Background image for a table row in IE7

Having this structure:

<tr class="current">
 <td class="project-number">
 </td>
 <td>
 </td>
</tr>

.current {background-color: #dcdcdc !important; background: url(../images/current-item.png) no-repeat 0 0;}

Class “current”  would display a “>” arrow to highlight the selected row, however IE7 displays the arrow on each table cell.

The solution is to include a css just for IE7:

<!--[if lte IE 8]><link rel="stylesheet" type="text/css" href="css/ie7.css" /><![endif]-->

Then in ie7.css:

.current td {background: none;}
.current td {background-color: #dcdcdc !important;}
.current td:first-child {background-color: #dcdcdc !important; background: url(../images/current-item.png) no-repeat 0 0;}

Update: Chrome and Safari have the same bug as IE7, Opera renders the image correctly.

Multi select DropDownList in ASP.NET

I needed a dropdown list that allows multi select, a sort of checkbox list paired with a dropdown. For example is very useful when working with months. MS Reporting Services has one.

After googling for a while, I couldn’t find one to satisfy me and I started to play with a dropdown. A click on dropdown and a list of checkboxes appears, another click and the list dissappears. Problem was that the dropdown wanted to show it’s “Select month” option.

Long story short, I paired a TextBox, styled with css to have a “select arrow”, with a CheckBoxList and some jQuery:

Multiselect DropDownList

And here is the code: MonthsControl-src.7z

Cannot pass arguments to OnClientClick javascript

I want to give more information to the confirm dialog when the user deletes a record.
I’m using an asp:LinkButton that can execute some javascript when the user clicks it, in the “OnClientClick” property.

<ItemTemplate>
     <asp:LinkButton ID="lnkClose" runat="server" CausesValidation="False"
         data-number='<%# Eval("Number") %>' CommandArgument='<%# Eval("Id") %>'
         CommandName="close" CssClass="selected_item close-project">Close
    </asp:LinkButton>
 </ItemTemplate>

Unfortunately, I cannot pass the project number as an argument to the javascript function in OnClientClick.

Luckily, there is jQuery:

$('#ProjectsList a.close-project').live("click", function()
 {
     var $parentRow = $(this).parent().parent();
     $parentRow.toggleClass("current");

     var projectNumber = $(this).attr("data-number");
     var answer = confirm("Close project " + projectNumber + "?");
     if (!answer)
     {
          $parentRow.toggleClass("current");
     }
     return answer;
 });

Update: There is a way to pass arguments:

http://forums.asp.net/t/980311.aspx/1?Eval+in+an+OnCLientClick

Set active menu item

I have a menu and I need to highlight the menu item that loaded the current page. I tried to set server-side the id of the body to something unique and pertaining to the current page being loaded. Surprisingly, I could not get the page file name (or some other unique Id) but only the page title which wasn’t good enough.

The HTML (in a Master page):

<div id="menu">
    <ul>
        <li id="regions">
            <asp:HyperLink ID="hlRegions" runat="server" CssClass="menu-item"
                                  NavigateUrl="~/Regions.aspx">Regions</asp:HyperLink>
        </li>
        <li id="municipalities">
            <asp:HyperLink ID="hlMunicipalities" runat="server" CssClass="menu-item"
                                  NavigateUrl="~/Municipalities.aspx">Municipalities</asp:HyperLink>
        </li>
    </ul>
</div>

The Javascript:

<script type="text/javascript" >
        function getPageName()
        {
            var loc = document.location.href;
            return loc.substring(loc.lastIndexOf('/') + 1, loc.indexOf('.')).toLowerCase();
        }
        jQuery(document).ready(function($)
        {
            var pageName = getPageName();
            log("pageName:", this, pageName);

            $('#menu li').removeClass("selected-menu");
            $('#menu ul #' + pageName).addClass("selected-menu");
        });
</script>

Each time the page loads, the “selected-menu” class is removed from all li items under #menu. Then, the “selected-menu” class is added to the li item that has the id equal to the page being loaded.

GridView, NHibernate and sorting

If you’re using an ASP.NET GridView with a custom DAL you might get this error when trying to sort the grid by clicking the column headers:

The data source does not support sorting with IEnumerable data. Automatic sorting is only supported with DataView, DataTable, and DataSet.

The web has some solutions to this problem, however I’ve found them either not working, sorting only in memory or too complex.

I’m using NHibernate and the simplest solution was to parse the sortExpression from the ObjectDataSource into a list of NHibernate.Criterion.Order, then add the Orders to the ICriteria.

This way, I only have to add SortParameterName=”sortExpression” to the ObjectDataSource and the corresponding code in the Select method.

The ObjectDataSource:

<asp:ObjectDataSource ID="odsProjects" EnablePaging="true" runat="server"
    SelectMethod="FindAll"
    SortParameterName="sortExpression"
    SelectCountMethod="GetCountOfProjects" TypeName="Model.Project">
</asp:ObjectDataSource>

The GridView:

<asp:TemplateField HeaderText="Title" SortExpression="Title">
    <ItemTemplate>
        <asp:LinkButton ID="lnkProjectTitle" runat="server"
         CommandName="select" Text='<%# Eval("Title") %>'
         CausesValidation="False"></asp:LinkButton>
    </ItemTemplate>
</asp:TemplateField>

The Find method in the Project class:

public static IList<Project> FindAll ( int startRowIndex, int maximumRows, string sortExpression)
{
    ISessionFactoryHolder sessionHolder = ActiveRecordMediator.GetSessionFactoryHolder();
    ISession session = sessionHolder.CreateSession( typeof( Project ) );

    try
    {
        ICriteria crit = session.CreateCriteria( typeof( Project ) );

        crit.SetFirstResult( startRowIndex )
            .SetMaxResults( maximumRows );
        // the important thing
        if ( string.IsNullOrEmpty( sortExpression ) )
            crit.AddOrder( Order.Desc( "Id" ) );
        else
        {
            foreach ( Order order in Extensions.CreateOrdersFrom( sortExpression ) )
            {
                crit.AddOrder( order );
            }
        }

        return crit.SetCacheable( true ).List<Project>();
    }
    catch ( Exception ex )
    {
        log.ErrorException( "FindAll: ", ex );
        return new List<Project>();
    }
    finally
    {
        sessionHolder.ReleaseSession( session );
    }
}

The CreateOrdersFrom method:

/// <summary>
/// Creates a list of NHibernate.Criterion.Order from an sql sort expression. If sort is missing, ASC is assumed.
/// </summary>
/// <param name="sqlSortExpression">Id DESC, Number ASC or Id, Name desc</param>
/// <returns></returns>
public static List<Order> CreateOrdersFrom ( string sqlSortExpression )
{
    if ( string.IsNullOrEmpty( sqlSortExpression ) )
        return new List<Order>();

    List<Order> orders = new List<Order>();
    string[] sortExpressions = sqlSortExpression.Trim().Split( ',' );

    Array.ForEach( sortExpressions, sortExpression =>
    {
        log.Debug( "expr: {0}.", sortExpression );

        string[] columnAndSort = sortExpression.Trim().Split( ' ' );

        string column = "", sort = "asc";

        if ( columnAndSort.Length == 1 )
        {
            column = columnAndSort[0];
        }
        if ( columnAndSort.Length == 2 )
        {
            column = columnAndSort[0];
            sort = columnAndSort[1];
        }
        log.Debug( "{0} x {1}.", column, sort );

        orders.Add( sort.ToLowerInvariant() == "asc" ? Order.Asc( column ) : Order.Desc( column ) );
    } );

    return orders;
}

jQuery Validation and select tags

Just a note to myself, when using jQuery Validation for a select, make sure the first value, "Please select an option" has an empty value.

Like this:

<select id="regions" class="required" name="regions">
    <option value="">Please select an option</option>
    <option value="1">Region 1</option>
    <option value="2">Region 2</option>
</select>

Here’s the original text:

http://docs.jquery.com/Plugins/Validation/Methods/required

Validate a form on a click (pun intended)

I have a grid with users, where for each user several reports can be generated.

The reports must have a start and end date and because some technical constraints and because I wanted to let users re-use an url, I decided to send the values by query string.

Then, I had to add some validation, so that the user would be forced to select the report dates.

Then, the problem, how to prevent the click on the link if the form was not valid?

Here’s the solution:

 

<div id="start-date-area">
    <p>Select the start date:</p>
    <input id="cal-from-date" name="from" type="text" class="required for-report clickable" readonly="readonly" />
    <p></p>
</div>
<div id="end-date-area">
    <p>Select the end date:</p>
    <input id="cal-to-date" name="to" type="text" class="required for-report clickable" readonly="readonly" />
    <p></p>
</div>

 

$("a.submit").live("click", function(ev)
{
    ev.preventDefault();
    var $self = $(this);

    $("#aspnetForm").validate();
    if ($("#aspnetForm").valid())
    {
        // generate a querystring fragment from the fields I need to send to the server
        var qs = $(".for-report").serialize();

        //console.log("qs: " + qs);
        document.location = $self.attr("href") + "&" + qs;
    }
});

I have used $("a.submit").live("click", function(ev) instead of

$("a.submit").click(function(ev) because the rows are added in the grid using ajax and click works only on current elements and not on possible future elements.