Hugoware

The product of a web developer with a little too much caffeine

Posts Tagged ‘Code Samples

More Control When Parsing Values

with 4 comments

As much as you might try, sooner or later you’re going to wind up parsing string values and converting them into their correct type. It is… inevitable.

If you’re going for clarity then this only takes a couple lines of code to accomplish. For example…

int value = default(int);
int.TryParse("44", out value);

No big deal, in fact it is possible to do on a single line of code…

int value = int.TryParse("44", out value) ? value : default(int);

Of course, this line of code is going to draw more questions from some of the less experienced developers on your team, but hey… doesn’t it just scream ‘Alpha Programmer’?

Parsing integers isn’t really a big deal in itself but wouldn’t it be nice if the entire process could be done on one line with one method and allow you to supply default values… and without causing confusion?

Below is an example of how you might create a class that handles parsing for you.

/// <summary>
/// Handles parsing string values to appropriate types
/// </summary>
public static class Parse {

	#region Static Constructor

	//prepares the Parse class
	static Parse() {
		Parse._CustomParsing = new Dictionary<Type, Func<string, object>>();
	}

	#endregion

	#region Properties

	//holds custom parse methods
	private static Dictionary<Type, Func<string, object>> _CustomParsing;

	#endregion

	#region Public Methods

	/// <summary>
	/// Registers a custom parsing method
	/// </summary>
	public static void RegisterType<T>(Func<string, object> compare) {
		Type type = typeof(T);
		Parse._CustomParsing.Remove(type);
		Parse._CustomParsing.Add(type, compare);
	}

	/// <summary>
	/// Attempts to parse a value and return the result
	/// but falls back to the default value if the conversion fails
	/// </summary>
	public static T TryParse<T>(string value) {
		return Parse.TryParse(value, default(T));
	}

	/// <summary>
	/// Attempts to parse a value and falls back to the
	/// provided default value if the conversion fails
	/// </summary>
	public static T TryParse<T>(string value, T @default) {
		value = (value ?? string.Empty).ToString();
		Type type = typeof(T);

		//so much can go wrong here, just default to the
		//fall back type if the conversions go bad
		try {

			//perform custom parsing first
			if (Parse._PerformCustomParse(type, value, ref @default)) return @default;

			//check if this is a nullable and if we should use a child type
			//this might not work with VB since the nullable name could be different
			if (type.IsGenericType && type.Name.StartsWith("Nullable`")) {
				
				//underlying type for a nullable appears to be the first argument
				type = type.GetGenericArguments().FirstOrDefault();
				
				//if no type was found then five up
				if (type == null) { return @default; }

				//try custom parsing with the underlying type if this was a nullable
				if (Parse._PerformCustomParse(type, value, ref @default)) return @default;
			}

			//try the remaining parsing methods
			if (type.IsEnum && Parse._PerformEnumParse(type, value, ref @default)) return @default;
			if (Parse._PerformParse(type, value, ref @default)) return @default;

			//finally, just try a conversion
			Parse._PerformConvert(type, value, ref @default);
			return @default;

		}
		//settle for the default
		catch {
			return @default;
		}

        }

	#endregion

	#region Checking Values

	//uses custom parsing methods
	private static bool _PerformCustomParse<T>(Type with, string value, ref T result) {

		//if there is no custom type, cancel
		if (!Parse._CustomParsing.ContainsKey(with)) { return false; }

		//find the conversion
		Func<string, object> parse = Parse._CustomParsing[with];

		//attempt to parse
		try {
			object converted = parse(value);
			bool success = converted is T;
			if (success) { result = (T)converted; }
			return success;
		}
		//if the attempt failed
		catch {
			return false;
		}

	}

	//tries to parse using an Enum
	private static bool _PerformEnumParse<T>(Type with, string value, ref T result) {

		//check for a result
		try {
			object parsed = Enum.Parse(with, value, true);
			bool success = parsed is T;
			if (success) { result = (T)parsed; }
			return success;
		}
		catch {
			return false;
		}

	}

