Posted on June 2, 2009 17:41 by swilliams

In the project I am currently working on, we are using JavaScript and jQuery in just about everything. One of the frustrations that I have been seeing is that I’ll render a view representing an object, but also want a JSON version of that object to manipulate. I am also quite anal when it comes to keeping my code clean and separating the concerns; I did not want to have JavaScript strewn throughout my HTML or vice versa.

I considered a couple of options. The first just involved making an AJAX call to the server and having it return a JsonResult. This is clean, but I did not want to effectively double my calls to the server.

I also considered extending the MVC framework and writing my own ActionResult class that returned both HTML and JSON. However, that also “felt” wrong; like I was short-circuiting the framework. I would have had to rely on JavaScript on the client side to parse the resulting object and place the HTML, not something I want to be doing with all of my views.

I let it sit on the backburner for a while, and then today came up with a pretty good solution. It’s not ideal, but it works well enough for me. I created a simple HtmlHelper extension that just dumps the JSON out into a variable:

    
using System.Web.Script.Serialization;

    public static class JsonExtensions {
        public static string Json(this HtmlHelper html, string variableName) {
            return Json(html, variableName, html.ViewData.Model);
        }

        public static string Json(this HtmlHelper html, string variableName, object model) {
            TagBuilder tag = new TagBuilder("script");
            tag.Attributes.Add("type", "text/javascript");
            JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
            tag.InnerHtml = "var " + variableName + " = " + jsonSerializer.Serialize(model) + ";";
            return tag.ToString();
        }
    }

You call it from a page like so:

<%= Html.Json("foo") %>
<%= Html.Json("bar", Model.Something) %>

This is not an ideal solution, you are still technically putting JavaScript in the HTML. But, it does not make an extra call to the server, and the markup in the IDE is still very clean.

Another approach I considered was to have an Action that returned a JavaScriptResult that consisted of the same thing. You could then add a script tag like:

<script type="text/javascript" src="/javascript/MyObject/1000">

The catch though is that it would cause more overhead, especially if the app was designed in such a way that the retrievals are expensive (ours is).

I’m still ruminating on that perfect scenario, but for now I’ll be doing it this way.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

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

Posted on May 14, 2009 13:04 by swilliams

Just prior to their 1.0 release, the ASP.NET MVC dev team added a nice feature to prevent CSRF attacks, the AntiForgeryToken. In brief, a CSRF attack is when a 3rd party gets one of your users to accidentally run a malicious script that accesses normally restricted URLs. The AntiForgeryToken pattern allows the web server to reject requests that come from places it was not expecting. More details can be found here. If you are a web developer and aren’t familiar with CSRF attacks, you need to fix that.

Anyways, the AntiForgeryToken bit is all well and good, but what if you are using jQuery (or another library) to handle your AJAX calls? Say you have an Action method like this:

[AcceptVerbs(HttpVerbs.Post), ValidateAntiForgeryToken]
public ActionResult DeleteAccount(int accountId) {
    // delete stuff
}

And you call it via:

$.post('/home/DeleteAccount', { accountId: 1000 }, function() {
    alert('Account Deleted.');
});

Since the POST does not include the AntiForgeryToken, it will fail.

Fortunately, it doesn’t take much brainpower to fix this. All the client side component of AntiForgeryToken does is put the token in a basic hidden field. So, you just need to pull that data out and include it in your AJAX call.

var token = $('input[name=__RequestVerificationToken]').val();

$.post('/home/DeleteAccount', { accountId: 1000, '__RequestVerificationToken': token }, function() {
    alert('Account Deleted.');
});

Do note that if you have multiple forms on the page with multiple AntiForgeryTokens, you will have to specify which one you want in your jQuery selector. Another gotcha is if you are using jQuery’s serializeArray() function, you’ll have to add it a bit differently:

var formData = $('#myForm').serializeArray();
var token = $('input[name=__RequestVerificationToken]').val();
formData.push({ name: '__RequestVerificationToken', value: token });

$.post('/home/DeleteAccount', formData, function() {
    alert('Account Deleted.');
});

Again, if you are making a web site that has any sort of interactivity at all, you need to be aware of these kinds of attacks. The tools to prevent them are readily available for you to use.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

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

Posted on May 11, 2009 21:36 by swilliams

I'm a big fan of the ASP.NET MVC framework. I love the fine grained control it gives you over everything. But what I love most is that you can unleash the fully armed and operational firepower of jQuery.

Recently, I've been working on a site that is using both MVC and jQuery to make AJAX calls. Typically the method being called returned HTML (via a PartialView). But, if an error was thrown, I wanted to return a JSON object encapsulating it.

Unfortunately, jQuery could not decide how to handle a response that could be either HTML, or a JSON object. You can tell jQuery what to expect, or let it try to figure out what the response dataType is. Here's the behavior of my Action method:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult HandleAjax(int id) {
    try {
        var myObj = RetrieveData(id);
        return PartialView("myview", myObj);
    } catch (Exception ex) {
        return Json(new { success = false, message = ex.Message });
    }
}

The problem is that regardless of what gets returned, jQuery only recognizes it as a string, and treats it as HTML.

I did think of one solution, but it used pretty poor design: it attempted to parse the responseText as JSON. If that was successful, it meant the error object was returned. But, if an exception was thrown, it was the HTML. The problem is that it was using error handling mechanisms to capture an expected result. Bad news; I'm not even going to post the code.

