Hugoware

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

Archive for June 2009

jLinq 2.2.0 Released!

with 14 comments

Ever hear of jLinq. If not, it’s no big deal. Its a personal project of mine to make a LINQ style query language for Javascript. With all these “Web 2.0” applications floating around, the ability to sort, query and manage your records on the client side may become a necessity. Use jLinq with the JSON data you already have and you’ve got quite a combination.

If you haven’t tried it out, there is an online version available you can use to see it in action.

Below are some of the new features in jLinq 2.2.0.

Smarter Comparisons

Let’s say you ran the command below…

jLinq.from(users)
    .less("firstname", 5)
    .select();

Seems simple enough, first names less than 5 characters long?

Nope…

The previous version of jLinq expected certain data types depending on the command. For example, if you used less, lessEquals, greater, greaterEquals, between or betweenEquals then the expected parameter was a number as was the field you were querying against.

In the new version you’ll find code like this when checking values.

//get the the parameter value
value = query.helper.when(value, {
number:function() { return value; },
other:function() { return value.length; }
});

//determine how to check this against the value
return query.when({
string:function() {
return (query.value.length < value); }, array:function() { return (query.value.length < value); }, other:function() { return (query.value < value); } }); [/sourcecode] Instead of making any assumptions, jLinq now checks the types and returns the values required to make the query work. For example, if you use 'less' with a string value, the length property is automatically used instead of the string value itself. jLinq also is more intelligent with different command types. For example, the .contains() used to work with string values only. Now it works with arrays or converts a value to a string then checks the result.

