Archive

Archive for the ‘JavaScript’ Category

Populating Select Lists in ASP.NET MVC and jQuery

September 25, 2009 David Longnecker Leave a comment

I’ve been working the last bit to find the best way to create/populate select (option) lists using a mixture of ASP.NET MVC and jQuery.  What I’ve run into is that the “key” and “value” tags are not passed along when using Json(data).

Here’s what I’m trying to pull off in jQuery: building a simple select drop down list.

var dd_activities = “<select id=’dd_activities’>”;
var count = data.length;
for (var i = 0; i < count; i++) {
 dd_activities += “<option value=’” + data[i].Key + “‘>” + data[i].Value + “</option>”;
}
dd_activities += “</select>”;

$(“#activities”).before(dd_activities);

Using some very basic key/value data:

[
 {"3","Text Value"},
 {"4","Another Text Value"},
 {"1","More boring values..."},
 {"2","Running out of values"},
 {"5","Last value..."}
]

Without any sort of name, I was at a loss on how to access the information, how to get it’s length, or anything.  FireBug was happy to order it up… but that didn’t help.
 
My first attempt was to use a custom object, but that just felt dirty—creating NEW objects simply to return Json data.
 
My second attempt matched the mentality of newing new anonymous Json objects and seemed to work like a champ:
 

[Authorize]

[CacheFilter(Duration = 20)]

public ActionResult GetActivitiesList()

{

    try

    {

        var results =

        _activityRepository

            .GetAll()

            .OrderBy(x => x.Target.Name).OrderBy(x => x.Name)

            .Select(x => new

                {

                    Key = x.Id.ToString(),

                    Value = string.Format(“[{0}] {1}”, x.Target.Name, x.Name)

                })

            .ToList();

 

        return Json(results);

    }

    catch (Exception ex)

    {

        return Json(ex.Message);

    }

}

 
Well, not beautiful, but returns a sexy Key/Value list that Json expects—and that populates our select list.
[
 {"Key":"3","Value":"Text Value"},
 {"Key":"4","Value":"Another Text Value"},
 {"Key":"1","Value":"More boring values..."},
 {"Key":"2","Value":"Running out of values"},
 {"Key":"5","Value":"Last value..."}
]
The next step was to get that out of the controller and into the data repository… pushing some of that logic back down to the database.
 

var criteria =

    Session.CreateCriteria<Activity>()

    .CreateAlias(“Target”, “Target”)

    .Add(Restrictions.Eq(“IsValid”, true))

    .AddOrder(Order.Asc(“Target.Name”))

    .AddOrder(Order.Asc(“Name”))

    .SetMaxResults(100);

 

var data = criteria.List<Activity>();

var result =

    data

        .Select(x => new

            {

                Key = x.Id.ToString(),

                Value = string.Format(“[{0}] {1}”, x.Target.Name, x.Name)

            })

        .ToList();

tx.Commit();

return result;

 
A bit of formatting, restrictions, push the ordering back to the database, and a tidy SQL statement is created.
 
The last touch is the return type.  Since we’re returning a “List” of anonymous types, the return type of GetActivitiesList() must be an IList.
 
That shrinks down my ActionResult to a single call.
 

try

 {

     return Json(_activityRepository.GetActivitiesList());

 }

 catch (Exception ex)

 {

     return Json(ex.Message);

 }

 
That works… and will work for now.  Though, I’ve marked it as a HACK in my code.  Why?  I’m honestly not sure yet.  Just a feeling.

Implementing IEPNGFix as a Reusable Control

January 30, 2009 David Longnecker 4 comments

Even with IE 8.0 on the horizon, a great deal of our internal users are still using IE 5.5 and 6.0.  While, for the most part, our current coding techniques are unaffected, we did move to using PNG files quite a while ago and are faced with rendering issues as the target audience for a few of our produces expands.

To solve those issues, I’ve been using TwinHelix’s IE PNG Fix behavior with a great deal of success; however, I dislike keeping track of multiple files and references between projects.  It made more sense to make it a reusable control and include it in our shared architecture library.  When Angus releases a new implementation, then I only need to update the control and push out the updated libraries rather than touching HTML in each project.

Here’s how:

1. Download the latest version of IE PNG Fix from here.

2. Add the IEPngFix.htc, blank.gif, and IEPngFix_tilebg.js (if using 2.0 Alpha 3) into your project.  Mark all three files as Embedded Content.

3. Create a basic CSS file that can be added to pages and call the IEPngFix behavior.  Use the full path to the Web Resource (we’ll add those in the next step).  It’s sensitive to the namespace of your project.

img, div, .pngfix, input {

    behavior: url(‘<%=WebResource(“Resources.IEPngFix.htc”)%>’);

}

3. Modify the Properties/AssemblyInfo.cs file and add the approprate Web References.

[assembly: WebResource("Resources.IEPngFix.css", "text/css",

       PerformSubstitution = true)]

[assembly: WebResource("Resources.IEPngFix.htc", "text/x-component",

       PerformSubstitution = true)]

[assembly: WebResource("Resources.IEPngFix_blank.gif", "image/gif")]

[assembly: WebResource("Resources.IEPngFix_tilebg.js", "text/javascript")]

Notice that the HTC behavior file is an “x-component”.  For a full list of MIME references, check out the w3schools.com.  Also, perform substitution allows us to use dynamic calls of resources—within resources, such as in our CSS file.

4. Create a new class that inherits from CompositeControl.  This control will add the javascript and CSS references into our projects.  Override the OnPreRender method and populate the calling Page’s header with the links to our two files.

protected override void OnPreRender(EventArgs e)

{

       // Base Code: http://www.twinhelix.com/css/iepngfix/

       // Include JavaScript for tiled background support.

       string javascriptInclude =

              Page.ClientScript.GetWebResourceUrl(GetType(),

             “Resources.IEPngFix_tilebg.js”);

           

       var jsLink = new HtmlLink

              {

                     Href = javascriptInclude

              };

       jsLink.Attributes.Add(“type”, “text/javascript”);

       Page.Header.Controls.Add(jsLink);

           

       // Include Css file that calls HTC.

       string cssInclude =

              Page.ClientScript.GetWebResourceUrl(GetType(),

             “Resources.IEPngFix.css”);

           

       var cssLink = new HtmlLink

              {

                     Href = cssInclude

              };

       cssLink.Attributes.Add(“rel”, “stylesheet”);

       cssLink.Attributes.Add(“type”, “text/css”);

       Page.Header.Controls.Add(cssLink);

 

       base.OnPreRender(e);

}

That’s it.  Build and add the new control to your project.  You can then add a new forms page and drop the control into the page.  I prefer, however, to keep a “DefaultPage” and inherit my pages from it—add once, apply to all. :)

