Animating Partial Postbacks and UpdatePanels with jQuery 4

Update panels make it really easy to do pseudo ajaxish stuff with little or no extra effort. Wrap your controls in a an UpdatePanel, pay for the entire page to post back and go through its life-cycle and you’re pretty much there. I’ve already written a bit on the extra steps you’ll need if you’re doing some jQuery magic inside that UpdatePanel. It’s not difficult and easy enough to either delegate up the chain to something outside the UpdatePanel (e.g. event delegation) or rinse and repeat the jQuery after the partial post back is complete (e.g. add_endRequest).

What would be really slick-o-matic is if we could do some animation to transition the partial postback so it wouldn’t just explode with new content in our face. Now granted, that may be an overstatement. The content changes usually aren’t drastic or very distracting to but let’s add a bit of polish.

Keep in mind this is a first draft, done in about 30 minutes after an idea landed in my head at 3am. It still needs some polishing, but the major hurdles are taken care of.

For our example, we’ll have a simple Div that will be worked upon in a partial postback. Our goal will be to gently transition the display of that work to the user. Something like this.

Original Video – More videos at TinyPic

We’ll start off with some basic styles to help illustrate the change. We’ll change the content of the Div and also the class.

	#mydiv{ width:200px; border:solid 1px black; font-size:xx-large; }
	.myclass0 { height:200px; background-color:Blue; }
	.myclass1 { height:100px; background-color:Red; }
	.myclass2 { height:150px; background-color:Lime; }
	.myclass3 { height:50px; background-color:Purple; color:White; }

Nothing too exciting, but our partial postback will give us some new dimensions and style. It’ll get the point across.

Next we need some HTML.

<form id="form1" runat="server">
	<asp:ScriptManager ID="ScriptManager1" runat="server">
	</asp:ScriptManager>
	<div>
		Original time: <%= DateTime.Now.ToLongTimeString() %> 
		<asp:UpdatePanel ID="UpdatePanel1" runat="server">
			<ContentTemplate>
				<asp:Button runat="server" Text="Button" ID="MyButton"
						OnClick="MyButtonClick"
					OnClientClick="return ClientClick(this,'#mydiv'); " />
				<div id="mydiv" runat="server">
					<asp:Label runat="server" Text="Label"
                                           ID="MyLabel"></asp:Label>
				</div>
			</ContentTemplate>
		</asp:UpdatePanel>
	</div>
</form>

The magic is going to live in the ClientClick event handler, but forget about that for now. The server side OnClick event will do some trivial work.

 protected void MyButtonClick(object sender, EventArgs e)
 {
	 MyLabel.Text = DateTime.Now.ToLongTimeString();
	 var c = "myclass" + DateTime.Now.Millisecond % 4;
	 mydiv.Attributes.Add("class",c);
 }

This could just as easily toggled a view from edit mode to read-only, expanded a detailed area, etc. Here, we are just picking one of four css classese to use on the div and also giving a label the current time. Like I said this isn’t the cool part.

The final steps are to do the following:

  • Get the jQuery animation to happen on the click of the button.
  • Get the partial postback to wait until the animation is done.
  • Get the DOM to appear in the pre-animation state when it comes back from the partial postback.
  • Get the animation to happen once we have the new page ready to go.

The function needs to know what needs to be animated upon. I’ve been using slide transitions, but the animation is something I think can very easily be abstracted out. We make some quick tests to see if we are in the process of animating or if the animation has been completed. I struggled with how to delay the button click’s post back from happening until the animation is complete and finally decided to just let it happen a second time, but to flag the second click to allow it to continue posting back. I’m using the jQuery data feature to keep some state about the button.

If we are currently sliding, then there is nothing left to do, and if we are done sliding then we can skip the other steps and continue the postback.

if (d.data("isSliding")) return false;
if (d.data("doneSliding")) return true;

If we don’t meet those conditions, we need to slide. We set our flag, wire up the end request handler and the callback to the slide method and kick off the slide.

The slide method is the simplest.

d.slideUp(500,
	function() {
		d.data("isSliding", false);
		d.data("doneSliding", true);
		$(sender).click();
	});

Slide our control up, and when we’re done, set some flags and kick off the click a second time. With the flags set, we’ll fire off the postback. Nothing really fancy here either. Notice we can still reference d here. We don’t need to find it again.