11 New Commands

  • attach(alias, function): Executes and attaches the return value of your function onto the record using the alias name you provice.
  • sum(field): Returns an object with information about the sum of the field name used.
    returns {
    count:the number of records counted,
    result:the sum of all records selected,
    records:the records used to find the sum
    }
  • average(field): Returns an object with information about the average of the field name used.
    returns {
    total:the sum before the average was calculated,
    count:the number of records used,
    result:the average of all records selected,
    records:the records used to find the average
    }
  • max(field): The maximum value found for the field name provided.
  • min(field): The minimum value found for the field name provided.
  • except(collection): Compares a second set of records and only returns records that are not found in the comparison list. Returns a new jLinq object. (example)
  • intersect(collection): Compares a second set of records and only returns records that are found in both lists. Returns a new jLinq object. (example)
  • union(collection): Compares a second set of records and only returns records that are unique in both lists. Returns a new jLinq object. (example)
  • skipWhile(delegate): Skips selecting records until the first ‘false’ result is returned from your function. After that point, all records are selected. Returns an array of results. (example)
  • takeWhile(delegate): Selects records until the first ‘false’ result is returned from your function. After that point, all records are ignored. Returns an array of results. (example)
  • selectMany(collection, compareFunction, selectionFunction): Compares each value of the current query against the provided collection array (example). For each successful comparison a new record is added to your results. If you use your own selection method then you need to write a function similar to function(queryRecord, compareRecord) {. The return value will be added to the list. If no selection method is used, then the following object is returned.
    returns {
    source:the record in the jLinq query that is compared,
    compare:the record in the collection array that is compared
    }

Bug Fixes

There was an Opera bug when you tried to sort records. I’m not sure that I understand why, but basically, there really is a difference between for loops in Opera.

jLinq Testing

If you’re interested in creating your own jLinq extension methods you can now download a series of tests that you can use to determine that your command doesn’t break anything else in jLinq.

Wrapping Up

Whew! You’re still with me? You must be dedicated!

Right now I realize that there still may be some confusion on how to use jLinq. I’m currently working on some screencasts that I can share to help people get started.

If you have some requests on what you would like to see in an upcoming screencast, please send me your ideas and I’ll add them to my list.

Source Code

Download jLinq-2.2.0.js

.

Advertisements

Written by hugoware

June 28, 2009 at 3:04 pm

More jQuery Magic – Search Highlighting

with 9 comments

So at first glance, which browser do you think we’re using in the screenshot below? FireFox? Chrome? IE8?

whatbrowser

It’s actually IE6 and all that search highlighting is done via jQuery!

oh-snap

Now most modern browsers do some sort of highlighting now when you do a “Find On Page” search so this may not be the most incredible jQuery trick you see in your life — but at the very least it’s the most impressive jQuery trick on this page.

Highlighting The Page

If you’re interested in following along, you can view the demo/source code at this page.

In order to search the page we’re going to need to a couple things…

  1. Check for user input.
  2. Use the search phrase and find matching text.
  3. Replace our matches with the new highlighted text.

Let’s jump in.

Checking For Input

jQuery makes it easy to work with events that we’re previously… well… a pain. The .keyup() function allows you to supply a delegate to monitor for changes to your search field. Below is the code you’ll find in the example.

//snip ...

self.input.keyup(function(e) {
	if (self.search) { clearTimeout(self.search); }
	
	//start a timer to perform the search. On browsers like
	//Chrome, Javascript works fine -- other less performant
	//browsers like IE6 have a hard time doing this
	self.search = setTimeout(self.performSearch, 300);
	
});

//snip...

As you can see by the comment, we don’t do the search each time the key goes down. IE6, bless it’s heart, tries it’s best to keep up but it’s a losing battle. Instead, we use a short time out to check for when the search begins. In many ways this is a lot better anyways. It’s fairly transparent to the user and saves undue strain on the browser.

Search And Find

Once we’re ready to search, we need to check the user’s input and format it as required.

//snip...

//create a search string
var phrase = self.input.val().replace(/^\s+|\s+$/g, "");					
phrase = phrase.replace(/\s+/g, "|");

//make sure there are a couple letters
if (phrase.length < 3) { return; }			

//append the rest of the expression
phrase = &#91;"\\b(", phrase, ")"&#93;.join("");

//snip...
&#91;/sourcecode&#93;

If you've read some of my blog before you know that <a href="https://somewebguy.wordpress.com/2009/06/04/complete-control-over-your-webforms-output/">I really like Regular Expressions.... a lot...</a> In this part we use our expressions to format our search phrase. Specifically, we're trimming it down and replacing spaces with "or". This makes sure that any phrase in the box is matched.

You may want to change this depending on your needs, for example, require all values to match, etc...

<h3>Find, Replace, Repeat</h3>

Once we have a valid search phrase, now it's time to actually replace the values on the page. You'll notice that I target specific types of elements since you don't want to search the entire document. Unlike a built in browser search option, this function actually makes changes to the markup. If you we're to highlight a value inside a <code>textarea</code> then you're going to end up with markup instead of a yellow block.

It's worth noting that this version only works with elements that don't have additional markup within them. Links, bold text, spans, etc... they are going to be wiped out by this. I'm working on another version that respects child elements, but for now - be warned.

The code below shows what we're doing to make this change.


//snip...

//find and replace with highlight tags
$("h1, h3, p").each(function(i, v) {

	//replace any matches
	var block = $(v);
	block.html(
		block.text().replace(
			new RegExp(phrase, "gi"), 
			function(match) {
				return ["<span class='highlight'>", match, "</span>"].join("");
			}));
	
});



//snip...

In this example I’m limiting my changes to a couple header tags and paragraphs. This helps me avoid things like my search bar at the top of the page. You could also create a class named .search and use that as a target.

The code starts by removing any existing highlighting classes from the element and then follows up by replacing any matches with a highlight tag.

Practical Uses… (tell me if you think of one)

I’ll admit that this was written just to see what it would look like. Most browsers already have a search on page feature that can be used to achieve the same effect. However, there are a few places that something like this may be handy.

AJAX Search Field
Have a page that searches other pages on the site and shows them as an list below the search field? Why not search the page they are on at the same time and highlight possible results?

Client Side Highlighting
Showing lists of data? Why not highlight matching values when a user hovers over certain buttons and filter options? Give them a preview of things to come?

Highlighting? How About Formatting?
Why just highlight text? Why not use this as dynamic formatting for text? Give users a preview of a change they are getting ready to make when they roll over a button?

Think this could be useful? Who knows! But it just goes to show just how much you can do with just a little bit of jQuery!

Written by hugoware

June 25, 2009 at 11:43 pm

Do You Have A Pet Project

with 2 comments

I’ve noticed that there has been some debate about the value of a programmer based on what they do with their free time. Strangely enough, it seems that a lot of value is placed on a person who leaves a 8 to 10 hour shift of programming just to return to their home and continue into the night hacking out lines of code.

I agree with the side that says when you get home you need to turn it off. You need to clear your mind for a few hours before you go back into work the next day and do it all over again…

Well, I agree with it in principle, but that’s about it… 🙂

Having A Pet Project

You may have noticed the project I was working on called jLinq, the Javascript Query Language. I’m still working on that project, trying to improve it and make it better. Better argument handling, performance tweaks, new extension libraries — etc. As much fun as writing a query language can be, there are more entertaining projects a person could be working on.

Since I was a kid, I was always into art and stuff – Never quite good enough to go professional, but good enough to get a decent job being a designer/programmer. I actually got into programming so I could make a video game (no surprise there, huh?)

I can say attempts A through G failed miserably — but the funny thing is that along the way I got a lot better at programming to the point I’ve got a career doing it.

Recently, I thought I’d give the game idea another shot.

//TODO: Come up with a game title

I’ve only been on this project about two weeks now, but here are some screenshots of the current game. It’s built in Flash, using ASP.NET MVC for the server side programming.

screenshot 1

screenshot 2

screenshot 3

screenshot 4

It’s funny, programming a game is so much easier with 8 years of software development under your belt!

Do You Have A Pet Project?… Well, Do Ya?

I really do agree you should clear your mind of programming once you get home — but I wouldn’t have gotten into my career if I followed that rule. Tinkering around with a small pet project can open doors for you that you never even knew were there!

Do you have a pet project — because if you do it may just lead you into your next career!

Written by hugoware

June 23, 2009 at 3:31 am

WebForms And MVC In Harmony — Almost…

with 6 comments

Check out a new post about using WebControls inline with MVC that actually works with postbacks!

Pop Quiz – What happens with the following snippet of ASP.NET code?

<% int number = 5; %>
<asp:PlaceHolder runat="server" >
<% =number %>    
</asp:PlaceHolder>

Prints the number 5? Nope. Maybe it equals zero? Sorta. How about this…

Compiler Error Message: CS0103: The name ‘number’ does not exist in the current context

Yikes…

I’ve complained before about the disconnect between WebControls and actual inline code. WebControls are still a very convenient way to write templates but because they exist in a different context than inline code they are effectively off limits. As cool as MVC is you’re pretty much stuck throwing all your existing WebControls out the window. Or are you?

Using Extension Methods Instead of Controls

Extension Methods came in really at the best time possible. I can’t see MVC working without them.

If you’ve never used one before, an Extension Method lets you create a static method else where in your project, do a couple fancy assignments and then it attaches that method onto the class you’re targeting. LINQ heavily relies on Extension Methods to provide such a seamless programming experience.

One way that ASP.NET MVC uses Extension Methods is to make working with certain control types easier. For example there is a method to create the input tag, one to render a form tag, etc…

Below is an example of how you could create an Extension Method that is attached to the HtmlHelper.

public static class MyExtensionMethods {

    //example method - don't write things this ugly
    public static string BulletList(this HtmlHelper helper, params string[] items) {
        return string.Concat(
            "<ul><li>",
            string.Join("</li><li>", items),
            "</li></ul>"
            );
    }
}

In our example we create a static class to house our Extension Methods. We also create static methods with a strange argument at the start. This argument is actually the class were attaching the method to. Now we can use our code like so…

<% =this.Html.BulletList("Apple", "Orange", "Pear") %>

Cool. If you’re not familiar on the things you can do with Extension Methods then I recommend you read about them some more before you start trying to add them to your project. You could also use delegates to simulate templating within an Extension Method.

public static class MyExtensionMethods {

    //example method - renders the content of each action
    public static void TwoColumns(this HtmlHelper helper, Action left, Action right) {
        HttpContext.Current.Response.Write("<div class='left'>");
        left();
        HttpContext.Current.Response.Write("</div>");
        
        HttpContext.Current.Response.Write("<div class='right'>");
        right();
        HttpContext.Current.Response.Write("</div>");
    }
}

Then you can use your “template” like so…

<% this.Html.TwoColumns(() => { /* Left Column */ %>
    I'm on the left!
<% }, () => { /* Right Column */ %>
    I'm on the right!
<% }); /* End Two Column */ %>

Code like this can get ugly in a hurry – so be conservative in your use.

Using IDisposable To Close Tags

Another way you can create a “WebControl” with ASP.NET MVC is to create a class that implements IDisposable. By placing markup in the constructor and the Dispose method you can essentially write your RenderBeginTag() and RenderEndTag() methods you normally find on CompositeControls!

public class StyledHeader : IDisposable {

    public StyledHeader(string color) {
        HttpContext.Current.Response.Write("<h1 style='color:" + color + "' >");
    }

    public void Dispose() {
        HttpContext.Current.Response.Write("</h1>");
    }
}

Naturally, StyledHeader should have been added to the core of the ASP.NET MVC library, but somehow it got missed :). In any case, our class can be used with the using keyword to render our fancy new header.