protected void Page_Load(object sender, EventArgs e)

{

       Page.Controls.Add(new IEPngFix());

}

Here we can see the rendered control. The PNG has a transparent background and without IEPngFix shows up as a white box rather than seeing the black background of the page.  Works like a champ!

IEPngFix in Action

Thanks again to Angus Turnbull for this excellent behavior!

Tags: , , , ,

IE6 Causes Z-Index Nightmares…

Rather than update the post from yesterday, this chaos deserves it’s own post.

Yesterday, I discussed layering Modal Popup Extenders with the Update Progress controls.  In IE7, FF3, and, well, most everything except IE6, it works like a champ as-is.

The “bug”?  After quite a bit of research, the problem revolves around the following issues:

  • lack of support for the { position: fixed } property,
  • lack of support for the { right; bottom} properties,
  • … unreliable suport for {height: 100%, width: 100% } properties,
  • general pain and suffering
  • <SELECT> tags (or ASP:DropDownList objects) exist above any other z-index,

I’m sure there were other issues.  Really.

After spending a good part of the day trying code, looking it up on QuirksMode, and trying again, I have somewhat of a solution; however, I still greatly dislike how it works in IE6.

On the MasterPage, I have a single UpdateProgress that isn’t associated to a specific UpdatePanel.  Therefore, it’ll catch all Async postbacks (and I only have ONE UpdateProgress control).

<asp:UpdateProgress

runat=”server” DisplayAfter=”100″ ID=”UpdateProgress”>

<ProgressTemplate>

<div class=”UpdateProgressModalBackground”></div>

<div class=”UpdateProgressPanel”>

<h3>Please wait…</h3>

<img src=”Images/ajaxbar.gif”
alt=”Please wait…”

style=”text-align: center; width: 100%; height: 10px; />

</div>

</ProgressTemplate>

</asp:UpdateProgress>

This, again, references our UpdateProgressModalBackground and UpdateProgressPanel styles.  These two styles are unchanged from the post yesterday.  Here they are again for reference:

/* UpdateProgressPanel is above EVERYTHING ELSE,

even other modal popups */

.UpdateProgressPanel

{

       z-index: 99999999;

       background-color:#fff;

       color:#fff;

       width: 200px;

       text-align: center;

       vertical-align: middle;

       position: fixed;

       bottom: 50%;

       left: 45%;

       padding: 10px;

       border: solid 2px #5D7B9D;

}

 

.UpdateProgressModalBackground

{

    z-index: 99999998;

    background-color: #6D7B8D;

    position: fixed;

    top: 0;

    left: 0;

    height: 100%;

    width: 100%;

    min-height: 100%;

    min-width: 100%;

    filter: alpha(opacity=50);

    opacity: 0.5;

    -moz-opacity: 0.5;

}

