Denny.NET

I can haz ASP.NET goodness?

About the author

Denny Ferrassoli
Developer at Casting Networks. MCP / .NET
E-mail me Send mail
Add to Technorati Favorites

Recent comments

Authors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008

UpdatePanels: When and Where

I've been using the ASP.NET AJAX Update Panels for quite some time now and have picked up a lot of tips on when and how to use them. Update Panels were intended to allow the developer to do Partial Page Updates. Usually what you see is Update Panels updating nearly the entire page which completely defeats the purpose of Update Panels!

Here are some good tips to take into account when developing with Update Panels:

#1. One thing I notice is that people want to stuff all their functionality into one page with multiple hidden/visible panels. Then utilize the functionality by showing/hiding the panels based on actions within the page. This can lead to very confusing code...

If you're changing from one action which does a lot of functionality with X to an action which does a lot of functionality with Y then separate the functionality and use a page postback to switch between those pages. Don't throw everything together into one update panel and separate it by hidden panels. You'll end up with a ton of code which is not resuable and difficult to understand. Separate your functionality just like you would separate your DAL, BL and Presentation.

Example for an Admin section:
  • User Management (insert, update, delete users)
  • Settings (change your web app's settings)
  • Media Management (insert, update, delete media)
  • etc...

#2. Separate your Update Panels. Instead of throwing everything into one update panel break it up! Plan what areas of your page will need to update and what will trigger them to update. This will save you an insane amount of bandwidth (and download time) and return much better performance.

Example:
Lets say you have 3 areas on your page that will allow a user to: select a category, select a video and then watch the video.

  • Part 1 displays a list of categories
  • Part 2 displays a list of videos within that category
  • Part 3 displays a video player

Lets think logically about the flow of execution with the 3 parts. First a user picks a category in Part 1. Then they select which video they want to watch in Part 2. And finally the video displays in Part 3 and begins playing.

So there are 2 steps involved to watch a video:

  1. Pick a category
  2. Pick a video


And 2 triggers:

  1. "Click" a category
  2. "Click" a video



(Each arrow represents a click)

So we've got the basic idea down now how do we determine WHERE we need update panels? We need to determine what parts change. The only parts that change are Part 2 which shows a list of videos within the selected category and Part 3 which plays the selected video. Part 1 will not change because nothing within that part changes. Part 1 is only used to select a category and the categories are loaded at Page_Load.

(Of course if you added paging or sorting to Part 1 you could then use an update panel but for this example Categories are static.)

So you have 2 parts that change meaning you only need 2 update panels, one for Part 2 and one for Part 3. Now how do we trigger these updates? Based on the flow we determined above we know what triggers are needed...

Triggers:

  • Part 2 needs to update when a category is selected from Part 1.
  • Part 3 should update when a video is selected from Part 2.

We also want to hide the video player when the user selects a new category because it wouldn't make sense to continue showing a video from the "Comedy" category after they selected the "Drama" category. So we'll need one more trigger:

  • Part 3 should update when a category has been selected since we don't want to display the old video when they select a new category.


(Each arrow represents where the item is triggered from [start of line inside part] and what part it affects [end of line])

And that's all we need to properly separate our update panels. The cool thing about upate panels is that your trigger control does not need to be within the same update panel. In other words, it can be located anywhere on your page outside the update panel. That's why we only need 2 update panels. The triggers in part 1 can be set programatically or through the update panel "triggers" GUI from the properties menu.

Quick Tip: If you want to know how to set a trigger programatically then read this post.

What's the benefit of separating the update panels? Alot of Bandwidth! Update panels respond with their entire rendered contents when doing an AJAX call. Update panels also attach any control viewstates to the response. If you were to place the entire content of the example above in one update panel you'll be uploading and downloading everything every time you do a callback. On the other hand if you separate your update panels, like the example above, you'll only download the contents of the update panel that has been triggered.

Quick Tip: If a control within an update panel does not need viewstate enabled then disable it! This is a good way to decrease the size of the response.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by SuperGhost on Thursday, August 30, 2007 2:19 PM
Permalink | Comments (1) | Post RSSRSS comment feed

TypeWatch: jQuery Plugin

Earlier this week I created a jQuery plug-in that allows you to potentially determine when a user has finished typing in a textbox. I created it for a search textbox on one of my websites so that I could return results by firing some AJAX after they're done typing. It could help with an AJAX auto-complete implementation too.

[UPDATED 11/02/07]

There are 4 settings you can set:

1. callback: The function to callback after the user has "finished" typing. Default void.
2. wait: The number of milliseconds to wait before the plugin considers that typing has finished. Default 750.
3. highlight: Aesthetics, determines if the text should be highlighted when the textbox receives focus. Default true.
4. enterkey: Determines if the ENTER key will fire the callback rather than wait for the timeout. Default true.

How it works:

For each textbox or textarea matched through jQuery it creates a timer which gets reset upon every [KeyDown] event. If the timer's [wait] is reached then the user has finished typing, or stopped typing long enough for the timer to reach its [wait] interval.

The callback will not execute if the length of text is less than 3 characters. Also, if the timer's [wait] interval is reached and the text has not changed it will not execute the callback. So if you change "some text" to "SOME TEXT" the callback will not execute. However if you have set the option enterkey to true, or left it at default, the callback will be executed when the ENTER key is pressed.

You can get the debug and packed version at: http://jquery.com/plugins/project/TypeWatch

The latest version 1.1.0 fixes an issue that any key would cause the callback to execute - including Home/End/Page Up etc... Now it will only fire if the text has changed.

DEMO:

Click here for the Live Demo

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Currently rated 3.7 by 29 people

  • Currently 3.689655/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: Client-Side
Posted by Denny on Friday, August 17, 2007 10:23 AM
Permalink | Comments (25) | Post RSSRSS comment feed

JavaScript Model Objects (JMO) - An Idea

A rough prototype of what I like to call "JavaScript Model Objects" or JMO for short.While playing with ASP.NET AJAX I came across an idea of using AJAX, JSON, and JavaScript to bind data onto page elements. So today I decided to play around and try to create a "repeater" but on the client-side. This is the gist of the idea...

#1. Get the data which I want to bind using AJAX and JSON.

Example JSON data: 

var myTestObj =
{
            "rows":
                        [{"id":1, "title":"Test one", "imagesrc":"images/ajax.gif", "isTest":true},
                        {"id":2, "title":"Test two", "imagesrc":"images/playmini.gif", "isTest":true},
                        {"id":3, "title":"Test three", "imagesrc":"images/playmini.gif", "isTest":true}]
}

In this example the JSON data must have "rows" with an array of the row columns/values.

#2. Define the template that I want to bind to. This is defined directly on my HTML page.

Example:

<table>
            <tr id="JMO1">
                        <td style="border: solid 1px black">!id!</td>
                        <td style="border: solid 1px black">!title!</td>
                        <td style="border: solid 1px black"><img src="!imagesrc!" /></td>
                        <td style="border: solid 1px black">!isTest!</td>
            </tr>
</table>

As you can see I have a table with 4 columns. I want to bind to the TR object so I give my TR an id. The places where I want the data to appear are surrounded by exclamation points, like !<name>!. Also notice that I have given the TR tag an ID of "JMO1" which I will use to pass to my binding function. The TR tag is essentially my "Model Object."

#3. The functions to bind the data to my model object... Please note this is a very rough sketch of the functionality, and yes I am using jQuery:

function initJMO(modelObj, dataObj) {    
        var obj = $(modelObj);
        var data = eval(dataObj);
        var dataMembers = getDataMembers(obj)
                  
        if (dataMembers.length > 0) {
                    // Deep clone the model, save reference
                    //var clone = obj.clone(true);
                    var dataClone = obj[0].outerHTML;
                    
                    for (x = data.rows.length-1; x >= 0; x--) {
                          var thisRow = dataClone;
                                   
                          for (i = 0; i < dataMembers.length; i++) {
                                  var rg = new RegExp("!" + dataMembers[i] + "!"); rg.global = true;

                                  if (dataMembers[i] == "length") {
                                         ev = data.rows.length.toString();
                                  } else {
                                         ev = eval("data.rows[" + x + "]." + dataMembers[i]).toString();
                                  }
                                        
                                  thisRow = thisRow.replace(rg, ev);
                          }

                          obj.after(thisRow);
                    }
                            
                    // Remove model
                    obj.remove();
        }
}

function getDataMembers(obj) {
              var str = obj[0].outerHTML;

              if (str.length > 0) {
                          var rg = /!(\w+)!/g;
                          var match = str.match(rg);
                          var dMembers = [];
                          dMembers.push("length");

                          if (match != null) {
                                      for(i = 0; i < match.length; i++) {
                                            dMembers.push(match[i].replace(/!/g,""));
                                      }
                          }

                          return dMembers;
              } else {
                          return [];
              }
}

$(function() {
              initJMO("#JMO1", myTestObj);
} );

initJMO requires 2 params... 1 is the model object (our TR in this case). 2 is the data object (our un-eval'd JSON). 

initJMO clones the model object, finds all the data members (column names) we want to bind to and then goes through and replaces each !<name>! with the corresponding JSON column's data. It then appends the source of our cloned/replaced element after the model object, thus repeating the data with each row of our data object. Finally initJMO removes the model object from the page.

So what you get is your model object repeated with every row of your data object.

The cool thing about this is you can define ANY element as the model object!Now yes this still needs a lot of work and there are a few issues with it but I'd like to get some feedback. Good idea? Has this been done before?

A sample page can be viewed here: http://www.dennydotnet.com/Test/Default2.aspx

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: Client-Side | Server-Side
Posted by SuperGhost on Friday, August 10, 2007 9:48 PM
Permalink | Comments (19) | Post RSSRSS comment feed

Making Visual Studio and Safari play nice

You know how to set a default browser for debugging: (http://stevenharman.net/blog/archive/2007/08/02/setting-a-default-browser-for-visual-studio.aspx). This works great for most browsers, however if you're in an environment where you have to test with Safari as well... you're out of luck. Apparently Safari doesn't like the way Visual Studio opens the browser window and instead shows the default page. So how do you get Safari to play nice with Visual Studio?

#1. Right-click any folder or page in Solution Explorer and select "Browse With..."
#2. Click "Add..."
#3. Browse to your Safari folder (@:\Program Files\Safari\) and select the "Safari.exe"
#4. Under the "Program name:" textbox you'll see the path to Safari in quotes: "@:\Program Files\Safari\Safari.exe" At the end of the string (outside the quotes) add "-url" so it looks like: "@:\Program Files\Safari\Safari.exe" -url
#5. Click "OK"
#6. You'll get a message that states "File name does not exist, is invalid... Do you want to change your entry?" Make sure you select "NO"

 

You can now highlight Safari and browse to whatever page or folder you selected.

Note* Setting Safari as default will not allow you to start debugging. You'll get an error stating Visual Studio was "Unable to start program..."

There's no fix for the debugging that I am aware of.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: ASP.NET | General
Posted by SuperGhost on Monday, August 06, 2007 2:27 PM
Permalink | Comments (1) | Post RSSRSS comment feed