<% using (new StyledHeader("#f00")) { %>
    Howdy - This is my header control!
<% } /* End StyledHeader */ %>

The Super Secret Final Method

As you noticed at the beginning of my post I mentioned about throwing away WebControls since they aren’t any use to us anymore. Well, that isn’t true — We can still use WebControl with our inline code for the page!

If you’ve read any of my previous blog posts, you can see that I’m a big fan of overriding the Render() method for WebControls. In similar fashion, we’re going to use the RenderControl() method to render our WebControls right when we need them.

using System.Reflection;
using System.IO;
using System.Web.UI;
using System.Web;
using System.Web.Mvc;

public static class MyExtensionMethods {

    //example method - renders a webcontrol to the page
    public static void RenderControl(this HtmlHelper helper, Control control) {

        //perform databinding if needed
        //MethodInfo bind = control.GetType().GetMethod("DataBind");
        //if (bind is System.Reflection.MethodInfo) {
        //    bind.Invoke(control, null);
        //}

        //Call a courtesy databind
        //Thanks for pointing it out Richard
        control.DataBind();
        
        //render the HTML for this control
        StringWriter writer = new StringWriter();
        HtmlTextWriter html = new HtmlTextWriter(writer);       
        control.RenderControl(html);

        //write the output 
        HttpContext.Current.Response.Write(writer.ToString());
        
        //and cleanup the writers
        html.Dispose();
        writer.Dispose();         
    }

}