The UpdateProgress and these two classes work just fine in IE7+, FF2+.  So, now to fix IE6..

So, what’s the difference in IE6?  Well, we can’t use the positioning attributes in the above classes–-they won’t work properly. 

Issue #1 – Fitting the Popup and Background Without Positioning Attributes

Searching the web, I found an article by Damien White discussing his his same pains with this.  His solution involved using the IE-specific CSS “expressions” to calculate the height and width of the window.

height:

expression(

        document.documentElement.scrollTop +

        document.documentElement.clientHeight + “px”);

 

width: expression(document.body.clientWidth + “px”);

However, at least for me, Damien’s expressions wouldn’t handle scrolling down the page.

Damien explains:

The thinking behind this was to take the window height (which document.documentElement.clientHeight gives us) and then add the scroll top position, which will give us the upper portion if the user scrolls up.  The problem shows itself when the user scrolls down; that area is not covered.  The good thing about this is that I didn’t need to mess with the body height, but the solution isn’t optimal in the long haul.

That’s a bad deal because that’s the whole point!  Reading a bit more, there was a comment from Kunal Mukherjee on Damien’s post that solved the problem.

Kunal’s expressions looked at the scrollHeight of the window as compared to the offsetHeight and returned the larger.

height: expression(

document.body.scrollHeight > document.body.offsetHeight
? document.body.scrollHeight
: document.body.offsetHeight + ‘px’ )
;

Actually, that works really well. Cool.

Finally, I’d recommend, as Damien did, breaking out your CSS into two files—one for “IE6” and one for everyone else.  This is easily done using the IE-specific conditional statements.

<!–[if lt IE 7]>
<link rel=”stylesheet” type=”text/css” href=”App_Themes/ie6/ie6.css” />
<![endif]–>

I also included !important flags on each of the properties in the ie6.css file—just to be safe.

Issue #2 – IE6 Pushes <SELECT> tags above everything else…

This is where the solution gets dicey; however, I’m relying on Kunal’s solution again.  In his comment, he pointed out a way to hide <SELECT> tags in IE6 without causing the disappearing act that the ModalPopupExtender causes—cover them with an IFRAME.

To me, this hack seems… sketchy at best, but it works.

In the ProgressTemplate of the UpdateProgress control, add in the IFRAME.

<iframe id=”UpdateProgressHideSelect”></iframe>

In the default.css (or the non-ie6.css, whatever you’ve called it), I recommend setting the iframe’s style to {display: none}—it isn’t needed outside IE6, don’t render it. :)

On the ie6.css, add the UpdateProgressHideSelect in—along with another expression to place the iframe over the entire page (like the standard BackgroundCssClass of a ModalPopupExtender):

#UpdateProgressHideSelect

{

    z-index: 15000;

    position: fixed;

    top: 0;

    left: 0;

    background-color: #fff;

    border: none;

    filter: alpha(opacity=0);

    -moz-opacity: 0;

    opacity: 0;

    height: 100%;

    width: 100%;

    display: inline !important;

}

 

* html #UpdateProgressHideSelect

{

    position: absolute;

    height: expression(

document.body.scrollHeight > document.body.offsetHeight

? document.body.scrollHeight

: document.body.offsetHeight + ‘px’);

}

The z-index of 15000 for the iframe ensures that it appears above the normal 10000 of a ModalPopupExtender panel; however, under our crazy high UpdateProgress control.

Problem solved—for now.

Here’s how they look, side by side.

FireFox 3:

FireFox 3 Output

Nice and clean, properly centered given the size of the box and window size.  Can see drop down lists and MPE behind the UpdateProgress, but cannot access them.

IE 7:

IE7 Output

Output as expected and where expected.  Can see drop down lists and MPE behind the UpdateProgress, but cannot access them.

IE 6:

IE6 Output

Output as expected—basically where expected.  Drop down lists are hidden behind the IFRAME to prevent input.  Other controls are visible, including the MPE, but behind the background.

What fun!

Visual Studio 2008 and .NET 3.5 SP1 Beta

The blogs are abuzz this morning after the first beta release of the VS2008 and .NET 3.5 SP1.   Download it here.

In my opinion, this isn’t a service pack—this is a new version!

There are quite a few bug fixes (what you normally associate with a service pack), but also a huge list of new additions and improvements.

From Somasegar:

Traditionally our service packs address a range of issues found both through customer and partner feedback as well as our own internal testing.  While this service pack holds true to that theme and delivers updates for these types of issues, it also builds on the tremendous value that Visual Studio 2008 and .NET Framework 3.5 deliver today and enables an improved developer experience by adding a number of additional components that cover a range of highly requested customer features. For example, the service pack is the first release for Visual Studio 2008 that delivers full support for SQL Server 2008 and the ADO.NET Entity Framework.