The endRequest handler looks a bit more involved.

var prm = Sys.WebForms.PageRequestManager.getInstance();

var f = function(s, e) {
	d = $(whatToSlideDown);
	d.css("display", "none");
	d.slideUp(0);
	d.slideDown(500);
	prm.remove_endRequest(f);
}

prm.add_endRequest(f);

Here, inside the function we do need to ask jQuery to find what we want again. The DOM has been changed and the old d we created from $(whatToSlideUp) probably isn’t there anymore. In addition, we need to set the element in the state we left the old element. In this case, we want the display to be set to “none”. This allows the slideDown to work just like we would expect following a slideUp.

This is part of the setup that I don’t like. I’ve tried quickly running a slideUp(0) on the the new elements, but I was seeing a flash of the default state before getting the slide up. This is something that I would like to factor out. The animation, including this default state should be a parameter to the function.

Here is a look at the function as a whole. It’s a stupid function name I know, but that is easily changed.

function ClientClick(sender,whatToSlideUp,whatToSlideDown) {

	if (!whatToSlideDown)
		whatToSlideDown = whatToSlideUp;

	var d = $(whatToSlideUp);

	if (d.data("isSliding")) return false;
	if (d.data("doneSliding")) return true;

	d.data("isSliding", true);

	var prm = Sys.WebForms.PageRequestManager.getInstance();

	var f = function(s, e) {
		d = $(whatToSlideDown);
		d.css("display", "none");
		d.slideUp(0);
		d.slideDown(500);
		prm.remove_endRequest(f);
	}

	prm.add_endRequest(f);

	d.slideUp(500,
		function() {
			d.data("isSliding", false);
			d.data("doneSliding", true);
			$(sender).click();
		});
	return false;
}

That’s it. There is definitely room to polish this up and make it more flexible. I’ll post back when I get it up and running in a real application so it looks more useful.

Scoping JavaScript with Module Pattern 0

I’ve entered the world of actually writing JavaScript. In the past, usability was really a secondary concern. I need to do a postback to make a button visible, no problem. The screen will flash, but who cares. It’s not like the user is going to stop using my application to do the stack of work on their desk. They have to use it. It’s their only option.

Now that isn’t entirely true. We attempted to make it as usable as possible, but anything that even close to using jQuery was probably just, according to the powers that be, the developers just playing around with cool toys. I’m not sure the value of the user experience fell nicely into a quantifiable metric. I’m beginning to rant, so back to the point.

In my new adventures with jQuery, I’ve been writing a lot of JavaScript. The biggest complaint I’ve had with my JavaScript is that everything is global and can potentially be overwritten by subsequent JavaScript, or I might be overwriting someone else’s functions or variables. My JavaScript files looked like the following.

var foo = "berry";
function doWork(s){
	alert(s+foo);
}

$(function(){doWork("foo")});

I just cross my fingers that no one else has a doWork function or foo variable. There has to be a way to scope this stuff.

Luckily, I found and article that explains exactly that. It explains the Module Pattern and how to use it to limit the scope of JavaScript.

I’ll let you read the article for a more complete description that I could put together, but ultimately, my JavaScript ends up looking like this.

myScript = function(){
  return {
	init:function(){doWork("foo");}
  }
  var foo = "berry";
  function doWork(s){
	alert(s+foo);
  }
}();
$(myScript.init);

In this case, init is the only method that gets exposed. You can’t invoke doWork. Also, by adding the scope of myScript, you can have greater confidence your methods and variables aren’t getting overwritten.

My practice thus far is to have one JavaScript file for each page and user control. The scope of each page’s file is the name of the page, or control. So you could see Login.aspx.js with a scope of MyApp_Login.

So far so good. We’ll see how it goes.

Finding parent elements with jQuery 1.3 0


magnifying monkey man.

I was recently writing a little javascript function that would traverse up the object graph and apply jQuery selectors to pick the correct parent that I needed. It was a pretty basic function, but I had that gut feeling that this is something that I shouldn’t be writing. It has to be already written by someome. 

Luckily, with jQuery 1.3, it’s part of the core library. New in this version is the closest method which will find the closest parent that matches the selector you pass.

ASP.Net Ajax payload size compared to jQuery 0