	//searches for a 'Parse' method
	private static bool _PerformParse<T>(Type with, string value, ref T result) {

		//make sure a try parse was even found
		MethodInfo method = with.GetMethods().FirstOrDefault(item =>
			item.Name.Equals("parse", StringComparison.OrdinalIgnoreCase) &&
			item.IsStatic);
		if (method == null) { return false; }

		//check for a result
		try {
			object parsed = method.Invoke(null, new object[] { value, result });
			bool success = parsed is T;
			if (success) { result = (T)parsed; }
			return success;
		}
		catch {
			return false;
		}

	}

	//performs common conversions
	private static bool _PerformConvert<T>(Type type, string value, ref T result) {
		object convert = Convert.ChangeType(value, type);
		bool success = convert is T;

		//update the type if needed
		if (success) { result = (T)convert; }
		return success;
	}

	#endregion

}

The general idea behind this code is to attempt to parse using a variety of ways and then fall back to a default value if nothing works out. This way we can get in and out of parsing values without needing to split up the code.

There is an ugly little bit of reflection in there, so if your application can’t incur that kind of penalty hit you might want to fall back to the classic parsing methods.

int count = Parse.TryParse("44", 0); // 44
bool success = Parse.TryParse("cheesecake", true); // true
decimal = Parse.TryParse("3.01", 3M); // 3.01

Additionally, this code allows you to add your own parsing methods to the class and use the same method across the entire project.

//register our own parsing method
Parse.RegisterType<Color>(value => ColorTranslator.FromHtml(value));
Parse.RegisterType<decimal>(value => {
    value = Regex.Replace(value, @"[^0-9\.]", string.Empty);
    return decimal.Parse(value);
    });

//use it just like any other value
Color color = Parse.TryParse("#ff0000", Color.Blue);
decimal total = Parse.TryParse("$45.33", 0M);

You could take the extension methods a step further by adding the same functionality to your strings. For example.

/// <summary>
/// Extensions to quickly parse string types
/// </summary>
public static class StringExtensions {

	/// <summary>
	/// Parses a string to the correct type or default value
	/// </summary>
	public static T ToType<T>(this string value) {
		return value.ToType(default(T));
	}

	/// <summary>
	/// Parses a string to the correct type or default value
	/// </summary>
	public static T ToType<T>(this string value, T @default) {
		return Parse.TryParse(value, @default);
	}
	
}

This would allow you to perform the conversions from the string itself and avoid the call to a static method floating around in the project.

bool admin = "true".ToType<bool>();
int count = "3334".ToType<int>();
Color blue = "something".ToType(Color.Blue);
Color green = "#00ff00".ToType(Color.Red);

Parsing values isn’t hard but is certainly doesn’t hurt to make it a bit easier.

Written by hugoware

August 5, 2010 at 1:29 am

Using WebControls In ASP.NET MVC Views – Part 3

with 18 comments

Check out my newest blog post about using WebControls inside of MVC (source code included)🙂

WebControls In MVC Series

I mean’t to have this post out this morning, but I was busy working on getting my personal website online — Please check it out and tell me what you think!

Up until now all of the post in this series have been tests to see if we could make the process work. Now, finally, now we get into some real code that we can actually use. I’ll take just a little bit of space to explain how it works and how to set it up, but then the rest of the post to explain how to use it.

Getting The Code Setup

Before we discuss how to use the code lets go over briefly how to setup the code.

To start, the code you need to download is found at the end of the post. When you download it, put both the .cs and the .aspx file into your project. By default the code expects the .aspx to be in your Views directory, but you can move it — but if you do then you need to update MVCWebFormExtensionMethods._WebFormRenderControl.TEMPLATE_PAGE with the new location (yeah, it’s a long name :)).

Optionally, you can make a couple changes to your Web.config to make sure that the extension method and MvcControlGroup are available to the rest of your application without needing to add anything special onto each of your pages.