I’ve posted a few links at the end of the post to the more extensive sources right now, take a look and get ready for the plunge.

So, what am I most excited about?

  • ADO.NET Entity Framework – I’m hoping that the “real” release motivates Oracle to develop provides for the entity framework and my dream of LINQ-esque connections to Oracle will be realized.
  • ASP.NET Routing Engine – As the MVC framework gets closer to a production reality, it’s very motivating to see the underpinnings already in place.
  • VS2008 Performance Improvements – Anything has to be an improvement. :(
  • JavaScript Code Formatting – Sweet, now if I can only get JavaScript intellisense to work. :(
  • LINQ Debug Support – Very nice, love seeing the generated SQL right there at debug time.

There are also lots of updates to WCF and WPF.  Hopefully this summer I’ll have more time to use these .NET 3.0 technologies and maybe be a bit more excited. ;)

Visual Studio 2008 GUI/Tools

The Web Developer Tools team has released a comprehensive list of designer bug fixes, IIS templates and modules, formatting changes, intellisense upgrades, and more on their blog.

MVC and URL Routing

Phil Haack details the effects of the URL routing changes on the MVC Preview releases as well as how it affects the upcoming Preview 3.

Everything

ScottGu, as always does an excellent job tying everything up together—designer, framework, and tooling.

Now, if ReSharper 4.0 would EVER get to RTW before we’re ready to VS2009, it’d be super!

Update Obsolete JavaScriptSerializers

April 2, 2008 David Longnecker Comments off

I have three extension methods in a shared library we use that convert Json back and forth.  The “obsolete” JavaScriptSerializers work just fine—as long as I ignore the warnings from Visual Studio whenever I modify the library.

Along with a few other changes, I set off today to update those extension methods to the new DataContractJsonSerializer.  What a pain.

Here’s what it takes—step-by-step.

1. Decorate all of the classes you wish to serialize with the [Serializable].  This is easy enough for internal, controlled classes.  The [DataContract] attributes do not appear to be needed (feedback?).

[Serializable]

public sealed class School { }

2. Change your two to three lines of simple code into painful MemoryStreams.

The old code, which can be found here, was pretty darned simple.  Use the JavaScriptSerializer and either Serialize or Deserialize.  One returned a string, one returned the object.

Unfortunately, the new DataContractJsonSerializer is a bit more complicated on both sides.

The ToJson extension method:

public static string ToJson(this object obj)

{

var serializer =

new DataContractJsonSerializer(obj.GetType());

      

using (var stream = new MemoryStream())

       {

             serializer.WriteObject(stream, obj);

             return Encoding.Unicode.GetString(stream.ToArray());

}

}

The FromJson extension method:

public static T FromJson<T>(this object obj)

{

var returnObject =

Activator.CreateInstance<T>();

       var serializer =

new DataContractJsonSerializer(returnObject.GetType());

 

using (var stream = new

MemoryStream(Encoding.Unicode.GetBytes(obj.ToString())))

{

              return (T) serializer.ReadObject(stream);

}

}

Gone are the Serialize and Deserialize methods; replaced by ReadObject and WriteObject.  Unfortunately to read/write, a stream is required.  It’s not ‘terrible,’ but is another object to create and destroy.

3. Rerun unit tests.

Thank goodness for tests—nuff said. :)

That’s it.  So far, both the tests and the few places I’d ran additional, manual tests of data objects<->Json, things have worked well with these new methods.  I’d love to hear/understand WHY the methods changed and what benefits dumping to/from streams provides us for extensibility.  I’m sure there’s a reason.

Oh, and Visual Studio doesn’t throw warnings anymore—yay.

IE8 – JavaScript window.open invalidates session?

March 14, 2008 David Longnecker 6 comments

Anyone else having this problem?  On web sites (my own included) that open a new window with the JavaScript window.open method, that new window no longer has access to session variables from the parent.

In IE7 and FF2, if I have a page that:

Session[”MyVar”] = “Hello, world”;
ClientScript.RegisterClientScriptBlock(
     this.GetType(),
     ”PopupReport”,
     ”<script language=’javascript’>window.open(‘RunReport.aspx’)</script>”);

Then, RunReport.aspx could read Session[”MyVar”] and output ‘Hello, world’.  That works fine.

Unfortunately, in IE8, the spawned window from window.open doesn’t have access to those session variables.  I ran across this again reading through some Microsoft Training materials—the new window couldn’t tell I was logged in—and there was nothing (that I could figure out) to fix it.

Going into IE7 mode doesn’t appear to fix it either, which is a bummer.

Ideas?

 

Categories: JavaScript, Microsoft

