jvance.com

.net, c#, asp.net, linq, htpc, woodworking

Jarrett's Tech Blog - Browsing jQuery

  1. Simple Fix for ASP.NET FormsAuthentication Redirect when using AJAX

    There is one paticular annoying "feature" of ASP.NET forms authentication module that has kicked my butt many times. When a user loads a page but their session has expired, the module will take over the request and return a 302 redirect to the login page rather than the appropriate 401 unauthorized.

    Specification of the correct behaviour has been part of the HTTP standard for more than 15 years now. HTTP 1.1, RFC 2616 (and before that, HTTP 1.0, RFC 1945) specify the correct behavior in sections 10.4.2 and 9.4 respectively (the verbiage hasn't changed significantly):

    This "feature" has always been broken in ASP.NET and it has caused me countless hours of research and workarounds. Others have also dealt with the problem:

    Back in 2008, I used the  HttpModule workaround as decribed in many of the above posts. I've also utilized an Application_OnError workaround. Unfortunately, many of these solutions require too much code, additional config, and/or tradeoffs.

    I would prefer a fix directly to forms authentication, but Microsoft still hasn't addressed the problem. We could replace forms authentication with something like AppHarbor.Web.Security or MADAM. However, this can be scary to those who are unfamiliar with exercising options outside of those provided by Microsoft.

    So that brings me to point of this post. How can we KISS and still fix the damn problem?

    Add this to Global.asax.cs to fix the broken FromsAuthentication redirect behavior. This code will reset the 302 back to 401 for AJAX requests.

    protected void Application_EndRequest()
    {
        var context = new HttpContextWrapper(this.Context);
    
        // If we're an ajax request and forms authentication caused a 302, 
        // then we actually need to do a 401
        if (FormsAuthentication.IsEnabled && context.Response.StatusCode == 302 
            && context.Request.IsAjaxRequest())
        {
            context.Response.Clear();
            context.Response.StatusCode = 401;
        }
    }
    

    Add this javascript to your layout so that anytime you use jQuery ajax, get, or post, the client will detect the 401 and reload the page. This will cause the browser to redirect to login page.

    $(document).ajaxError(function (xhr, props) {
      if (props.status === 401) {
        location.reload();
      }
    });
    

    That's all. Problem fixed with very few lines of code.

    Posted by JarrettV on September 21 at 5:39 AM

  2. Comparison of YUI Compressor for .Net to Microsoft Ajax Minifier

    Minify

    Microsoft just released the Microsoft Ajax Minifier for minifying javascript files.  Since I've been using the Yahoo! UI Library: YUI Compressor for .Net to do this in AtomSite, I thought it would be great to compare the two to see which is best.  I'm mainly interested in the file size reduction but it would be nice to know any speed differences as well.

    The Test

    image

    This method allows me to test compress some javascript using any method I pass into the Func delegate and capture the results.

    To get a reasonable sample of the performance I minified 3 different files with each method 1000 times.  I attempted to configure both algorithms to produce the smallest output possible.

     image

    The Results

    image

    From these results you can see that Microsoft AJAX Minifier creates smaller files in about the same amount of time.  Note, both algorithms have been set in aggressive, or hypercrush, mode to rename variables and perform other tweaks for reducing file size. The Microsoft AJAX Minifier seemed to have more granular options for tweaking output. However, the YUI Compressor is open source so you could add additional options if you need them.

    The Comparison

    Scorecard Speed Size Reduction Options CSS & JS Support Build Task Open Source
    YUI Compressor lose lose lose win win win
    Microsoft AJAX Minifier win win win lose win lose

    And the Winner is..

    It depends.  I suggest using the Microsoft AJAX Minifier as it produces smaller files.  However, the YUI Compressor.Net better satisfies my needs as it can minify both JS and CSS files.  So, when I need to minify dynamic combinations of both types of files, I'll use Yahoo! UI Library: Compressor for .Net.  When I need to do one-time minification during a build or prior to deployment, I'll use the Microsoft AJAX Minifier.

    Download

    I've uploaded the test solution and console app so you can run the tests yourself.

    JsMinTest.zip (291KB) fixed

    More Reads

    Check out how I am using minification and combination in AtomSite to speed up page load time.

    Posted by JarrettV on October 19 at 11:57 PM

  3. Get Value of Checkbox using jQuery to Enable Button

    Reading the value of a checkbox in jQuery is not obvious.  You must use a special selector :checked and then check if the value is undefined.

    //checked
    var checked = $('input[type=checkbox]:checked').val() != undefined;
    
    //unchecked
    var unchecked = $('input[type=checkbox]:checked').val() == undefined;
    

    The typical use case for this code is when you want the user to check the "I agree to the terms and conditions" before they can continue. For example:

    $(function() {
      $('#agree').click(function() {
        var satisfied = $('#agree:checked').val();
        if (satisfied != undefined) $('#continue').removeAttr('disabled');
        else $('#continue').attr('disabled', 'disabled');
      });
    });
    

    The above code finds the checkbox and binds to the click event.  When the user checks or un-checks the checkbox, it finds the continue button and enables or disables it based on the value of the checkbox.

    Update - A more elegant way

    //checked
    var checked = $('input[type=checkbox]').is(':checked');
    

    Change Textbox Readonly Value via Checkbox using jQuery

    Another case you may want to enable or disable a textbox based on the value of the checkbox.

    $(function() {
      $('#isOther').click(function() {
        var other = $('#isOther:checked').val();
        if (other != undefined) $('#other').removeAttr('readonly');
        else $('#other').attr('readonly', 'readonly');
      });
    });
    

    The above code changes the readonly property on the textbox when the checkbox is changed by the user.

    Posted by JarrettV on July 14 at 3:58 PM

  4. Using the New DateTime Support in .NET 3.5 via MVC & jQuery

    I've added New Global Date and Time Support  to BlogSvc by utilizing the new expanded support for date times with proper time zone support.  Some highlights in the MSDN documentation:

    The DateTimeOffset structure represents a date and time value, together with an offset that indicates how much that value differs from UTC. Thus, the value always unambiguously identifies a single point in time. A DateTimeOffset value is not tied to a particular time zone, but can originate from any of a variety of time zones. The TimeZoneInfo class makes it possible to work with dates and times so that any date and time value unambiguously identifies a single point in time. Taking advantage of time zone support in the .NET Framework is possible only if the time zone to which a date and time value belongs is known when that date and time object is instantiated.

    So the MSDN documentation is not clear on which class can make a date/time unambiguous.  However, the last sentence is the best clue.  We must capture both the UTC value and an originating time zone.

    For an ASP.NET MVC application we can add configuration to associate all date/times to our preferred time zone. 

    TimeZoneSettings

    With this configuration, we can now write an HtmlHelper extension to display a DateTimeOffset in our preferred time zone.

    DateTimeAbbrHelper

    Call the extension method and pass it either a DateTimeOffset or a DateTime

    .AbbrUsage

    This will result in the follwing html:

    <abbr title='Tuesday, October 07, 2008 10:01 PM (GMT-06:00) Central Time (US &amp; Canada)'>10/7/2008 10:01 PM - CST</abbr>
    

    This gives an abbreviated date/time display at your preferred time zone.

    However, you may want to display time relative to the user browsing your website. There are two ways to accomplish this:

    • Ask and store each user's time zone
    • Automatically determine user's time zone using javascript

    The first option is commonly used with forums and requires the user to register and choose their preferred time zone. The second option makes much more sense for content websites (such as a blog) since it can occur automatically without registration.

    There is already a great plugin for jQuery that can display fuzzy times that are directly relative to the user.  It is called the Time Ago Plugin.  To use it, lets create another helper extension that utilizes a micro-format:

    TimeAgoAbbrHelper

    This creates abbreviations in the html, that when activated through jQuery show times that will be automatically updated even after the user has loaded the page.

    TimeAgoDisplay

    This DateTime display is much more recognizable and personable to the casual user.

    Head on over to the BlogSvc website to download the code.

    Update: here is a bonus function that will allow you to format the date (with access to the time zone information) anyway you'd like.

    DateTimeAbbrHelperBonus

     

    Call it like

    :DateTimeAbbrHelperBonusCall

    Posted by Jarrett on October 09 at 2:24 AM

  5. New jQuery Rater Plugin for Star Ratings

    The jQuery Star Rating widget is a neat control to add to your website.  It has many options that allow you to easily customize it.  However, it's usage is based on a fully degradable form submission model which means you must use markup containing an option list.  Unfortunately, this means it becomes quite complex to support a rating model that fires off an ajax request to submit a new rating.  Therefore, the developer is left to worry about:

    • Writing code on the server to generate the option list only for users that have not already rated
    • If the user has already rated, the server must generate different markup, or set the widget to disabled
    • The developer must write javascript to handle the widget callback and build an ajax request
    • No built in support for rating count and updated rating result
    • No built in support for a failed rating

    To make life easier, I wrote the jQuery Rater Plugin that should reduce the complexity of implementing an ajax rating scenario. 

    jQuery Rater Plugin Demo

    jQuery Rater Plugin Demo

    Features

    • Auto Ajax posting
    • Supports rating update and rating count
    • Shows previous rating before user has rated
    • Markup is same for rated and unrated
    • Supports step ratings (partial stars)

    View the Demo Page

    First, lets take a look at the markup which is contained in an ASP.NET user control.  However, you could write this in your server language of choice.  There are three things being set below.  The width of the stars, the current rating, and the count of ratings.

    RaterMarkup

    The only markup elements required by the plugin are the "ui-rater-starsOff" and "ui-rater-starsOn" spans.  Also, they must be contained within an element that has an id you can reference.

    We only need to activate the plugin when the user has not already rated the entry.

    SetupPlugin

    The only option I've set is the address to post the rating to.  When the user performs a rating, the plugin will automatically build an ajax request to the postHref.  It includes the id and chosen rating value in the form post data.

    This plugin does more with less code than the existing jQuery Star Rating Widget because it foregoes the degrade-ability in favor of ajax.

    • Previous Javascript size: ui.core.packed.js 4KB + ui.stars.pack.js 4KB + rate.js 2KB = 10KB
    • New Javascript size: jquery.rater.js 3KB (unpacked)

    View the source code

    To see a full server implementation, see the source code of AtomSite.

    Download jQuery Rater Plugin (javascript + demo html + image + sample server page)

    Found this plugin useful? Please kick it - kick it on DotNetKicks.com

    Posted by Jarrett on September 29 at 1:37 AM

© Copyright 2024