<configuration>
    <!-- snip... -->
    <system.web>
        <pages>
            <controls>
                <!-- snip... -->
                <add tagPrefix="mvc" 
					namespace="MvcWebControls" 
					assembly="YourProjectAssemblyName" />
            </controls>
            <namespaces>
                <!-- snip... -->
                <add namespace="MvcWebControls"/>
            </namespaces>
        </pages>
    </system.web>
    <!-- snip... -->
</configuration>

I’ve hidden most of the Web.config from this example, so make sure to add the areas you see above, not simply replace your entire config.

The rest of this post goes over some demos found out on my website, you may want to follow along to better understand what is going on.

Example 1 — Simple Postbacks

<html>
    <head runat="server">
        <title>Simple Postback Example</title>
    </head>
    <body>    
        <h2>Just A Simple Form</h2>
        <% this.Html.WebForm((form) => { %>        
            <% form.RenderControl(new TextBox()); %>        
            <% form.RenderControl(new Button() { Text = "Save" }); %>
            <hr />
            <% form.RenderControl(new Calendar()); %>
        <% }); %>    
    </body>
</html>

For the first example, we want to see if we can use a few simple WebControls and see if our values are posted back the way we would expect. In this example we add a TextBox, Button and Calendar. Pay attention to how this HtmlHelper method works.

If you notice, the method excepts a delegate to render the control onto the page. We do it like this because it allows us to provide markup to our page along side with the WebControls. The method accepts a single parameter the MvcWebForm. Think of this as a very, very simple version of a WebForm.

The MvcWebForm gives you access to the page that is being used to render the controls. This is important to remember and I’ll go over it in the next section.

Example 2 — Using Events

This is handy so far but unless we are using some events for our controls, nothing much has changed. Let’s look at another example.

<html>
    <head runat="server">
        <title>Using Events</title>
    </head>
    <body>    
        <h2>Simple Button Click Event</h2>
        <% this.Html.WebForm((form) => { %>        
            <strong>Clicked : </strong>
            <% Label text = form.RenderControl(new Label() { Text = "0" }); %>
            
            <br /><br />            
            <% Button submit = form.RenderControl(new Button() { Text = "Add" });
               submit.Click += (s, e) => {
                   int value = 0;
                   int.TryParse(text.Text, out value);
                   text.Text = (++value).ToString();
                   
                   //post back this information
                   form.Page.ClientScript.RegisterStartupScript(
                       typeof(Page),
                       "confirm",
                       string.Format("alert('Updated to {0}');", text.Text),
                       true
                       );
               }; %>
        <% }); %>    
    </body>
</html>

In this example we are assigning a Click event to the button we added to the page. You’ll notice when we run this example the value is incremented up by one on each press.

Notice that we use form.Page instead of this.Page. When you use this code you must remember that you are working with two separate Page instances. One for the View and the other for rendering the control. In this example we use RegisterStartupScript to display an alert box. If you were to have used this.Page.ClientScript, nothing would happen.

It’s a subtle difference that you are going to want to keep in mind while you use this class.

Example 3 — MvcControlGroup

So far all of our examples have only used a couple controls that were all rendered inline with the rest of the page. While this is going to work in most situations, some places won’t work as well.

The example below shows how you can use the MvcControlGroup to group controls together, for example, the Wizard control.