New Articles Section and AJAXing in .NET Article

January 11, 2008 David Longnecker 7 comments

Last year, I had several requests to take my “longer” blog posts and series and make articles out of them.  I understand where readers are coming from and empathize—reading 4–5 posts that are 2–3 pages long across a week of entries can be… very disconnected.  In addition, code formatting, images, and such are difficult to get exactly right on a blog image (I tend to avoid capturing code in images so that it’s still searchable).

So, to that, I’ve added a new section to the blog, Articles.

In this, I’ll tend to focus on using the blog for short bits of information, key points, and summaries of various topics.  The Articles section will be for the longer, in-depth reviews of technologies, practices, and guides.

The first post in this section is from the recent AJAXing in .NET series

AJAXing in .NET – #3 – Live Volta and Script#

January 8, 2008 David Longnecker Comments off

This is the third and final part of the series looking at several “AJAXing” technologies for .NET—ranging from “old school” JavaScript to new, VERY alpha technologies like Volta.

Post 1:

  • Example #1 – Plain ASP.NET Page with PostBacks
  • Example #2 – ASP.NET AJAX with UpdatePanels

Post 2:

  • Example #3 – Standard HTML and JavaScript
  • Example #4 – ASP.NET AJAX Framework and JavaScript

Post 3 (this post):

  • Example #5 – Nikhil Kothari’s Script#
  • Example #6 – Microsoft Labs Live Volta

This post, to be totally honest, will be short.  Why?  After FAR too long of dinking with them, I simply can’t get either solution to work.  Here’s where I’m at NOW.  Once I get these working, I’ll better evaluate them against current JavaScript solutions.  That said, the sheer idea of learning a language to avoid writing a language seems odd at best…

#4. Microsoft Live Labs Volta

I previewed Microsoft Live Labs Voltron Volta back in December and was quite impressed—a Microsoft-designed solution for creating type-safe JavaScript within C#.  I wasn’t thrilled with the special project layouts or 45K of compiled Volta code that attached to each project; however, it’s in … alpha, I expected that.

In our Volta code-behind, we have the following logic. 

public partial class VoltaPage1 : Page

{

 

Select photoList;

Image photoPreview;

 

public VoltaPage1()

{

InitializeComponent();

photoList.Change +=

new HtmlEventHandler(photoList_Change);

}

 

void photoList_Change()

{

photoPreview.Style.Display = “block”;

       photoPreview.Src =  “Images/” + photoList.Value;

}

 

partial void InitializeComponent()

{

photoList =

Document.GetById<Select>(“PhotoList”);

photoPreview =

Document.GetById<Image>(“PhotoPreview”);

}

}

That compiles, is easy to read, and type safe.  Neato.  The HTML code is identical to our prior examples, so a simple copy and paste from there.  That saves some time.

The problem?

It appears that Volta doesn’t appreciate resources that are not embedded.  I’ve posted up to the Volta community groups and will slowly work through either a) rectifying what the correct code should be or b) accepting that this is “outside the scope” of the current Volta design.  I can’t fathom having hundreds of embedded resources in a project—for simple graphics.