You may notice the courtesy DataBind() call we’re doing there — Just in case something has a DataSource I was calling the method as well. Depending on how you use this you may want to change this some. But enough of that, how is it used?

<% int&#91;&#93; numbers = { 1, 2, 3, 4, 5 }; %>
<% this.Html.RenderControl(new DataGrid() { DataSource = numbers }); %>

You can also define your class before you pass it into the RenderControl method in case you need to do a little more to it than just assign some values to the properties.

Finally, WebForms and MVC In Harmony… Or Maybe Not…

Now I won’t pretend that you can plug all of your WebControls into this and expect it to work like WebForms used to. A lot of things are missing that a lot of WebControls rely on (like the ViewState). But, if your mainly interested in the rendered output of a WebControl then you’re in luck.

Written by hugoware

June 18, 2009 at 2:11 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

The One Thing All Browsers Have In Common

leave a comment »

As it turns out, all browsers actually have one thing in common – NONE of them behave the same.

Sadly enough, I was notified by someone last night that Opera doesn’t handle OrderBy quite correctly in jLinq.

sorry sir, I’m boyr.
I sent three feedback to say some bugs about “orderby”.
I make a mistake, the real bug is that “orderby” DOES NOT work correctly in Opera sometimes! NO problem in IE or FireFox.
You can try in Opera with follow codes[juest like codes on your homepage]:
var results = jLinq.from(data.users)
.startsWith(“first”, “a”)
.orEndsWith(“y”)
.orderBy(“age”)=========>>>only remove “admin”;
.select();