<html>
    <head runat="server">
        <title>Using Events</title>
    </head>
    <body>    
        <h2>Using Wizard Control with MvcControlGroup</h2>
        <div>
        <% this.Html.WebForm((form) => { %>
        <mvc:MvcControlGroup runat="server" >
        <asp:Wizard runat="server" >
            <WizardSteps>
                <asp:WizardStep runat="server" Title="Personal Information" >
                    <p>Leaving fields blank will catch the validators.</p>
                    <strong>Name</strong>
                    <asp:TextBox ID="name" runat="server" />
                    <asp:RequiredFieldValidator runat="server" 
                        ControlToValidate="name" ErrorMessage="Must provide a name" />
                    <br /><br />
                
                    <strong>City</strong>
                    <asp:TextBox ID="city" runat="server" />
                    <asp:RequiredFieldValidator runat="server" 
                        ControlToValidate="city" ErrorMessage="Must provide a city" />                    
                </asp:WizardStep>
                
                <asp:WizardStep runat="server" Title="Reservation Date" >
                    <strong>Date Requested</strong>
                    <asp:Calendar ID="date" runat="server" />                 
                
                </asp:WizardStep>
                
                <asp:WizardStep runat="server" Title="Confirm" >
                    
                    <h2>Confirm This Order?</h2>
                    <p>This step maps to a Controller Action before submitting</p>
                    
                    <% MvcWebForm.Current.Action = "/Projects/MvcWebForms/Submit"; %>
                    <% MvcWebForm.Map(() => new {
                        name = name.Text,
                        city = city.Text,
                        date = date.SelectedDate.ToShortDateString()
                       }); %>
                       
                </asp:WizardStep>
            </WizardSteps>
        </asp:Wizard>
        </mvc:MvcControlGroup>
        <% }); %>
        </div>
        
    </body>
</html>

Just like with other controls, the MvcControlGroup must be rendered in a separate page instance. This control moves it to the correct context before it is processed.

If you remember, the idea behind this project was to allow people to use WebControls with Mvc — not just use WebControls in Mvc. On the last step we point our form to a Controller Action and use a method called Map to format our information for the postback.

When the user finished the Wizard they can post the finished form back to the correct Controller Action!

**whew** — that’s a lot to take in!

Limitations

There are a couple limitations that still need to be worked through…

  • HTML output must be well formed – If your control outputs bad HTML, this thing will croak. The reason is that instead of using Regular Expressions to try and match content the output is parsed using the XDocument.
  • PageMethods, AJAX calls will probably not work – Controls like the UpdatePanel or using PageMethods will most likely not work anymore. Some additional work is going to be required to make those work.

I’m sure there is more that needs to be looked at but at this point it seems as if it can be used — at least for testing.

Please let me know if you have any ideas, feedback or suggestions! I’m going to continue to work on this and see what kinds of improvements can be made.

Source Code

Download MvcWebForms.zip

.

Written by hugoware

August 12, 2009 at 8:58 pm

Include Stylesheets and Scripts From A WebControl In MVC

with 8 comments

As of MVC2 this code may not work anymore – Check here for updated code.

Have you ever created a WebControl in MVC and though “Gee, it sure would be nice if I could add a stylesheet/script to the header of my page.” It’s not as easy as it used to be. Lets just pretend you ran this code right here.

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<html>
    <head runat="server">
        <title>Just A Test</title>
    </head>
    <body>
        <% Page.Header.Controls.Add(
            new LiteralControl(
                @"<script src=""/script.js"" type=""text/javascript"" ></script>"
                )); %>
    </body>
</html>

It would compile and run just fine but you wouldn’t see your script! That’s because the page life-cycle has come and gone and you’re in the middle of the page render! We’re too late!

Inline code doesn’t make it easy to communicate with other parts of the page. As far as I can tell, inline code is rendered in the same order that it appears on the page (or at least, parsed), so once you finally get to the end of the page, the code at the start has already been executed.

A Workable Solution

I’ve included some code at the end of this post that simplifies the whole process and for the remaining of this post I explain how it works. In an effort to solve this problem I ended up coming up with two extension methods that are attached to the HtmlHelper.

InsertMarker(id) : Creates a point on the page that will render any content that is added to it. Uses the id provided (either an enum or a string)

AppendToMarker(id, content) : Appends the string content to the matching marker id (either an enum or a string)

These methods allow marker points to be added to the page inline and then content appended to each marker, regardless of where they are used. Let’s look at an example of the code. If this code doesn’t make sense just yet, don’t worry — I’ll explain 🙂

A Simple Example

Lets use this code to add a script to the header of our page — but from within a WebControl.