Finally, it appears the problem that Henry discussed in my last post also exists in Volta—Document.GetById isn’t case sensitive at all. :(   Thanks Henry for the heads-up to keep that in mind!

[Update: 10 January 2008 : Danny van Velzen’s explaination in the forums helped out a lot.  At this time, as expected, the CTP simply doesn’t support anything besides embedded resources; however, has logged the request as a future work item.  *cheer*  To work around this problem, he recommended a post-build event, which is basically a batch command.  I’ve tried that out and this example works like a champ!

The only gotcha is figuring out where to copy the files to and what correlates to the “root” of your application.  It’s not the root of our bin\Debug or bin\Output.  It’s the Volta directory underneath.  With that information, you can write up a quick event:

xcopy /i /y “$(ProjectDir)Images” “$(TargetDir)Volta\Images”

Given this simply copies the images for this prototype project; however, you could use these events to copy pages, .css, or anything that you didn’t feel like “embedding” into your project.  As I noted on the Volta communities post—I’m looking forward to this maturing and having this functionality built into the compiler. :)

With this updated information, I can finally compare implementation with our other options..

  • HTML Code: 9, Code Behind: 5 with whitespace and method names.
  • To me, this code is just as simple to read as JavaScript—maybe a bit easier because it’s strongly typed and hooks up event handlers just like .NET code.
  • All tests come back clean—and Volta supports FireFox debugging out-of-the-box, which is great because I have come to prefer FireBug over the IE Developer Toolbar.
  • Pitfalls are, at this time, the fact it’s VERY alpha and still in development.  Most of the DOM appears to be ready to go, however, issues like the embedded resources make this impractical for production use at this time.  In addition, Volta requires a special project type for its tier-splitting—you can’t just drop some Volta/JavaScript into a project and go.  That’s a HUGE drawback to me.  I’d love to see the technology integrated into the existing web platform so I could program JavaScript like this against Web Forms, MVC, or whatever.

#5. Script# 0.4.5.0

The latest build of Script#, 0.4.5.0, appears to have a few glitches in the Scriptlet editor (cutting out the top and bottom lines, throwing compile errors when they don’t exist, etc) and after blowing through about a dozen project—it just won’t compile.  Period. 

Here’s the code for the class.  It looks right, from what I have as examples, but blows up that I have extra “}” (which is a known bug apparently) and believes that my IDisposable doesn’t exist, though I see it right there. :(

using System;

using System.DHTML;

using ScriptFX;

using ScriptFX.UI;

 

public class Viewer : IDisposable

{

    private SelectElement _photoList;

    private ImageElement _photoPreview;

    private DOMEventHandler _photoListOnChangeHandler;

 

    public Viewer()

    {

        _photoListOnChangeHandler =

new DOMEventHandler(PhotoListOnChange);

        _photoList =

(SelectElement)Document.GetElementById(“PhotoList”);

        _photoList.AttachEvent(“onchange”, _photoListOnChangeHandler);

    }

 

    public void PhotoListOnChange()

    {

        _photoList =

(SelectElement)Document.GetElementById(“PhotoList”);

        _photoPreview =

(ImageElement)Document.GetElementById(“PhotoPreview”);

 

        _photoPreview.Src = “Images/” + _photoList.Value;

    }

 

    public void Dispose()

    {

        if (_photoListOnChangeHandler != null)

        {

            _photoList =

(SelectElement)Document.GetElementById(“PhotoList”);

            _photoList.DetachEvent(“onchange”, _photoListOnChangeHandler);

 

            _photoListOnChangeHandler = null;

        }

    }

}

I’m going to keep working with it (because the prototypes I have gotten working have worked well, but also don’t seem to work under 0.4.5.0) and I’ll update this post when I have more information.  If anyone out there is a Script# expert and has 0.4.5.0 up and going with VS2008, email me, please. :) .

AJAXing in .NET – #2 – Pure JavaScript and AJAX Framework JavaScript

January 7, 2008 David Longnecker 7 comments

This is the second in the three part series looking at “AJAXing” technologies for .NET developers.

Post 1:

  • Example #1 – Plain ASP.NET Page with PostBacks
  • Example #2 – ASP.NET AJAX with UpdatePanels

Post 2 (this post):

  • Example #3 – Standard HTML and JavaScript
  • Example #4 – ASP.NET AJAX Framework and JavaScript

Post 3 (this post):

  • Example #5 – Nikhil Kothari’s Script#
  • Example #6 – Microsoft Labs Live Volta

In these two examples, we’ll take a look at the differences of JavaScript programming—between “standard” JavaScript and using the methods and objects provided by the ASP.NET AJAX Framework, but without using the actual server-side controls.

#3. Standard HTML and JavaScript

The next example is a classic—clean HTML and a JavaScript function.  This is a standard HTML page without any “fancy” .NET or framework technologies.  How does this compare to .NET?

In our header, there’s a simple JavaScript function to handle the OnChange event of the drop down list:

<script type=”text/javascript” language=”javascript”>

function LoadPhoto()

{

PhotoPreview.style.display = ‘block’;

       PhotoPreview.src = Images/ + PhotoList.value;

}

</script>

Next, our HTML.

<select id=”PhotoList” onchange=”LoadPhoto()”>

<option label=”ABCs – Blocks” value=”abc_blocks.jpg” />

       <option label=”ABCs – Chalkboard #1″ value=”abc_board.jpg” />

       <option label=”ABCs – Chalkboard #2″ value=”abc_board2.jpg” />

       <option label=”Graduation” value=”capandgown.jpg” />

</select>

<br /><br />

<img id=”PhotoPreview” style=”display: none; src=”" />

As we can see from the Fiddler capture, the HTML, of course, is EXTREMELY thin here and, since postback events are not firing, the page ever reloads, simply loads the resources (in this case, images) as necessary.  In addition, the images are cached, so additional downloading isn’t necessary..

  1. HTML Code: 8 + 2 4 JavaScript function lines (see below).
  2. I may be a bit older, but this is how it “used” to be done, so it’s readable to me.  For those unfamiliar with JavaScript may be turned off by it.
  3. IE 7 and Safari (*shocked*) work, however, Opera and FireFox are broken.  See details below.
  4. As you’ll read below, managing compatibility between JavaScript functionality on each platform is a HASSLE and can be a major turn off for DIY JavaScript AJAX.

Details for Compatibility Issues:

IE 7 and Safari actually render correctly because they use the “label” property from HTML 4.0 for option boxes.  FireFox and Opera turn out blank.  To have options in those browsers, we’ll need to place the text in the body of the tag. 

<option label=”ABCs – Blocks” value=”abc_blocks.jpg”>
ABCs – Blocks
</option>

That fixes Opera, but FireFox is still broken.  Why?  Because FireFox can’t read the DOM directly, you have to populate each element into a variable and manipulate the variable.  Updating our JavaScript to the following code will fix the problem.  Also, since this method works in all the OTHER browsers, this would be the “preferred” method to accomplish this.

var photoPreview = document.getElementById(‘PhotoPreview’);

var photoList = document.getElementById(‘PhotoList’);

 

photoPreview.style.display = ‘block’;

photoPreview.src = ‘Images/’ + photoList.value;

While this code works, you can run into challenges for browsers that do not yet support getElementById.

#4. ASP.NET AJAX Framework and JavaScript

In our last example, browser compatibility was the most challenging pitfall to overcome.  If we want to write our own JavaScript, but would like the padding of a framework, we can use the ASP.NET AJAX framework without all the fancy server-side controls.

When we add a new AJAX Web Form, a single control is added, the ScriptManager.  In this example, we’re not going to use UpdatePanels, but simply access the objects provided for us by the ScriptManager.

The JavaScript in our Header:

<script type=”text/javascript”>     

function LoadPhoto() {    

       $get(‘PhotoPreview’).style.display = ‘block’;

       $get(‘PhotoPreview’).src = ‘Images/’ + $get(‘PhotoList’).value;

}

</script>

And the HTML:

<asp:ScriptManager ID=”ScriptManager1″ runat=”server” />

<select id=”PhotoList” onchange=”LoadPhoto()”>

<option label=”ABCs – Blocks” value=”abc_blocks.jpg”>

              ABCs – Blocks</option>

<option label=”ABCs – Chalkboard #1″ value=”abc_board.jpg”>

              ABCs – Chalkboard #1</option>

<option label=”ABCs – Chalkboard #2″ value=”abc_board2.jpg”>

              ABCs – Chalkboard #2</option>

<option label=”Graduation” value=”capandgown.jpg”>

              Graduation</option>

</select>

<br /><br />

<img id=”PhotoPreview” style=”display: none; src=”" />

The $get alias simply returns browser-compatible JavaScript for getElementById.  You can read more about how this alias works on Irena Kennedv’s blog.  The short is that this alias will generate the correct code based on the browser.

The Fiddler logs are nearly identical to the plain JavaScript; however, the .aspx page is a bit heavier.

  1. HTML Code: 9 + 2 JavaScript function lines.
  2. Aside from familiarization with the aliases and framework functions in JavaScript, this code is nearly identical to the
  3. The only difference at this point is that the code allows us to access the $get alias and, most importantly, cross-browser compatibility handled by the framework—not you.
  4. Past the bit of losing “update panels”, this is a nice middle ground between pure JavaScript and pure server-side AJAX Framework.

This methodology also has another benefit: you can directly access web services (.asmx) from your JavaScript client code.  For more information on this topic, read Calling Web Services from Client Script.  I haven’t done a lot with this yet, but have a few notes sitting around to give it a try and see how it compares when reading actual data across the wire.

AJAXing in .NET – #1 – Plain ASP.NET and ASP.NET AJAX

January 7, 2008 David Longnecker 2 comments

With the release of Microsoft Live Labs Volta, Nikhil Kothari’s recent update of Script# to support VS 2008, the ASP.NET AJAX Library’s new functionalities, and good ‘ol JavaScript—developers are not limited on AJAX solutions for the Microsoft platform.  Given, JavaScript can be on any platform, I tend to focus more on .NET solutions. :)

One of my holiday projects was to weigh and see exactly what went back and forth across the wire for each of these technologies and compare that to:

  • Implementation lines of code,
    • I don’t count using statements, headers, and “required” coding lines, simply those lines that implement the solution.
  • Intuititiveness of code,
    • Does the code make sense to write?
  • Browser support,
    • Does it work and look the same on IE 7.0, FireFox 2.0, Opera, and Safari?
  • Weight of transmissions (using Fiddler).
    • How much data is going across the line for comparable transactions?
  • Pitfalls?
    • What are the gotchas?

Download Source Code : Download Project Solutions (coming soon)

Note: This project contains two solutions, one for Volta project and one for all the others.

To make this a bit easier to read (and to write :) ), I’ve broken the content into a series of posts.