Not exactly what I was hoping to read. For the love of Pete, AT THE VERY LEAST can the JavaScript cooperate?

Anyways, I’m presently working on the fixes now – I’m sure I’ll no doubt be missing some hair and much more stressed than before.

Cross browser compatibility Pain and CSS hacks eternal suffering, as is the life of a Web Developer.

You can quote me as the guy who coined that — 🙂

Written by hugoware

June 8, 2009 at 11:16 pm

Complete Control Over Your Webforms Output

with 4 comments

I like Regular Expressions… a lot. I know I’m not an expert with them, but even an amateur can do some pretty amazing things with just a couple Regular Expressions.

WebForms has always been a little… messy with it’s output. Your page is normally littered with a bunch of excessively long ID’s and name on content that doesn’t really need it (for example, I saw a vendors program with this little gem in it accounts_overview_body_quickAction_quickActionTitleLabel all for a span element).

You’re also stuck with the ViewState, which can get out of control in a hurry. You can disable it, but it still renders some content no matter what. It might not be that much, but when you don’t need it you may prefer it to be gone.

One of the last annoying things about WebForms is that you can’t put additional forms within your Page level form. Some browsers don’t mind, but others won’t work at all. If you didn’t need the WebControls to do anything (like persist their state) it would be nice to be able to drop them completely.

Get Control Over Your Page

Like I mentioned at the start, by overriding the Render event on a page you can have full access to your output before it gets sent down to the user. I posted some code about this before when I talked about minifying your content. If you read that post then you’ll have a general idea where this is heading.

The first step is to actually render our content so we can manipulate it. Without getting into too much detail we’re going to write our content to our own local HtmlTextWriter so we can manipulate it before we send it to the actual HtmlTextWriter. It’s not hard to do…

protected override void Render(HtmlTextWriter writer) {

    //render our output
    StringWriter output = new StringWriter();
    HtmlTextWriter html = new HtmlTextWriter(output);
    base.Render(html);

    //get the rendered string
    string rendered = output.ToString();

    //Make our changes
    //... discussed shortly

    //cleanup our writers
    html.Dispose();
    output.Dispose();

    //then write it
    writer.Write(rendered);
}

Pretty cool, right? We’ve got our string, now we can get started making our changes.

Drop The ViewState

Some pages you have really just don’t need the ViewState at all. Maybe it’s some product information or maybe a few photos, but there aren’t any controls on the page that the user is going to post back. It doesn’t take much to write a regular expression to remove it.

rendered = Regex.Replace(
    rendered, 
    "<input.*name=\"__VIEWSTATE\"&#91;^>]*>", 
    string.Empty, 
    RegexOptions.IgnoreCase
    );

That little snippet of code will drop the ViewState completely from the page. You could modify it a little further to drop other things (like the __EVENTSTATE) by changing the expression to "<input.*name=\"__\\w+\"[^>]*>".

Knock Out The Page Form

As I said earlier in the post, if you want to have other forms on your page then they have to be outside of the Page Form. Not all browsers work with nested forms.

With WebForms, you can have a Page Form, use all your controls inside and then drop the markup before it is sent to the client. That way you can use WebControls and nested forms.

This process is naturally a little more complicated.

//find all the forms and closed elements
MatchCollection matches = Regex.Matches(
    rendered, 
    "</?form&#91;^>]*>", 
    RegexOptions.IgnoreCase
    );

//create the expression to match for the ID
//master pages rename the form to 'aspnetForm' -- weird
Regex expectedId = new Regex(
    string.Format("id=\"?({0}|aspnetForm)\"?", this.Form.ID), 
    RegexOptions.IgnoreCase
    );