[Index.aspx (the View)]

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<html>
    <head runat="server">
        <title>Just A Test</title>
        <% this.Html.InsertMarker(Document.Head); %>
    </head>
    <body>
        <% this.Html.RenderPartial("SomeControl"); %>
    </body>
</html>

[SomeControl.ascx (the WebControl)]

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% this.Html.AppendToMarker(
    Document.Head,
    @"<script src=""/script.js"" type=""text/javascript"" ></script>"
    ); %>

As you can see, we can pick the name of the marker that we want to append content and it is added to the page — all from within our WebControl! You can define your own custom markers and append content to really anywhere you want on the page. If the marker isn’t found, then the content is never rendered.

How It Works (The Short Version)

Once we’re in the middle of our render event for our page it makes it quite difficult for us to make many changes to the rest of the document. This is where the HttpContext.Response.Filter stream comes in handy. With this stream we’re able to intercept all of the content before it is really sent out.

Each time we set a marker onto the page we place a bit of text to mark it as a point we need to replace before we push the content out. I had preferred the idea of remembering the position of the output stream, but apparently the output stream is written to all at once which took that out of the picture.

Once we’re done its as simple as using a Regular Expression and replacing all of the markers with the correct content.

MVC-ish – Kinda Sorta…

This may not have been what the guys who designed MVC were thinking of when they created it, but the ability to work with multiple areas of the page was definitely a feature that I felt was missing. How could something like this help you with your projects?

Source Code

ContentMarkerHtmlHelper.cs (Source)

.

Written by hugoware

July 28, 2009 at 1:57 am

Enums, Flags and C# — Oh my! (bad pun…)

with 12 comments

New Code! An updated blog post on this topic can be found here!

I’m not sure about everyone else, but I just love Enumerated types. Whats more, I love the Flags Attribute when you combine them together. This post explores how you can use these two things along with Extension Methods to make your code more compact and easier to understand.

If you’ve never used this combination before, then you’re missing out. Consider the following code…

class User {
    bool CanDelete;
    bool CanRead;
    bool CanWrite;
    bool CanModify;
    bool CanCreate;
}

Okay, so that’s no big deal even though it may be quite a few extra lines of code. It would be nice to be able to combine all of those permissions into a single value. That’s where an Enumerated Type with a FlagAttribute comes in.

[Flags]
enum PermissionTypes : int {
    None = 0,
    Read = 1,
    Write = 2,
    Modify = 4,
    Delete = 8
    Create = 16,
    All = Read | Write | Modify | Delete | Create
}

//and the class from before
class User {
    PermissionTypes Permissions = PermissionTypes.None;
}

Excellent…. so now what?

So now whats great about this is now we can assign multiple values onto the same property. Not only that, but we can also check for existing values with a (strange) comparison.

//create a new user
User admin = new User();
admin.Permissions = PermissionTypes.Read 
    | PermissionTypes.Write 
    | PermissionTypes.Delete;

//check for permissions
bool canRead = ((PermissionTypes.Read & admin.Permissions) == PermissionTypes.Read);
bool canWrite = ((PermissionTypes.Write & admin.Permissions) == PermissionTypes.Write);
bool canCreate = ((PermissionTypes.Create & admin.Permissions) == PermissionTypes.Create);

//and the results
Console.WriteLine(canRead); //true
Console.WriteLine(canWrite); //true
Console.WriteLine(canCreate); //false

Now shorter and easier to read — sorta. See that really odd comparison? That’s what you need to write each time you want to check for a value. It’s not that bad, but it isn’t really something I’d like to type very often. You could write a separate function to do these comparisons for you, but we can do even better than that.

Taking Advantage Of Extension Methods

Since an Enumerated type isn’t really a class you can’t extend methods onto them. However, you can extend methods onto the class System.Enum. Methods added to this class will appear in the methods for all of your enumerated types!.

Here is an example method…

//full class included at the end of the post
public static class EnumerationExtensions {