Let me start off by saying this isn’t scientific, or possibly even accurate, but was pretty shocking at first glance. I wanted to take a look at what the true size of our pages were, so I brought up Chrome’s nice resource inspector and refreshed and average page from our intranet application. It was a bit shocking at first.

image

All that orange is javascript! Now, I know the browser is probably caching that, when it goes through IIS – Cassini won’t cache it—, butit still seems like a pretty big chunk, but it’s probably all the jQuery and jQuery plugins we’re using right?

image

Without the rest of the files, it’s hard to put that into perspective, but trust me ,that is pretty small. What about the plugins?

image

Those are pretty small too. All that javascript has to be somewhere right? What about ASP.Net Ajax?

image

I had to scale the image so it would fit, but there is a lot there. You may have noticed that we are using the min version of the jQuery file. Is the ASP.Net Ajax minified?

NOPE!

I haven’t really looked to see if it is possible to shrink that JS somehow, we’ll see about doing that soon.

Update on Beyond Compare inside Team Build and why I’m starting to hate TFS 7

In the past few days, and nights, I’ve learned a few things. Most are bummers, but there is light at the end of the tunnel. This is what I feel our build process was like for the past few days, but I think we’re doing much better now and things are actually working. (Cross your fingers)

I’ve tried a few approaches yesterday and here is what I’ve found.

Deploying via Ftp

Initially, I tried to deploy to our servers via FTP. This appears to work well, but the timestamps are all adjusted by the GMT offset. In our case, the files end up on the server looking like they were edited 6 hours in the future. This makes every single file appear different on the next sync since none of the time stamps match. Apparently this is by design from Microsoft. What a bummer. Running the development server on GMT will cause the timestamps in the database on that server to also be off. This option is out.

Deploying via file share

Again, this appears to work well. The first time everything goes. We change a single file and the log sees that only one file has changed, but doesn’t move it. Doh! They come out of TFS as read-only, and copying to a file share will carry over those file attributes. No problem.  

attrib -r \\myServer\myShare\myApp\*.*

Nope! You can’t run attrib on a network share. It has to be a physical disk.

OK. Well I’ll just attrib -r the source files in the build’s working directory. Great! That worked. Let’s try it again. Doh!

Unable to perform the get operation because it is writable.

Miedo

You’re kidding me! Grr…OK! Fine! I’ll attrib +r after I push. Nope! Not every file in the source directory is suppose to be read only and some of them cannot be read only. AHHH!

Oh yes! Beyond Compare has an attrib -r command in the scripting reference.

ATTRIB
Usage: attrib (+|-) [(+|-) <...>]

Sets (+) or clears (-) the DOS file attributes in the current selection. An attribute set can include archive (a), system (s), hidden (h), and read only (r) attributes. Windows only implementation: Linux version will not recognize ATTRIB.

Sound great right?….that doesn’t work. Even on simple unit test this doesn’t work. I’m at my wit’s end now. There is one more thing to try. There is one more command in the Beyond Compare script reference that might be able to help.

OPTION
Usage:
option stop-on-error
option confirm:(prompt|yes-to-all|no-to-all)

Adjusts script processing options.
· stop-on-error makes the script watch for various error conditions, including file operation errors, and, when one occurs, prompts the user before continuing.
· confirm can use prompt, yes-to-all, or no-to-all to handle confirmation dialogs that occur due to file operations. By default, prompt is used.

Let’s hope this works. I’ll put it right before the sync, cross our fingers and run it through some tests.

It WORKS! Or it appears to so far. Hopefully.

The files on the server still carry the read only flag. That’s not ideal for us, but it will have to do for now.

Welcome to jQuery 2

My first task at my new organization was to verify text being added to a freeform text field is not already associated to a different record of the same type. This would be similar to checking if a username is taken before completing a registration process. As you have probably encountered with the registration process, the typical way to complete this test is to wait for the user to click save button and then test the database for the existing record. It would be a lot nicer if the test would happen automatically as you type, so this is what I set out to do.

Doing this with ASP.Net AJAX would probably be possible, but given we are starting to invest in jQuery, I took this as a great opportunity to learn something new, while still delivering a great user experience. While working through some quick and dirty jQuery examples, I quickly see its potential. It feels nice to be in a dynamic language for a change.