Post 1 (this post):

  • Example #1 – Plain ASP.NET Page with PostBacks – Seeing our prototype page with standard ASP.NET—no AJAX.  This will provide our baseline.
  • Example #2 – ASP.NET AJAX with UpdatePanels – The “default” implementation of the ASP.NET AJAX Framework—using UpdatePanels to manage partial rendering with “postbacks” still happening in the background.

Post 2:

  • Example #3 – Standard HTML and JavaScript – This is the “old” way to do things: directly manipulating the DOM.
  • Example #4 – ASP.NET AJAX Framework and JavaScript – Manipulating the DOM using the aliases and cross-browser compatibility features of the AJAX Framework.

Post 3:

  • Example #5 – Nikhil Kothari’s Script# – Script# is a scripting solution that sits on top of the C# development environment.
  • Example #6 – Microsoft Labs Live Volta – Previewed before, we’ll build the same example as the rest of the examples in Volta for comparison.

Now, let’s get started!

#1. Plain ASP.NET Page – Postbacks

Moving into .Net, let’s start with a simple ASP.NET page—no AJAX involved.  This page has a drop down list (PhotoList) and an image control (PhotoPreview)—populating the image control OnChange of the drop down list.

<asp:DropDownList ID=”PhotoList” runat=”server” AutoPostBack=”true”