Fortunately, someone pointed out that if I set the http status code to 500, jQuery will send the result to the error() callback function, as opposed to success(). Thus, if you added:

this.Response.StatusCode = 500;

In the catch block, you can then use jQuery's error() callback to do exactly as you'd expect:

$.ajax({
    data: { id: 100 },
    dataType: 'html',
    error: function(XMLHttpRequest, textStatus, errorThrown) {
        var errorObj = JSON.parse(XMLHttpRequest.responseText);
        handleError(errorObj);
    },
    success: function(data) {
        $('#resultContainer').html(data);
    },
    url: '/home/HandleAjax'
});

This also makes use of Crockford's JSON library to parse the responseText string to a JSON object.

It is this transparency that makes me sing the praises of the MVC framework. Such a mechanism is certainly possible with classic WebForms, but it is hidden under layers of abstraction, and likely would have required mixing of markup, script, and server side code.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

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

Posted on November 10, 2008 13:48 by swilliams

One thing that every developer can agree on is that code readability and maintainability is a Good Thing. Nobody wants to come back to a project several months later only to find the critical piece of it is poorly formatted, uses three separate programming paradigms, and Oh My Goodness why is it using Exceptions as GOTO statements?

Wars have been fought over whether the opening curly brace goes on the same line as the expression, or a new one*. However, I am always surprised to see that the markup created by many developers is a tangled mess of HTML, CSS, and JavaScript. In a sufficiently large project, doing something as simple as moving a <div> from one corner to another is tantamount to sending a rocket to the moon.

[* The answer is the same line, as God intended.]

The common justification is the old "Well, I'm not a designer" routine. And again, yes, that is probably true, but do you actually like wasting hours figuring out why things aren't lining up the way they should?

Something that I've found helps enormously is to just treat your markup, style, and script as first class citizens. Here's how I do it:

Keep Your Stuff Separate

Keep your HTML, CSS, and JavaScript in separate files. Just like it's a bad practice to embed database logic in your UI, it's a bad practice to use the style="" attribute on an HTML tag*.

Why is this bad? It all comes back to readability, in both a human and machine sense. Fixing markup is easier when you don't have to account for styling and JavaScript embedded throughout. Programmatically parsing HTML is same way.

