These Pretzels Are Making Me Thirsty
Code, Life, etc.
Tuesday, November 2, 2010
Monday, August 23, 2010
Client-side Data Binding with jQuery Templates
Client-side data binding via templates is nothing new. But as with all things jQuery, jQuery Templates makes it easier - more flexibility and options with less code. I do believe that this jQuery plug-in is Microsoft's first contribution to jQuery, and it's a yummy one. Here's a small example that shows how to bind user data to a grid:
First, define the grid:
Then define the template for each grid row:
Alright, we are now ready to retrieve our data and bind.
Let's provide some data from the server:
Now let's call GetUsers() via an Ajax call and bind the returned data to our grid/table:
Background colors used for alternating and selected grid rows:
And our resulting grid:
If we examine the rendered HTML, we'll find that the template's markup basically got injected into the <tbody> content:
And that's it really. Simple, clean, fun!
You can download the complete, fully functional solution here. The solution code is organized slightly differently, with most of the client-side script located inside the .js include. This way you can also see how the HTML markup, templates and script implementation (including data binding) can be cleanly separated and organized.
First, define the grid:
<table id="userTable"> <thead> <tr> <th>First Name</th> <th>Last Name</th> <th>Email</th> </tr> </thead> <tbody></tbody> </table>
Then define the template for each grid row:
<script id="tmpl_userList" type="text/html"> <tr class="${alternate(this.data, this.dataSource)}"> <td>${FirstName}</td> <td>${LastName}</td> <td>${Email}</td> </tr> </script>Notice that the class attribute's value is set via javascript function that takes two arguments: the data item (for this particular grid row), and the complete data source, which is a custom parameter being passed into the template (more on that later).
Alright, we are now ready to retrieve our data and bind.
Let's provide some data from the server:
[HttpGet] public JsonResult GetUsers() { JsonResult result = new JsonResult { JsonRequestBehavior = JsonRequestBehavior.AllowGet }; List<User> users = new List<User>(); users.Add(new User { ID = 1, FirstName = "Jennifer", LastName = "Jones", Email = "test1@test.com" }); users.Add(new User { ID = 2, FirstName = "Jason", LastName = "Johnson", Email = "test2@test.com" }); users.Add(new User { ID = 3, FirstName = "Jerry", LastName = "Jones", Email = "test3@test.com" }); result.Data = new JsonResultData { Value = users }; return result; }
Now let's call GetUsers() via an Ajax call and bind the returned data to our grid/table:
$.ajax({ url: 'Home/GetUsers', success: function (response) { if (response.Success) { var data = response.Value; // Use template called tmpl_userList // dataSource is a custom parameter we pass into the template. $.tmpl('#tmpl_userList', data, { dataSource: data }) // Inject data into table userGrid .appendTo($('#userGrid') // Define event handlers for each row .click(function () { var item = $.tmplItem(this); alert(item.data.FirstName + ' ' + item.data.LastName + ' says, "Hi!"'); }) // Toggle row color .hover( function () { $(this).addClass('userRowSelected'); }, function () { $(this).removeClass('userRowSelected'); } ); } } });
Background colors used for alternating and selected grid rows:
.userRowAlt { background-color: #F7F8E0; } .userRowSelected { background-color: #F2F2F2; }
And our resulting grid:
If we examine the rendered HTML, we'll find that the template's markup basically got injected into the <tbody> content:
<table id="Table1"> <thead> <tr> <th>First Name</th> <th>Last Name</th> <th>Email</th> </tr> </thead> <tbody> <tr class="userRow"> <td>Jennifer</td> <td>Jones</td> <td>test1@test.com</td> </tr> <tr class="userRow userRowAlt"> <td>Jason</td> <td>Johnson</td> <td>test2@test.com</td> </tr> <tr class="userRow"> <td>Jerry</td> <td>Jones</td> <td>test3@test.com</td> </tr> </tbody> </table>
And that's it really. Simple, clean, fun!
You can download the complete, fully functional solution here. The solution code is organized slightly differently, with most of the client-side script located inside the .js include. This way you can also see how the HTML markup, templates and script implementation (including data binding) can be cleanly separated and organized.
UPDATE - 10/06/2010:
This jQuery Templates is now an official jQuery plug-in.
Labels:
Ajax,
ASP.NET,
C#,
HTML,
Javascript,
jQuery,
MVC,
templates,
web development
Friday, July 30, 2010
Firefox Slowness with localhost on Vista (or XP with IPv6)
I recently encountered an issue with a web project running locally and VERY slowly loading pages (more specifically images) in Firefox. Thanks to this post by Dan Wahlin, I was able to resolve the problem. Per his post:
It turns out that the slowness is caused by an IPv6 issue with DNS and can easily be resolved by turning IPv6 support off in Firefox while doing localhost testing. To make the change, type about:config in the address bar, locate the network.dns.disableIPv6 setting and double-click on it to set it to true. This does the trick for the Firefox localhost issue on Vista and everything is running fast again.
Tuesday, June 8, 2010
YouTube Deep Linking Inside FBML
There's a cool YouTube API option that let's you jump to any point in the video and start playing from there. For example, to jump 1 minute and 45 seconds into this video:
Now, if you want to do the same thing in your FBML Facebook application, the syntax is slightly different. Let's say you have the following FBML code that embeds a video on a page:
Now instead of #t=1m45s, add &start=105:
http://www.youtube.com/watch?v=-HWECQa23CsJust append #t=1m45s to the end of the URL:
http://www.youtube.com/watch?v=-HWECQa23Cs#t=1m45s
Now, if you want to do the same thing in your FBML Facebook application, the syntax is slightly different. Let's say you have the following FBML code that embeds a video on a page:
<fb:swf swfbgcolor="000000" imgstyle="border-width:3px; border-color:white;" swfsrc='http://www.youtube.com/v/-HWECQa23Cs' imgsrc='http://img.youtube.com/vi/-HWECQa23Cs/1.jpg' width='340' height='270' />
Now instead of #t=1m45s, add &start=105:
<fb:swf swfbgcolor="000000" imgstyle="border-width:3px; border-color:white;" swfsrc='http://www.youtube.com/v/-HWECQa23Cs&start=105' imgsrc='http://img.youtube.com/vi/-HWECQa23Cs/1.jpg' width='340' height='270' />
Thursday, June 3, 2010
SubSonic and Object-Relational Mapping
I love SubSonic (especially the latest 3.x version with T4 template support) and its ability to map data to model objects/data contracts. However, I've hit a bit of a snag when it comes to mapping not just the high-level object properties, but also its (complex type) children.
Say for example I have the following classes defined:
Then using SubSonic, I can run the following fluent query to hydrate a list of users:
However, the problem is that User's Role and Profile properties will remain null - projection mapping FAIL! Now I've spent quite some time googling around for a possible solution to this, thinking that maybe I'll find a "trick" of some sort to have SubSonic auto-magically hydrate all lower-level properties of my User object, without making a bunch of trips to the database and back to hydrate all properties. But I found nothing.
And again, User's Role and Profile properties remained null, while all other simple type properties got set appropriately. Sadly, SubSonic alone couldn't hydrate all my object's children without some assistance.
So, I moved forward with Ben's suggested solution, and it worked beautifully (with some minor tweaks)!
First, define a custom attribute class:
Then, define a projection mapper class, which will do all the leg work for you:
You'll notice there's a slight difference between this definition and the one in Ben's blog. First of all, he's referencing some ReflectionUtil, which I don't have and wasn't sure what it was. So I simply replaced the ReflectionUtil.GetAttributes() call with property.GetCustomAttributes(). Also, I added a DBNull check of the value - better safe than sorry.
Next, you must decorate your objects' properties with the new MapToColumn attribute, to map the properties to the appropriate columns (their names) returned by the database call:
And finally, let's use this bad boy:
The solution is clean and relatively efficient; this makes Kon a happy boy. Again, I must give most of the credit to Ben Scheirman for his help.
Say for example I have the following classes defined:
[DataContract] public class User { [DataMember] public int ID { set; get; } [DataMember] public Role Role { set; get; } [DataMember] public Profile Profile { set; get; } [DataMember] public string UserName { set; get; } [DataMember] public string Password { set; get; } } [DataContract] public class Role { [DataMember] public int ID { set; get; } [DataMember] public string Name { set; get; } } [DataContract] public partial class Profile { [DataMember] public int ID { set; get; } [DataMember] public string FirstName { set; get; } [DataMember] public string LastName { set; get; } [DataMember] public string EmailAddress { set; get; } }
Then using SubSonic, I can run the following fluent query to hydrate a list of users:
List<User> users = db.Select .From<User>() .InnerJoin<role>(RolesTable.Role_IDColumn, UsersTable.Role_IDColumn) .InnerJoin<profile>(ProfilesTable.Profile_IDColumn, UsersTable.Profile_IDColumn) .ExecuteTypedList<User>();
However, the problem is that User's Role and Profile properties will remain null - projection mapping FAIL! Now I've spent quite some time googling around for a possible solution to this, thinking that maybe I'll find a "trick" of some sort to have SubSonic auto-magically hydrate all lower-level properties of my User object, without making a bunch of trips to the database and back to hydrate all properties. But I found nothing.
Ben Scheirman and his SubSonic and Projections blog post to the rescue!
First of, let me work backwards and start with the comments following this blog post. Rob Conery (of SubSonic fame) responded to Ben and suggested using ExecuteSingle(), which should map things appropriately. However, I've tried that as well:User user = db.Select .From<User>() .InnerJoin<Role>(RolesTable.Role_IDColumn, UsersTable.Role_IDColumn) .InnerJoin<Profile>(ProfilesTable.Profile_IDColumn, UsersTable.Profile_IDColumn) .ExecuteSingle<User>();
And again, User's Role and Profile properties remained null, while all other simple type properties got set appropriately. Sadly, SubSonic alone couldn't hydrate all my object's children without some assistance.
So, I moved forward with Ben's suggested solution, and it worked beautifully (with some minor tweaks)!
First, define a custom attribute class:
[AttributeUsage(AttributeTargets.Property)] internal class MapToColumnAttribute : Attribute { private readonly string _columnName; protected internal MapToColumnAttribute(string columnName) { _columnName = columnName; } protected internal string ColumnName { get { return _columnName; } } }
Then, define a projection mapper class, which will do all the leg work for you:
internal class ProjectionMapper { protected internal T Map<T>(IDataReader dr) where T : new() { Type type = typeof(T); T target = new T(); foreach (PropertyInfo property in type.GetProperties()) { foreach (MapToColumnAttribute attr in property.GetCustomAttributes(typeof(MapToColumnAttribute), true)) { object value = dr[attr.ColumnName]; if (!(value is DBNull)) { property.SetValue(target, value, null); } } } return target; } }
You'll notice there's a slight difference between this definition and the one in Ben's blog. First of all, he's referencing some ReflectionUtil, which I don't have and wasn't sure what it was. So I simply replaced the ReflectionUtil.GetAttributes() call with property.GetCustomAttributes(). Also, I added a DBNull check of the value - better safe than sorry.
Next, you must decorate your objects' properties with the new MapToColumn attribute, to map the properties to the appropriate columns (their names) returned by the database call:
[DataContract] public class User { [MapToColumn("ID")] [DataMember] public int ID { set; get; } [DataMember] public Role Role { set; get; } [DataMember] public Profile Profile { set; get; } [MapToColumn("UserName")] [DataMember] public string UserName { set; get; } [MapToColumn("Password")] [DataMember] public string Password { set; get; } } [DataContract] public class Role { [MapToColumn("ID")] [DataMember] public int ID { set; get; } [MapToColumn("Name")] [DataMember] public string Name { set; get; } } [DataContract] public partial class Profile { [MapToColumn("ID")] [DataMember] public int ID { set; get; } [MapToColumn("FirstName")] [DataMember] public string FirstName { set; get; } [MapToColumn("LastName")] [DataMember] public string LastName { set; get; } [MapToColumn("EmailAddress")] [DataMember] public string EmailAddress { set; get; } }
And finally, let's use this bad boy:
List<User> users = new List<User>(); User user = null; SqlQuery query = db.Select .From<User>() .InnerJoin<Role>(UsersTable.Role_IDColumn, RolesTable.IDColumn) .InnerJoin<Profile>(UsersTable.Profile_IDColumn, ProfilesTable.IDColumn); ProjectionMapper mapper = new ProjectionMapper(); using (IDataReader dr = query.ExecuteReader()) { while (dr.Read()) { user = mapper.Map<User>(dr); user.Role = mapper.Map<Role>(dr); user.Profile = mapper.Map<Profile>(dr); users.Add(user); } }
The solution is clean and relatively efficient; this makes Kon a happy boy. Again, I must give most of the credit to Ben Scheirman for his help.
Saturday, May 29, 2010
C# Extension Method Bummer
I love extension methods, which were introduced in .NET 3.5 Framework. While trying to avoid extending everything and its grandmother, I find them very useful for very common tasks like special ToString() formatting or basic array manipulation (adding an element to an already full array). But I was pretty disappointed to find an ugly limitation of extension methods, specifically in C#.
Let's say for example you want to create an extension method that adds an item to an array of objects while dynamically growing said array. Note: Sure we can do these things easily with ArrayLists or any other type of generic lists. But say you're stuck with working with simple arrays... just go with me here.
Wouldn't it be nice if it were that simple? ...and working? Unfortunately, that is not the case with C#. Remember that in C# objects are passed by value, not reference. So the fact that we're setting source to tmp at the end of the extension method bares no impact whatsoever on the original source array outside of this method's scope. This is one of those very rare times I say, "What the hell?! I'd be better off doing this in VB!"
You also can't use ref keyword to pass this instance into the extension method by reference, because you're not really supplying that parameter to the method when calling it. So there's nothing to put ref in front of.
And that just gives me the willies. It gets the job done, but... ugh.. I sure would have preferred to be able to alter the original object within the extension method - that way seems a lot cleaner to me. What a bummer!
Let's say for example you want to create an extension method that adds an item to an array of objects while dynamically growing said array. Note: Sure we can do these things easily with ArrayLists or any other type of generic lists. But say you're stuck with working with simple arrays... just go with me here.
So consider the following extension method:
public static void Add<T>(this T[] source, T newItem) { // Create a new temporary array that's larger than the original T[] tmp = new T[source.Length + 1]; // Copy contents of source array to temporary array source.CopyTo(tmp, 0); // Assign new item to the temporary array tmp[tmp.Length] = newItem; // Set original source to the newly grown array source = tmp; }
And then you can simply add an item to an array with a single line of code:
user[] users = new user[0]; users.Add(new user());
Wouldn't it be nice if it were that simple? ...and working? Unfortunately, that is not the case with C#. Remember that in C# objects are passed by value, not reference. So the fact that we're setting source to tmp at the end of the extension method bares no impact whatsoever on the original source array outside of this method's scope. This is one of those very rare times I say, "What the hell?! I'd be better off doing this in VB!"
You also can't use ref keyword to pass this instance into the extension method by reference, because you're not really supplying that parameter to the method when calling it. So there's nothing to put ref in front of.
So one alternative is to just return the new array:
public static T[] Add<T>(this T[] source, T newItem) { // Create a new temporary array that's larger than the original T[] tmp = new T[source.Length + 1]; // Copy contents of source array to temporary array source.CopyTo(tmp, 0); // Assign new item to the temporary array tmp[tmp.Length] = newItem; // Return the newly grown array return tmp; }
But that's ugly, because now you have to assign the return value to the variable you just called a method on:
user[] users = new user[0]; users = users.Add(new user());
And that just gives me the willies. It gets the job done, but... ugh.. I sure would have preferred to be able to alter the original object within the extension method - that way seems a lot cleaner to me. What a bummer!
Friday, May 21, 2010
Subscribe to:
Posts (Atom)