//expression to check for a close of a form
Regex closeForm = new Regex(
    @"</\s?form\s?>",
    RegexOptions.IgnoreCase
    );

//loop through and remove the page form
Match open = null;
Match close = null;
int depth = 0;

//we're checking for the open form THEN checking for the 
//matching close tag (checking for nesting)
for (int i = 0; i < matches.Count; i++) {
    Match match = matches&#91;i&#93;;

    //check if this is the page form
    if (expectedId.IsMatch(match.Value) && !(open is Match)) {
        open = match;
    }

    //if we aren't tracking yet, just continue
    if (!(open is Match)) { continue; }

    //change the direction of the nesting
    depth += closeForm.IsMatch(match.Value) ? -1 : 1;

    //if the nesting is back to zero we can assume this 
    //is the correct tag
    if (depth == 0) {
        close = match;
        break;
    }

}

//remove the tags - make sure to start with the close tag
//since this will affect the index of the Matches
if (open is Match && close is Match) {
    rendered = rendered.Remove(close.Index, close.Length);
    rendered = rendered.Remove(open.Index, open.Length);
}
&#91;/sourcecode&#93;

With this code we can remove the Page Form from the page, but preserve all of the other forms so they can handle their postbacks however the see fit.

It's worth noting though, like removing the ViewState, postbacks and WebControls that rely on these features will most likely no longer work (or at least as expected).

<h3>Shorten Your IDs</h3>

ASP.NET 4.0 is going to offer some nice features to help developers push meaningful ID's down to the client. Right now IDs are generated by using the parents, parents, parents, etc, ID. It's great to avoid naming collisions - but it's horrible if you're trying to do anything client side. Not only that, but sometimes you end up with IDs on elements that you have no intention of working with so it's just wasted space.

Again, with a little Regular Expression magic, we can make changes to the IDs on our page.


//lastly, drop any unwanted IDs
MatchCollection extraIds = Regex.Matches(
    rendered, 
    @"<&#91;^>]*actualId=""(?<id>[^""]*)""[^>]*>", 
    RegexOptions.IgnoreCase
    );

//loop backwards to avoid affecting indexes on the matches
for (int i = extraIds.Count; i-- > 0; ) {
    Match extra = extraIds[i];

    //drop the unwanted parts
    string newElement = extra.Value;
    string newID = extra.Groups["id"].Value;

    //lastly, remove the actual ID field
    newElement = Regex.Replace(
        newElement, 
        @"actualId=""[^""]*"" ?", 
        string.Empty, 
        RegexOptions.IgnoreCase
        );

    //if the ID is blank, just remove it                
    newElement = Regex.Replace(newElement, @"(id|name)=""[^""]*"" ?", (str) => {
        if (string.IsNullOrEmpty(newID)) { return string.Empty; }
        return string.Concat(
            str.Value.StartsWith("id", StringComparison.OrdinalIgnoreCase) ? "id" : "name",
            "=\"",
            newID,
            "\" "
            );
    });

    //finally, replace the new string
    rendered = rendered.Remove(extra.Index, extra.Length);
    rendered = rendered.Insert(extra.Index, newElement);

}

Clearly, this is a custom solution to say the least. The idea here is that we can now add the property “actualId” onto our controls and the id and name attributes will be updated to reflect that value. Additionally, our actualId attribute will be removed completely from the element.

You could adjust the code a little more to grab up all IDs that aren’t flagged in some way to retain their ID.

Absolute Power Corrupts

It is fun to get in to your rendered output and make changes to what is sent to the client. You have a lot of power to completely change what your content looks like. But be careful – the more you change, the more likely you are to break the way ASP.NET works.

If you come up with some cool ways to use this, let me know!

Note: As the commenter below noted, this doesn’t work with UpdatePanels — at least not without more work. The content from UpdatePanels is delimited with pipes and has character counts for the content with all of the IDs it is returning (I haven’t used them in a while so this is from memory). It would be pretty tricky to make changes without breaking anything (but not impossible!!).

Written by hugoware

June 4, 2009 at 3:03 am