My first task was to fire off a function after a certain amount of time elapses without the user typing into the field. I know Javascript provides a timer mechanism, but I’m hoping jQuery provides a nice abstract to it…and it does. I’m able to find my text box and attach my timers. It was when I first tried to move this out of my static html proof of concept into an ASP.Net application hat I first realized the bane of ASP.Net when using jQuery, control id’s.

All of the examples in jQuery have really nice, hand crafted control id’s.

	$("#myTextbox").keypress(function(){
		$("#myTextbox").oneTime(1000,"mytimer",function(){alert("times up");});
	});

That’s great, but my text box is inside a user control, inside another user control, inside a page. I don’t get id = "myTextbox". I get id = "ctl0__ctl1_ctl1_etc_myTexbox", which makes the selector a little more difficult to write. Luckily, we can use some nasty escaped ASPX code to handle that. I’m not sure this is the best way to handle it, but it is working for now.

	<script type="javascript">
		var controlName = "<%= myTextbox.ClientID %>";
		$("#" + controlName).keypress(function(){"pressed it");});
	</script>

On occasion, the client id is not as easy to come across. For example, in my particular case, I am trying to select a text box inside the InsertItemTemplate of a ListView.

<asp:ListView ID="ListView1" runat="server">
    <!-- ... -->
    <InsertItemTemplate>
        <asp:TextBox ID="myTextbox" runat="server" />
        <script language="javascript" type="text/javascript">
            var controlName = '<%= ListView1.InsertItem.FindControl("myTextbox"); %>';
        </script>
    </InsertItemTemplate>
</asp:ListView>

…OK. I’ve learned not to be too ambitious with my blogs post. I’ll be contributing in smaller chunks form now on.

Incentivizing Programmers 0

In most factories, especially those that pride themselves on their safety records, you’ll find a sign that says something like “600 days since our last lost time incident”. We should have the same for our automated build qualities, although I doubt they will ever reach 600 days of consecutive green builds. It would hopefully generate a sense of pride in the build. Imagine if you joined a team that had 60 days of green builds and that number was publicized for the entire organization to see. Wouldn’t you take extra care to make sure you don’t do something that flips it over to red, even for one build?

Gaining momentum behind doing automated build is something our organization is struggling with at the moment. For some reason the value isn’t immediately apparent or the schedules and budgets don’t allow for it at the moment. Both of those are topics for another post. Maybe a component to gaining that momentum is illustrating the elevation and longevity of the quality of the builds. I see two metrics being valuable.

  1. Days of consecutive green builds
  2. Change in the number of unit tests over time

Potentially a third being the number of customer reported defects.

The number of consecutive green builds is important, but if one team is doing nightly builds and another is doing continuous integration, does one team have a significant advantage in quality over another? I would say there is benefit there, but I wouldn’t categorize the advantage as significant. Also, looking at the change in the number of tests provides a better indication of progress than percentage change. Adding a hundred unit tests to a build that already has a thousand is substantially better than adding one unit test to a set of ten. I imagine you’re saying that is still rather subjective because you could have ten quality tests and a thousand horribly simple ones and that’s true, but maybe this isn’t the place to make those determinations. Let’s assume all unit tests are of roughly the same complexity and comprehension.

So here is my question. Would it be valid and beneficial to incentivize teams to improve these metrics or compete against other teams to improve the metrics? In the past we’ve given out $5 gift cards to Starbucks or iTunes when people did good jobs on something, just as a nice “thank you”. Would that work here? Could giving a $5 gift card to the each member of the team that has the longest stretch of green builds or added the most unit tests in the last month help motivate people? Now I don’t expect people to add hundreds unit tests every month to get their free fat free half caf soy carmel white chocolate mocha macchiato (I’m not even sure that drink exists or if would be less than $5 if it did). I’m not saying those are the metrics and the periodicity of the rewards that would work the best, just wondering if the spirit of it would work.

Recent posts by Ayende and Joel Spolsky seem to imply it would fail miserably.

I’m not sure something like $5 will lead teams to work the system just for the reward. Even without the monetary reward the principle behind taking pride in the build quality could established by making an aggregated build report public. Something really public. Maybe a screen when I get off the elevators, or a TV in the lobby that gives some metrics. Let me see who the people are who are writing the most unit test. I’m sure they can answer some of my questions or give me advice. Show me who isn’t building and we can get them the help they need to get it off the ground. There should be something we could do to help.