        //checks to see if an enumerated value contains a type
        public static bool Has<T>(this System.Enum type, T value) {
            try {
                return (((int)(object)type & (int)(object)value) == (int)(object)value);
            } 
            catch {
                return false;
            }
        }
}

Now, this code does make an assumption that it can cast your Enumerated Type to an integer. You could do some type checking before you do the comparisons, but for the sake of this example, we’re going to keep this short.

So just how do you use this extension?

//start with a value
PermissionTypes permissions = PermissionTypes.Read | PermissionTypes.Write;

//then check for the values
bool canRead = permissions.Has(PermissionTypes.Read); //true
bool canWrite = permissions.Has(PermissionTypes.Write); //true
bool canDelete = permissions.Has(PermissionTypes.Delete); //false

Now that is much easier to read! Even better, you’ll notice despite the fact this has a Generic parameter, we don’t have to provide the type at the start since the method can infer it from the parameter (implicitly typed parameters — sweeeeet!)

And don’t forget, System.Enum isn’t the only class you can do this with, there are other classes (like System.Array for example) that you can add your own extension methods to for surprising results!

Below is the full source code for the EnumerationExtensions class. If you have any improvements, please let me know!

namespace Enum.Extensions {

    public static class EnumerationExtensions {

        //checks if the value contains the provided type
        public static bool Has<T>(this System.Enum type, T value) {
            try {
                return (((int)(object)type & (int)(object)value) == (int)(object)value);
            } 
            catch {
                return false;
            }
        }

        //checks if the value is only the provided type
        public static bool Is<T>(this System.Enum type, T value) {
            try {
                return (int)(object)type == (int)(object)value;
            }
            catch {
                return false;
            }    
        }

        //appends a value
        public static T Add<T>(this System.Enum type, T value) {
            try {
                return (T)(object)(((int)(object)type | (int)(object)value));
            }
            catch(Exception ex) {
                throw new ArgumentException(
                    string.Format(
                        "Could not append value from enumerated type '{0}'.",
                        typeof(T).Name
                        ), ex);
            }    
        }

        //completely removes the value
        public static T Remove<T>(this System.Enum type, T value) {
            try {
                return (T)(object)(((int)(object)type & ~(int)(object)value));
            }
            catch (Exception ex) {
                throw new ArgumentException(
                    string.Format(
                        "Could not remove value from enumerated type '{0}'.",
                        typeof(T).Name
                        ), ex);
            }  
        }

    }
}

Written by hugoware

June 13, 2009 at 2:59 am

Free Bandwidth For All ASP.NET Users

with 7 comments

That’s right, you read it correctly – free bandwidth. With a very short function we’re going to minify our output.

Makes me think of a song, but I don’t want to ruin the rest of the post.

When people render their WebForms and MVC Views, they send their finished HTML back down to the page. The HTML contains all the markup required to run in the browser. Every developer knows all this though (and if not… well…).

Part of the whole grand ASP.NET pipeline is the Response.Filter. A seemingly innocent property with a lot of potential. Enough boasting about this guy, let’s get onto the code and see what it can do.

First, you’re going to need to create a custom stream. I’m hiding all the inherited members because they aren’t going to mean much in this example, but don’t forget that you need them.

With our custom stream, add a hidden property called the UnderlyingStream (honestly call it whatever you want). Lastly, accept a stream in the constructor and assign it to the underlying stream when you instantiate the new stream you’re building.

Lastly, we’re going to override .Write() routine to actually minify our output. A couple simple Regular Expressions and we can chop out most of the whitespace.