OnSelectedIndexChanged=”PhotoList_SelectedIndexChanged”>

<asp:ListItem Text=”ABCs – Blocks” Value=”abc_blocks.jpg” />

<asp:ListItem Text=”ABCs – Chalkboard #1″ Value=”abc_board.jpg” />

<asp:ListItem Text=”ABCs – Chalkboard #2″ Value=”abc_board2.jpg” />

<asp:ListItem Text=”Graduation” Value=”capandgown.jpg” />

</asp:DropDownList>

<br /><br />

<asp:Image ID=”PhotoPreview” runat=”server” Visible=”false” />

In our code behind:

protected void PhotoList_SelectedIndexChanged(object sender, EventArgs e)

{

PhotoPreview.ImageUrl = “~/Images/” + PhotoList.SelectedValue;

       PhotoPreview.Visible = true;

}

Using Fiddler, an HTTP debugging tool, we can see that each time the page is requested, it posts back and grabs the image.  It’s also important to note that there isn’t any caching at this point.  Notice how events #39 and #43 request the same image and transmit it.

Using our scale above:

  • HTML Code: 9, Code Behind: 2
  • Being standard HTML and .NET code-behind, this is easily readable and makes sense. 
  • As we can see from the image below, the page looks much the same on every browser (given, it’s pretty basic).  The browsers, clockwise from top-left, are: Safari b3, IE 7, Opera 9, and FireFox 2.
  • Avoid postback “flash” is the most common, I think, to implement some sort of AJAX technology—cleaning up a UI and improving the user experience.  The lack of caching (with the post back) is also a trouble; however, caching could be implemented with additional coding.

#2. ASP.NET AJAX with UpdatePanel

Our first method would be the standard ASP.NET AJAX technique—surrounding those two controls with an UpdatePanel and adding a ScriptManager to the page.

<asp:ScriptManager ID=”ScriptManager” runat=”server” />

<asp:UpdatePanel ID=”UpdatePanel” runat=”server”

UpdateMode=”Conditional”>

<ContentTemplate>

<asp:DropDownList ID=”PhotoList” runat=”server”

AutoPostBack=”true”

OnSelectedIndexChanged=”PhotoList_SelectedIndexChanged”>

<asp:ListItem Text=”ABCs – Blocks” Value=”abc_blocks.jpg” />

<asp:ListItem Text=”ABCs – Chalkboard #1″ Value=”abc_board.jpg” />

<asp:ListItem Text=”ABCs – Chalkboard #2″ Value=”abc_board2.jpg” />

<asp:ListItem Text=”Graduation” Value=”capandgown.jpg” />

</asp:DropDownList>

<br /><br />

<asp:Image ID=”PhotoPreview” runat=”server” Visible=”false” />

</ContentTemplate>

</asp:UpdatePanel>

While our UI hasn’t changed, our HTTP traffic has changed quite a bit.  Here we can see the WebResource and ScriptResource files pull down to the local client and cache as well as the first load of the page.  What is interesting here is that on request #89, I’ve rerequested the capandgown.jpg image, but it never re-requests it, the cached image just loads on the client.  Good deal and MUCH faster.

Using our scale above:

  • HTML Code: 14, Code Behind: 2
  • This is the basic way of implementing the ASP.NET AJAX Framework—enclosing existing controls in panels and letting partial rendering do it’s magic.  I see this as very intuitive syntax.
  • Functionality is identical on all four platforms; this is because the ASP.NET AJAX framework handles browser support for us via ScriptManager.
  • As you can see from the Fiddler log, this page is extremely heavy—trading off smooth performance during usage for a resource load at the page load.