[* I'm using absolutes here for emphasis, there are always exceptions.]

To accomplish this, I use a file structure I call "The Cradle." It consists of my main HTML page (index.html, or a Master Page, or whatever), and all of the .js and .css files I will be needing. Its contents are:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Title</title>
    <link type="text/css" rel="stylesheet" href="css/master.css" />
</head>
<body>

<!-- Content goes here -->

<script type="text/javascript" src="js/framework.js"></script>

</body>
</html>

The reference to the master.css file is the only time CSS is ever mentioned in the page. The CradleFramework.js is replaced by whichever JavaScript framework I am using, usually Prototype or jQuery. I'll also add another JavaScript line to reference custom JavaScript for the page. Again, this is the only time JavaScript is ever mentioned on the page. I do not use any of the onclick, onmouseover, onwhatever event attributes here. This keeps the HTML light and easy to scan.

Additionally, all CSS file references are at the top of the page, since the styles won't be applied otherwise, and JavaScript at the bottom to avoid as much of a delay as possible when the page is rendered.

Split up your CSS

Why only one css file referenced? Because with the @import directive, you can call separate CSS files from the master.

This means my master.css file looks like:

@import url('type.css');
@import url('layout.css');
@import url('color.css');

If I feel that a CSS reset is needed, I'll include a reset.css above all of that. As you can probably guess, type.css contains styling for text, and text only. Layout determines the positioning and sizing of things, and color.css makes them pretty. I try to avoid spillover as much as possible; type does not define font color. Borders are kind of a wildcard since they deal with both layout and have a color component, so I keep them in color.css.

Additionally, these can split up further for the various media types out there. @importing a print_layout.css in the layout file can help if you need to maintain a print version of the page. Same with a mobile version. They are not kept in the Cradle since I rarely use them.

An added benefit of splitting CSS is that file sizes become shorter. A smaller line count makes it easier to scan and find selectors.

One Off Styles

All of these tips have applied to a global style. But what happens if you have a separate page that needs various elements specific to just it to be styled? If the page only has a minimum set of elements, I'll throw them in with the global style. If not, I'll use a separate file and include it on just that page.

Use JavaScript To Wire Up Events

I mentioned earlier that you should avoid using the onevent attributes that HTML provides. When I first heard this, I thought it was silly, since it meant I wouldn't be able to have all the fancypants Web 2.0 things that all the hip kids were doing.

It turns out that you can have your cake and eat it too. One convention I use with my JavaScript is to have an init() method like so:

var MYAPP = function() {
  return {
    init: function() {
      // put stuff here
    }
}();

$(document).ready(MYAPP.init);

If this syntax looks a little screwy to you, that's ok, read up on some of JavaScript's awesome functional roots.

This bit of code runs the init() function when the page loads. Inside init() is where other functions are called, including createEvents():

var createEvents = function() {
  $('#new').click(function() {
    alert('You clicked the new link!');
  });
};

This attaches a function to an element with the id "new." When it is clicked a friendly dialog pops up providing some useful text.

Both of these examples use the jQuery library, though you can do the same thing with Prototype, YUI, MooTools, or plain old JavaScript.

Once you have The Cradle set up to your specifications, it is easier to keep designs up to date. If someone tells you, "The font in the header needs to be bigger" you automatically know that it is in type.css, and won't be difficult to find from there. No more poking through various HTML and CSS files to find it.

I keep my version of The Cradle in my documents folder and copy it to each new project at the beginning. You can download your very own copy and use it however you would like. I included a recent copy of jQuery and Prototype, but you can use whichever library suits you.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

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

Posted on August 27, 2008 17:34 by baugustine
 

Interesting issue Shawn and I ran into today with the <script> tag in ASP .Net. A page was defined with <script> tag that was closed with a /> instead of </script> as shown below.

 

<script language="javascript" src="myJavaScripts.js" type="text/javascript" />

 

And any time a control on the page did a post back it started throwing java script errors such as "Object Expected". Other variants could be "__doPostback not defined" but I did not see that error. Anyway the culprit was the /> closing tag. So to fix the error I had to end the <script> tag with </script> tag instead of />. So changing the above statement to

 

<script language="javascript" src="myJavaScripts.js" type="text/javascript"><script>

 

fixed the error.

 

Incidentally this worked also.

 

<script language="javascript" src="myJavaScripts.js" type="text/javascript" />

<script></script>

 

Go figure.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

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

Posted on July 18, 2008 15:04 by swilliams

Confession time: I love Panic software. They put tons of effort into the UI of their products, and it shows. Even their website shows astonishing attention to detail, and web design isn't even a service that they offer. What gets me the most are the sliding panels on the page for Coda. I peaked at the source code for it and saw:

// Not for redistribution

Hrmph. And then I thought that I could probably reverse engineer what they were doing without copying and pasting their code. Just to be clear, I did not copy a byte of their code; everything here was written entirely by me (except in one case where labeled). To do some of the lifting, I used the Prototype JavaScript library, though you could just as easily do it with JQuery, YUI, or no library at all.

First, the Markup

This is the simplest part. The tabs are just a horizontally positioned list with the bullets removed. And the panels are divs floated sequentially. The idea is that there is a "window" div that displays one of the divs behind it. When a link is clicked, the floated divs slide in the proper direction.

scroller_image

Here is the markup to make it happen:

<div id="main">
    <ul>
        <li><a href="#" rel="scroll">Panel One</a></li>
        <li><a href="#" rel="scroll">Panel Two</a></li>
        <li><a href="#" rel="scroll">Panel Three</a></li>
        <li><a href="#" rel="scroll">Panel Four</a></li>
    </ul>
    <div id="scroll_container">
        <div id="scroller">
            <div>
                <h1>Panel 1</h1>
            </div>
            <div>
                <h1>Panel 2</h1>
            </div>
            <div>
                <h1>Panel 3</h1>
            </div>
            <div>
                <h1>More</h1>
            </div>
        </div>
    </div>
</div>

The only other thing worth mentioning is the rel="scroll" attribute on the anchor tags. This is just used to identify that these links cause a scrolling action to occur, and are used by the JavaScript to easily grab them.

The Style

Styling the HTML isn't too tricky, though there were a couple of small gotchas. My first thought was to set the position of scroller to relative and then use the JavaScript to adjust its left property. This would have worked, but then IE displays all of the scroll panels even if scroller's overflow is set to hidden.

After a bit of snooping I found that I could get the same behavior by adjusting the scrollLeft property on scroller. This manipulates the [invisible] scrollbar.

Scroller's width is large to accomodate all the panels, but could be set to anything greater than or equal to the aggregate width of the panels.

div#main
{
    width: 600px;
    margin: 0 auto;
    height: 800px;
    overflow: hidden;
}
div#main > ul
{
    margin: 0;
    padding: 0;
    width: 100%;
}
div#main > ul li
{
    font-size: 1.4em;
    margin-right: 20px;
    display: inline;
    list-style-type: none;
}
div#scroll_container
{
    width: 600px;
    overflow: hidden;
    height: 740px;
    background: #eee;
}
div#scroller
{
    width: 5000px;
}
div#scroller > div
{
    width: 600px;
    height: 740px;
    float: left;
}

JavaScript - where the magic happens

I took an iterative approach for the JavaScript. First, the most basic way to get "sliding" functionality. The initial design didn't even slide at all, it just moved the panels without an animation.

var scroller = function() {

    var scroll = function(index) {
        var totalOffset = index * scroller.scrollPanelWidth;
        var scrollee = $(scroller.scrollPanel);
        scrollee.scrollLeft = totalOffset;
    }

    var getScrollLinks = function() {
        var links = $$('a[rel=scroll]');
        links.each(function(elem, index) {
            elem.observe('click', function() {
                scroll(index);
            });
        });
    };
    
    return { 
        scrollPanel: '',
        scrollPanelWidth: 0,
    
        init: function(panel, panelWidth) {
            scroller.scrollPanel = panel;
            scroller.scrollPanelWidth = panelWidth || 600;
            getScrollLinks();
        }
    };
}();

This does exactly that. Some of the conventions I'm using here may seem a little weird, but it allows the scroller object to have private fields. To learn more about it, see here.

You can see this in action here.

Functional, but not fancy. I was going to use Script.aculo.us to do the animation, but it does it using the position: relative method described a few paragraphs ago, making IE render incorrectly. Which is kind of a bummer.

So, we'll have to animate this by ourselves. I arbitrarily decided that 500 milliseconds was an adequate time for the animation to take, in 25 frames (for simplicity's sake, pick a number that divides the duration evenly). To accommodate for these values, a couple of properties were added to the scroller object and the scroll() function now does the animating:

    var currentPosition = 0;   
    
    var scroll = function(index) {
        var totalOffset = index * scroller.scrollPanelWidth;
        var desiredOffset = totalOffset - currentPosition;
        var scrollee = $(scroller.scrollPanel);
        var tick = scroller.scrollTime / scroller.ticks;
        var timeIndex = 0.0;
        var inter;
	    
        function animate() {
            timeIndex += tick;
            var delta = desiredOffset / scroller.ticks;
            if (timeIndex > scroller.scrollTime) {
                clearInterval(inter);
                currentPosition = scrollee.scrollLeft;
                return;
            } 
            scrollee.scrollLeft += delta;
        }
        
        inter = setInterval(function() { animate(); }, tick);
    }

See it in action here.

With each tick of the timer the scroller div is moved a little bit in the proper direction. Since the duration remains constant, this has the neat effect of scrolling divs quicker the further apart they are.

At this point we could pat ourselves on the back and call it a day, but there is still a little bit more we could do. If you'll notice in Panic's design, the animation starts slowly, speeds up, then eases into the final position. Kind of like a train leaving the station, and then arriving at the next stop. Script.aculo.us's Effect.Move has the same property. It is these little things that really amp up the aesthetics of an app.

comparison How did they do it? Math! A sine curve has the function of what we're looking for. Our current example has a linear progression. Meaning each tick moves the scroller the same amount. With a sine curve, we get the behavior that Panic and Script.aculo.us have.

Since I haven't actually calculated the sine of anything since school, I decided to just steal borrow someone's code. As mentioned, Script.aculo.us has a sinoidal function. But grabbing a 100k library for a 3 line function is just silly, so I copied it to my own file directly.

var sinoidal = function(val) {
   return (-Math.cos(val * Math.PI) / 2) + 0.5;
}

sinoidal returns a value between 0 and 1, so we just need to multiply it by our desiredOffset to get our delta and tweak how the scrollLeft moves.

var delta = sinoidal(timeIndex / scroller.scrollTime) * desiredOffset;
/* ... */
scrollee.scrollLeft = currentPosition + delta;

And voila, smooth and fancy animation.

Lastly, I created a simple locking mechanism to keep the scroller from getting confused if a link is clicked before the animation is finished. There is still probably work left to be done, but that goes beyond the scope of what I wanted to discuss. So go forth and make great apps!

See the final example in motion.



Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Currently rated 5.0 by 1 people

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

Posted on March 5, 2008 05:57 by mcollins

While I am a fan of using Microsoft's AJAX framework in my ASP.NET applications, I am realistic and admit that it does some things well, but for other things, sometimes there's a better way.  Take the following web page for example:

   1: <%@ Page Language="C#" AutoEventWireup="true" ... %>
   2:  
   3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   4:     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   5: <html xmlns="http://www.w3.org/1999/xhtml">
   6: <head runat="server">
   7:     <title>Untitled Page</title>
   8: </head>
   9: <body>
  10:     <form id="form1" runat="server">
  11:     <asp:ScriptManager ID="ScriptManager1" runat="server">
  12:     </asp:ScriptManager>
  13:     <div id="faq">
  14:         <h2><a href="#">Question 1</a></h2>
  15:         <div>
  16:             <p>Answer 1</p>
  17:         </div>
  18:         <h2><a href="#">Question 2</a></h2>
  19:         <div>
  20:             <p>Answer 2</p>
  21:         </div>
  22:     </div>
  23:     <asp:Panel ID="DebugPanel" runat="server" Visible="false">
  24:         <textarea id="TraceConsole" rows="30" cols="60"></textarea>
  25:     </asp:Panel>
  26:     </form>
  27:  
  28:     <script type="text/javascript">
   1:  
   2:     <!--
   3:         Sys.Application.add_init(function() {
   4:             Sys.Debug.trace('Initializing page.');
   5:  
   6:             // Create client components. Initialize the page.
   7:             
   8:             Sys.Debug.trace('Page initialized.');
   9:         });
  10:         
  11:         function pageLoad() {
  12:             Sys.Debug.trace('pageLoad called.');
  13:             
  14:             // Begin executing the business logic for the page. Attach
  15:             // event handlers to elements, etc.
  16:             
  17:             Sys.Debug.trace('pageLoad completed.');
  18:         }
  19:         
  20:         function pageUnload() {
  21:             Sys.Debug.trace('pageUnload called.');
  22:             
  23:             // The page is being unloaded. If you attached event
  24:             // handlers in pageLoad, detach them here to prevent
  25:             // memory leaks.
  26:             
  27:             Sys.Debug.trace('pageUnload completed.');
  28:         }
  29:     //-->
  30:     
</script>
  29:  
  30: </body>
  31: </html>

This code template is a standard FAQ that has two questions and two answers.  Typically, when you see a page like this in a browser, you may come across the FAQ hiding the answers and showing you a list of the questions.  When you click on a question, then the answer will display itself.  To accomplish this feat, we'll use a little JavaScript, DOM, and CSS manipulation to show and hide the answers.  Here's the code with JavaScript using the Microsoft AJAX framework:

   1: <%@ Page Language="C#" AutoEventWireup="true" ... %>
   2:  
   3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   4:     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   5: <html xmlns="http://www.w3.org/1999/xhtml">
   6: <head runat="server">
   7:     <title>Untitled Page</title>
   8: </head>
   9: <body>
  10:     <form id="form1" runat="server">
  11:     <asp:ScriptManager ID="ScriptManager1" runat="server">
  12:     </asp:ScriptManager>
  13:     <div id="faq">
  14:         <h2><a href="#">Question 1</a></h2>
  15:         <div>
  16:             <p>Answer 1</p>
  17:         </div>
  18:         <h2><a href="#">Question 2</a></h2>
  19:         <div>
  20:             <p>Answer 2</p>
  21:         </div>
  22:     </div>
  23:     <asp:Panel ID="DebugPanel" runat="server" Visible="false">
  24:         <textarea id="TraceConsole" rows="30" cols="60"></textarea>
  25:     </asp:Panel>
  26:     </form>
  27:  
  28:     <script type="text/javascript">
   1:  
   2:     <!--
   3:         Sys.Application.add_init(function() {
   4:             Sys.Debug.trace('Initializing page.');
   5:  
   6:             // Create client components. Initialize the page.
   7:             
   8:             Sys.Debug.trace('Page initialized.');
   9:         });
  10:         
  11:         function pageLoad() {
  12:             Sys.Debug.trace('pageLoad called.');
  13:             
  14:             var faq = $get('faq');
  15:             var questions = faq.getElementsByTagName('H2');
  16:             for (var i = 0; i < questions.length; i++) {
  17:                 questions[i].nextSibling.style.display = 'none';
  18:                 $addHandler(questions[i].firstChild, 'click',
  19:                     toggleAnswer);
  20:             }
  21:             
  22:             Sys.Debug.trace('pageLoad completed.');
  23:         }
  24:         
  25:         function pageUnload() {
  26:             Sys.Debug.trace('pageUnload called.');
  27:             
  28:             var faq = $get('faq');
  29:             var questions = faq.getElementsByTagName('H2');
  30:             for (var i = 0; i < questions.length; i++) {
  31:                 $removeHandler(questions[i].firstChild, 'click',
  32:                     toggleAnswer);
  33:             }
  34:             
  35:             Sys.Debug.trace('pageUnload completed.');
  36:         }
  37:         
  38:         function toggleAnswer() {
  39:             Sys.Debug.trace('toggleAnswer called.');
  40:             
  41:             var answer = this.parentNode.nextSibling;
  42:             if (answer.style.display == 'none') {
  43:                 answer.style.display = 'block';
  44:             } else {
  45:                 answer.style.display = 'none';
  46:             }
  47:             
  48:             Sys.Debug.trace('toggleAnswer completed.');
  49:             return false;
  50:         }
  51:     //-->
  52:     
</script>
  29:  
  30: </body>
  31: </html>

In the pageLoad function, I begin by using the Microsoft AJAX framework's $get function to get the element with an id of faq.  From there, I get all of the child H2 elements of the FAQ.  Next, I do two things.  First, I hide the block containing the answer to the question.  Second, I attach an event handler to the click event of the A element inside of the H2 element.

Inside of the toggleAnswer function, I look at the current display state of the block containing the answer.  If the block is visible, I hide the block.  If the block is visible, I show the block.

Overall, this code works, but it seems like a lot of code.  Is there an easier way to build this page?

   1: <%@ Page Language="C#" AutoEventWireup="true" ... %>
   2:  
   3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   4:     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   5: <html xmlns="http://www.w3.org/1999/xhtml">
   6: <head runat="server">
   7:     <title>Untitled Page</title>
   8: </head>
   9: <body>
  10:     <form id="form1" runat="server">
  11:     <asp:ScriptManager ID="ScriptManager1" runat="server">
  12:         <Scripts>
  13:             <asp:ScriptReference Path="~/jquery-1.2.3.min.js" />
  14:         </Scripts>
  15:     </asp:ScriptManager>
  16:     <div id="faq">
  17:         <h2><a href="#">Question 1</a></h2>
  18:         <div>
  19:             <p>Answer 1</p>
  20:         </div>
  21:         <h2><a href="#">Question 2</a></h2>
  22:         <div>
  23:             <p>Answer 2</p>
  24:         </div>
  25:     </div>
  26:     <asp:Panel ID="DebugPanel" runat="server" Visible="false">
  27:         <textarea id="TraceConsole" rows="30" cols="60"></textarea>
  28:     </asp:Panel>
  29:     </form>
  30:  
  31:     <script type="text/javascript">
   1:  
   2:     <!--
   3:         var $j = jQuery.noConflict();
   4:         
   5:         Sys.Application.add_init(function() {
   6:             Sys.Debug.trace('Initializing page.');
   7:  
   8:             // Create client components. Initialize the page.
   9:             
  10:             Sys.Debug.trace('Page initialized.');
  11:         });
  12:         
  13:         function pageLoad() {
  14:             Sys.Debug.trace('pageLoad called.');
  15:             
  16:             $j('#faq > div').hide();
  17:             $j('#faq > h2 a').click(function() {
  18:                 Sys.Debug.trace('click handler called.');
  19:                 
  20:                 $j(this).parent().next().toggle();
  21:                 
  22:                 Sys.Debug.trace('click handler completed.');
  23:                 return false;
  24:             });
  25:             
  26:             Sys.Debug.trace('pageLoad completed.');
  27:         }
  28:         
  29:         function pageUnload() {
  30:             Sys.Debug.trace('pageUnload called.');
  31:             
  32:             Sys.Debug.trace('pageUnload completed.');
  33:         }
  34:     //-->
  35:     
</script>
  32:  
  33: </body>
  34: </html>

In this new code sample, notice on line #13 in the HTML markup that we're now including a reference to the jQuery library.  jQuery is another JavaScript framework that makes DOM and CSS manipulation significantly easier.  Using jQuery, we've been able to significantly reduce the amount of JavaScript code that we needed to really only about four lines of code if you remove the debugging statements.

The moral of this story is don't limit yourself only to using the Microsoft AJAX library to implement your JavaScript and AJAX layer in your web pages.  The Microsoft AJAX library gives you a lot of tools on both the client and server for implementing AJAX-type logic, but it's not the only player out there and can play just as well with other frameworks such as jQuery. 

If you read up on jQuery, you'll see that jQuery offers page-level events similar to Microsoft AJAX's init event and the pageLoad and pageUnload methods.  So the other question is which framework you should use as your primary.  I typically choose to use Microsoft's AJAX library as my primary and just use the other frameworks as necessary.  I do this because the Microsoft AJAX ScriptManager control is a primary component of my page and I use that as my base library and just add other functionality to it.  There's no right or wrong answer to this one, and everyone will have to make their own decisions.  That's just the way that I do things.

Technorati tags: , , ,


Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Currently rated 5.0 by 1 people

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

Posted on March 4, 2008 20:25 by mcollins

(I reposted this because it accidentally got deleted.)

Building a web application is not so much different than writing a normal desktop application when you consider it from the perspective of the server side.  The main difference is that your web application can be accessed by many users concurrently, while your desktop application is only accessed by a single user.  But in both cases, the applications start up, initialize themselves, and then wait and respond to user inputs to perform business logic.

When considering the client side of things in a web application, it becomes a little different.  A typical web application is made up of many web pages that are served to the user.  The user will typically navigate between the web pages by clicking hyperlinks or by pressing buttons that cause the server to redirect them to a different web page.  However, from the browser's perspective, each web page is a new application.  As such, a web page must also go through the initialization and wait for stimulus process that a typical application will go through.

The ASP.NET AJAX framework has support for building web pages and alerting them when they need to initialize.  The ASP.NET AJAX framework implements a global page manager object named Sys.Application that is created when the page is being loaded and manages alerting the page's JavaScript code when the page should be initialized, when the page has been loaded and should start running its business logic, and when the page is being unloaded and should clean up after itself.  The first event, initializing the page, is handled by the Sys.Application object calling an event handler for the init event.  The second event, telling the page to start running, is implemented by the Sys.Application object calling a special page-scoped function named pageLoad.  And the third event, telling the page to clean up and unload itself, is implemented by the Sys.Application object calling another special page-scoped function named pageUnload.  Your typical ASP.NET AJAX page template would look like this:

   1: <%@ Page Language="C#" AutoEventWireup="true" ... %>
   2:  
   3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   4:     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   5: <html xmlns="http://www.w3.org/1999/xhtml">
   6: <head runat="server">
   7:     <title>Untitled Page</title>
   8: </head>
   9: <body>
  10:     <form id="form1" runat="server">
  11:     <asp:ScriptManager ID="ScriptManager1" runat="server">
  12:     </asp:ScriptManager>
  13:     <div>
  14:     </div>
  15:     </form>
  16:  
  17:     <script type="text/javascript">
   1:  
   2:     <!--
   3:         Sys.Application.add_init(function() {
   4:             // Create client components. Initialize the page.
   5:         });
   6:         
   7:         function pageLoad() {
   8:             // Begin executing the business logic for the page. Attach
   9:             // event handlers to elements, etc.
  10:         }
  11:         
  12:         function pageUnload() {
  13:             // The page is being unloaded. If you attached event
  14:             // handlers in pageLoad, detach them here to prevent
  15:             // memory leaks.
  16:         }
  17:     //-->
  18:     
</script>
  18:  
  19: </body>
  20: </html>

The difference to remember between the init event handler and the pageLoad function is that the init event is raised while the page is loading, but before the page is ready.  When the init event is raised, the page has been loaded and the initial DOM tree is accessible, but some things such as images, applets, and other embedded objects most likely haven't been loaded and are not accessible.  You can use the init event to inject elements into the DOM tree or create other client components, but you shouldn't start executing your page's business logic during this event.  When the pageLoad function is called, the page and all of its media elements have been loaded and are rendered, so it's safe to do things such as activate controls, set timers, or begin animations.

Technorati tags: , ,


Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

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

Posted on March 4, 2008 07:13 by mcollins

Let's face it, one of the problems that has always plagued client-side development in the browser is that JavaScript can be a pain to debug.  As a developer, you have no knowledge if the browser is actually executing your code or what is happening when a page loads.  You refresh the page in the browser, wait, and see if your latest changes worked.  If not, you then have to mentally figure out what happened inside your script without really having any tools to see inside.  Sure, Microsoft makes a script debugger for IE, and sometimes script debugging does work inside of Visual Studio, but I've found a lot of times where the scripts won't load in the debugger or breakpoints that I set inside of Visual Studio aren't tripped.  When that doesn't work, I've typically had to fall back to putting alerts into my code and going through many popup message boxes to tell me what's going on.

Fortunately, ASP.NET AJAX has support to make debugging easier through the Sys.Debug JavaScript object.  The Sys.Debug object provides a trace method for outputting simple messages to a trace console and a traceDump method for outputting object contents to the trace console.  So what is the trace console?  If your browser has a JavaScript console then your messages will go there.  Internet Explorer may have one, but I've never found it.  So the other approach is to make your own inside of your web page, which turns out to be quite easy to do.  You simply create a TEXTAREA element inside of your web page and set its ID attribute to the value TraceConsole.  The Sys.Debug object will automatically find it and append your trace output to that element.

   1: <%@ Page Language="C#" AutoEventWireup="true" ... %>
   2:  
   3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   4:     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   5: <html xmlns="http://www.w3.org/1999/xhtml">
   6: <head runat="server">
   7:     <title>Untitled Page</title>
   8: </head>
   9: <body>
  10:     <form id="form1" runat="server">
  11:     <asp:ScriptManager ID="ScriptManager1" runat="server">
  12:     </asp:ScriptManager>
  13:     <div>
  14:     </div>
  15:     <textarea id="TraceConsole" rows="30" cols="60"></textarea>
  16:     </form>
  17:  
  18:     <script type="text/javascript">
   1:  
   2:     <!--
   3:         Sys.Application.add_init(function() {
   4:             Sys.Debug.trace('Initializing page.');
   5:             
   6:             // Create client components. Initialize the page.
   7:             
   8:             Sys.Debug.trace('Page initialized.');
   9:         });
  10:         
  11:         function pageLoad() {
  12:             Sys.Debug.trace('pageLoad called.');
  13:             
  14:             // Begin executing the business logic for the page. Attach
  15:             // event handlers to elements, etc.
  16:             
  17:             Sys.Debug.trace('pageLoad completed.');
  18:         }
  19:         
  20:         function pageUnload() {
  21:             Sys.Debug.trace('pageUnload called.');
  22:             
  23:             // The page is being unloaded. If you attached event
  24:             // handlers in pageLoad, detach them here to prevent
  25:             // memory leaks.
  26:             
  27:             Sys.Debug.trace('pageUnload completed.');
  28:         }
  29:     //-->
  30:     
</script>
  19:  
  20: </body>
  21: </html>

Here's a screen shot of the trace output in the page:

image

Of course, what happens if you don't want this console to show up on pages in the production environment.  You can wrap the trace console element inside of a Panel control, and then choose to show or hide the panel depending on whether the page is in debug mode or not.

   1: <%@ Page Language="C#" AutoEventWireup="true" ... %>
   2:  
   3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   4:     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   5: <html xmlns="http://www.w3.org/1999/xhtml">
   6: <head runat="server">
   7:     <title>Untitled Page</title>
   8: </head>
   9: <body>
  10:     <form id="form1" runat="server">
  11:     <asp:ScriptManager ID="ScriptManager1" runat="server">
  12:     </asp:ScriptManager>
  13:     <div>
  14:     </div>
  15:     <asp:Panel ID="DebugPanel" runat="server" Visible="false">
  16:         <textarea id="TraceConsole" rows="30" cols="60"></textarea>
  17:     </asp:Panel>
  18:     </form>
  19:  
  20:     <script type="text/javascript">
   1:  
   2:     <!--
   3:         Sys.Application.add_init(function() {
   4:             Sys.Debug.trace('Initializing page.');
   5:             
   6:             // Create client components. Initialize the page.
   7:             
   8:             Sys.Debug.trace('Page initialized.');
   9:         });
  10:         
  11:         function pageLoad() {
  12:             Sys.Debug.trace('pageLoad called.');
  13:             
  14:             // Begin executing the business logic for the page. Attach
  15:             // event handlers to elements, etc.
  16:             
  17:             Sys.Debug.trace('pageLoad completed.');
  18:         }
  19:         
  20:         function pageUnload() {
  21:             Sys.Debug.trace('pageUnload called.');
  22:             
  23:             // The page is being unloaded. If you attached event
  24:             // handlers in pageLoad, detach them here to prevent
  25:             // memory leaks.
  26:             
  27:             Sys.Debug.trace('pageUnload completed.');
  28:         }
  29:     //-->
  30:     
</script>
  21:  
  22: </body>
  23: </html>

You can see here on line 15 that I wrapped the TEXTAREA element with an ASP.NET Panel control named DebugPanel.  Initially the panel's Visible property is set to false, meaning that the Panel control and it's contents won't be rendered by the page when the page is requested.  In the code-beside file for the page, I handle displaying the Panel control when the Page.Load event is raised:

   1: public partial class _Default : System.Web.UI.Page {
   2:     protected void Page_Load(object sender, EventArgs e) {
   3:         ShowDebugConsole();
   4:     }
   5:  
   6:     [Conditional("DEBUG")]
   7:     private void ShowDebugConsole() {
   8:         DebugPanel.Visible = true;
   9:     }
  10: }

In the code-beside file for the page, by Page_Load handler is being called when the page is being requested by a user.  Inside of the event handler, it's invoking the ShowDebugConsole method.  The ShowDebugConsole method is simply setting the value of the Visible property on the DebugPanel control to true to indicate that the debugging console should be rendered in the page's output.  The real magic here is in the use of the Conditional attribute on the ShowDebugConsole method.  When the page is being compiled in debug mode, then the C# compiler will define the DEBUG symbol.  When the DEBUG symbol is defined, the compiler will compile the code inside of the ShowDebugConsole method, and thus the debugging console will be displayed in the rendered HTML and on the browser.  When the page is being compiled in release mode, the DEBUG symbol is not defined and the code inside of the ShowDebugConsole method is not compiled.  The ShowDebugConsole method will still be included in the generated IL code, but the method will be empty and will simply return to the caller.

The next part of the magic is how do you tell an ASP.NET application that it's running in debug mode versus release mode.  There are two ways of doing this.  If you're using an ASP.NET Web Application project for your web application, or if you are using a Web Deployment Project to compile and package your web application, then the build mode is determined by the compiler at build time.  For example, this is handled from the toolbar in Visual Studio by choosing between a debug build or a release build.  The other ASP.NET mode for web applications is to deploy the .aspx files side-by-side with the .cs files and ASP.NET will compile pages as they are requested.  In this case, you need some other way to tell ASP.NET to compile the pages in debug or release mode.  It turns out that this can be done using the web.config file:

   1: <?xml version="1.0"?>
   2: <configuration>
   3:     <system.web>
   4:         <compilation debug="true">
   5:             <assemblies>
   6:                 ...
   7:             </assemblies>
   8:         </compilation>

Above is a fragment of my web.config file.  Line 4 is the line that we need to focus on.  Notice that the debug attribute on the compilation element is set to true.  When this value is set, then the runtime ASP.NET compiler will build the pages in debug mode and will define the DEBUG symbol for the C# compiler.  Setting the value of the debug attribute to false will turn off debug mode for the web application.  You can therefore control whether the debugging console appears on your pages using the web.config file.

In summary, the Sys.Debug object provides a lot of advantages to JavaScript debugging at runtime over using the JavaScript alert function.  First, you don't need to deal with those annoying message boxes and removing them after you've fixed your bug.  Second, by using a little .NET and ASP.NET creativity, you can add debugging support to your pages that you can easily disable in the production environment by modifying your web.config file and not your source code.  The end result is that you have a page that is easier to debug and easier to maintain in the long run.

Technorati tags: , , ,


Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

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

Posted on March 3, 2008 21:53 by mcollins

When I hear people talk about AJAX, I often hear about the removal of page refreshes or the ability to asynchronously call web services on the server from the browser.  I see many developers around me using the AJAX Control Toolkit and calling that AJAX because of the watermark control or other controls, but I think that most developers miss the mark on the prime feature of AJAX: JavaScript.  Or at least, in my opinion, it's JavaScript.

I tried JavaScript a long time ago when it first came out.  I honestly did.  And I passed on it because it really didn't do what I wanted it to, or maybe I understood how to use it.  And it was a different time when each browser did things their own way.  To some extent, each browser still does things their own way, but at least they're getting closer.  But I bought the books about JavaScript programming, I read them, I tried the techniques, and I got too tired of dealing with browser differences and the fact that it was far easier to debug server-side code than client-side JavaScript code.

Flash forward a few years into the modern age of web development where Web 2.0 has made developing web applications cool again.  My interest in JavaScript was first aroused once again with two books that I found.  The first book, DOM Scripting: Web Design and JavaScript and the Document Object Model by Jeremy Keith and published by friends of ED, reintroduced me to JavaScript and helped me see what could be accomplished with JavaScript in the modern generation of browsers.  The next book, AdvancED DOM Scripting: Dynamic Web Design Techniques by Jeffrey Sambells and Aaron Gustafson and also published by friends of ED helped me to really understand the object-oriented nature of JavaScript, how to build JavaScript libraries, and how to find and take advantage of third-party JavaScript libraries such as Prototype, Script.aculo.us, and jQuery.

JavaScript, in its current incarnation, is a powerful and capable language and stands on its own when compared to the current masters of the programming landscape: C# and Java.  It is just as object-oriented as both languages, and in some ways a lot more flexible.  Most importantly, JavaScript is the language, unlike C# and Java, that is going to lead the Web 2.0 generation.  Kind of ironic for a language that was dismissed not so long ago as something that nuisances were made of.

If you set no other goals for yourself for 2008, make 2008 the year that you sit down and return to JavaScript.  It's a tool that needs to be in your toolbox, and when everyone else in the room is talking AJAX, you'll be the one actually doing it.  AJAX is more than XML and UpdatePanels.  It's all about JavaScript and the browser that is being controlled by your JavaScript.

Amazon.com: DOM Scripting

ISBN: 1590595335
ISBN-13: 9781590595336

Amazon.com: AdvancED DOM Scripting

ISBN: 1590598563
ISBN-13: 9781590598566

Technorati tags: ,


Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

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