public class MinifyFilter : Stream {

//inherited members from Stream class – Don’t forget
//See download for more information
//…

//The real output stream
private Stream _UnderlyingStream;

//Make sure to pass in the current Response.Filter
public MinifyFilter(Stream stream) {
this._UnderlyingStream = stream;
}

//Override our write event
public override void Write(byte[] buffer, int offset, int count) {

//clean out the whitespace characters
string html = Encoding.UTF8.GetString(buffer);
html = Regex.Replace(html, @”\n|\t”, ” “);
html = Regex.Replace(html, @”>\s+<", "><").Trim(); html = Regex.Replace(html, @"\s{2,}", " "); //write the new html byte[] output = Encoding.UTF8.GetBytes(html); this._UnderlyingStream.Write(output, 0, output.Length); } } [/sourcecode] This is a very streamlined version of the code that doesn't take everything into account. You might want to put some special attention into preventing formatting of text in the <pre> tags or <code> tags, but it's a great start. Now using it is as simple as... [sourcecode language='csharp'] //MVC Example: At the start of a controller action public ActionResult Index() { this.Response.Filter = new MinifyFilter(this.Response.Filter); //...rest of the action return this.View();  } //WebForms Example: At the Page_Init protected void Page_Init(object sender, EventArgs e) { this.Response.Filter = new MinifyFilter(this.Response.Filter); //rest of the Page_Init code } [/sourcecode] You could also assign this to a more global event that runs for all requests, but at that point you will need to write code to make sure you don't accidentally minify something like an image or a file (things that can't be compressed by just removing white-spaces). You might wonder how much a little script like this would save. The answer is simple - It depends. Clearly, pages with a lot of white spaces will find a lot more gain. Sometimes it’s 1 or 2 KBs (which will add up over the course of a month). Sometimes though, especially on larger pages, you can see some real savings.

Here are a few popular sites and their savings

GameSpy 94K – (84K minified)

StackOverflow 119K – (102K minified)

Forums.ASP.net 222K – (154K minified)

Keep in mind that this code isn’t bullet-proof, but instead it’s here to get you started. You can continue to tweak the .Write() method to make sure that your code behaves the way you would like.

With all the savings you get from the extra bandwidth make sure you remember to send me a Coke Zero!

Source Code

Download MinifyFilter.cs

.

Written by hugoware

May 9, 2009 at 4:50 am

jQuery Magic – Why I Love Enclosures

with 15 comments

One thing that I’ve learned I really love in programming is enclosures. I’m amazed that someone, somewhere had the brain power to design something that has some much potential to fail.

In a recent web application I was working on I had to come up with a login screen with a standard username and password. I wanted it to be a user friendly as possible since I knew a large variety of users would be accessing this screen. There isn’t much you can do about a login form – it’s two text fields and a button.

However, if you’ve ever noticed in Vista, there are some password fields that have a check box that let you see what is in the field. It’s handy when you don’t have prying eyes around you or trying to help Grandma enter a password. That seems like it might be handy!

 

Web Based Password Display

 

I wanted to have something similar for the web app I was working on, and with some jQuery magic and those loveable enclosures, it was possible with a single chained command.

$("input[type=password]")
  .each(function(index,input) {
    input = $(input);
    $('<div/>')
      .append(
        $("<input type='checkbox' />")
          .attr("id", ("check_"+index))
          .click(function() {
            var change = $(this).is(":checked") ? "text" : "password";
            var rep = $("<input type='" + change + "' />")
              .attr("id", input.attr("id"))
              .attr("name", input.attr("name"))
              .val(input.val())
              .insertBefore(input);
            input.remove();
            input = rep;
          })
        )
        .append(
          $("<label/>")
            .attr("for", ("check_"+index))
            .text("Show contents of the password box.")
        )
        .insertAfter(input);
      });  

The jQuery worked great. Now, when the fields toggle back and forth between text and password the form will still contain all the information required to postback your information.

You’ll notice that the input variable is assigned to each time the click is handled, overwriting the previous value all while updating for the new value… Javascript designers, wherever you are, simply amazing!

I know that quite a few people are against long jQuery commands, and I agree that readability comes before all else (since we write code for human eyes, not the computer). But there is a certain satisfaction in being able to use the magic of enclosures to cram everything you need into a single jQuery command. This code can be dropped into a page and all the work is done.

In any case, I don’t advocate doing this with all your code, but it is a good exercise in the power of enclosures to see what you can built with a single chained jQuery command.

Written by hugoware

May 6, 2009 at 2:22 am