Dan Maharry

TinyMCE, .NET, UpdatePanels and DataBinding

by

(In which the question of getting TinyMCE to DataBind successfully in UpdatePanels is partially solved, but Chrome refuses to play nicely.)

There seems to be a common cry of agony when you try to stick a TinyMCE-adorned textarea in an UpdatePanel. Partial page updates strip the iFrame that TinyMCE’s init script lays onto the textarea. The UpdatePanel also seems to prevent TinyMCE’s built-in trigger from updating the underlying textarea in non-IE browsers (oh the irony) which means that if you try and update values to a database, the FormCollection at the back of the page never gets the new value and the database doesn't get updated.

TinyMCE's download page has an alpha .NET wrapper for TinyMCE which I’m using here by the way. Chris de Vos has used some of the solution described below to implement an AJAX extender control which applies TinyMCE to a designated control. My own version of ‘TinyMCE.NET’ which doesn’t use gzip compression but which does embed the TinyMCE scripts into the DLL can be downloaded here as a .NET 3.5 solution. If you have any improvements on it, please let me know. Download it here.

Textarea loses TinyMCE wrapper in Partial Postbacks

There are two approaches that .NET has for fixing this issue. The first is to use the page’s ScriptManager to re-run the call to TinyMCE.Init whenever the UpdatePanel containing the textarea is posted back asynchronously. So then, if we have a function which generates a call to TinyMCE.init (called GenerateInitCall), then we can just make this call.

ScriptManager.RegisterStartupScript(
this, this.GetType(), this.ClientID + "_ajax", GenerateInitCall(), true);

The alternate approach comes from Stefan (steho706), who figured out how to use the MS AJAX javascript library to remove and then re-add the TinyMCE skin to the textarea. The original thread is here on forums.asp.net. His solution has three parts. It works best if your page contains a button that causes the partial postback.

1. When the partial postback is triggered, save the tinyMCE value back to the textarea associated with it. If you’re using a button of some sort to initiate the postback, that means associating the following function to its onClick (onClientClick if you’re doing it in .NET) event.

function UpdateTextArea()
{ 
tinyMCE.triggerSave(false, true); 
} 

If you’re using something other than a button - for example, a command link in a DataGrid, you’ll need to attach the function to the initializeRequest event that the MS AJAX javascript library makes available for partial postbacks via its client-side PageRequestManager.

Sys.WebForms.PageRequestManager.
getInstance().add_initializeRequest(UpdateTextArea);

If you’re not familiar with this, it works pretty much the same as the asp.net page lifecycle but is completely client-side. MSDN has a good introduction to it here.

2. As the partial postback request begins, unload the TinyMCE editor from the page. Note that the function tests whether the button clicked to cause the postback is the one associated with the TinyMCE textarea. As noted earlier this makes it more awkward if buttons aren't what is causing the postback. Use the PageRequestManager's BeginRequest event to trigger the function.

Sys.WebForms.PageRequestManager.
getInstance().add_beginRequest(BeginRequestHandler);function BeginRequestHandler(sender, args)
{
// Fix to make tinyMCE work with UpdatePanel var elem = args.get_postBackElement();if (elem.id == '<%= btnSave.ClientID %>') // Only the button unloads the editor
{ // Check that there is an instance to removeif (tinyMCE.getInstanceById('<%= txtContent.ClientID %>') != null && 
tinyMCE.getInstanceById('<%= txtContent.ClientID %>') != "undefined")
{
tinyMCE.execCommand('mceFocus', false, '<%= txtContent.ClientID %>');    
tinyMCE.execCommand('mceRemoveControl',false,'<%= txtContent.ClientID %>');
}
}
}

3. At this point, the value in the TextArea is saved back into the form and posted back to the server. When the page is posted back, TinyMCE must be loaded back onto the textarea. To achieve this, we attach one more function, this time to the PageRequestManager’s endRequest event.

Sys.WebForms.PageRequestManager.
getInstance().add_endRequest(EndRequestHandler);function EndRequestHandler(sender, args)
{ // Ensure that the editor is not already loaded if (tinyMCE.getInstanceById('<%= txtContent.ClientID %>') == null || 
tinyMCE.getInstanceById('<%= txtContent.ClientID %>') == "undefined")
{
tinyMCE.execCommand('mceAddControl',false,'<%= txtContent.ClientID %>');
}
}

Both solutions work well. The former is simpler, but relies on the .NET ScriptManager to inject the code. The latter doesn’t rely on server-side code, but needs an identifiable trigger for the postback so that each event fires only against the desired TinyMCE area and not all the ones on the page. If you are using .NET, the latter needs to be registered as a StartupScript.

if (IsInUpdatePanel)
{
Page.ClientScript.RegisterStartupScript(this.GetType(), this.ClientID + "_ajax", GenerateMceAjaxFixScript(), true);
}

Two-way Binding To TinyMCE in an UpdatePanel

One further problem I discovered after making the changes noted above to TinyMCE’s alpha .NET wrapper was that while I could mark its text contents as [Bindable] in code, that two-way binding did not always work. Specifically when the TinyMCE control was in an UpdatePanel and changes were being made by a browser that wasn’t Internet Explorer (ironically). It seems that even if a call to TinyMCE.triggerSave is made as the request for a partial postback is initialized to update the textarea with the new value given by the user, that is still too late to have that new value saved to the FormValueCollection that is actually posted back to the server for binding to the server (as part of the page’s ViewState). The save is made in time by Internet Explorer but is not by Firefox or Chrome.

Fortunately, there is an easy partial solution to this problem for Firefox users. TinyMCE’s editor exposes a number of events including onChange which fires when a user has changed the text on the page. Adding a setup call in TinyMCE.init that handles onChange and also copies the new value to the textarea seems to do the trick.

tinyMCE.init({
relative_urls:false,
elements:'<% = elm.ClientID %>',
...,
setup : function(ed) { 
ed.onChange.add(function(ed, l) { var hidden = document.getElementById('<% = elm.ClientID %>');
hidden.value = l.content; }); }
});

So now we have two-way data binding working in IE and Firefox. Unfortunately it doesn’t work in Chrome, but hey - it’s a start. Download this code here.

TinyMCE, .NET, UpdatePanels and DataBinding

by

(In which the question of getting TinyMCE to DataBind successfully in UpdatePanels is partially solved, but Chrome refuses to play nicely.)

There seems to be a common cry of agony when you try to stick a TinyMCE-adorned textarea in an UpdatePanel. Partial page updates strip the iFrame that TinyMCE’s init script lays onto the textarea. The UpdatePanel also seems to prevent TinyMCE’s built-in trigger from updating the underlying textarea in non-IE browsers (oh the irony) which means that if you try and update values to a database, the FormCollection at the back of the page never gets the new value and the database doesn't get updated.

TinyMCE's download page has an alpha .NET wrapper for TinyMCE which I’m using here by the way. Chris de Vos has used some of the solution described below to implement an AJAX extender control which applies TinyMCE to a designated control. My own version of ‘TinyMCE.NET’ which doesn’t use gzip compression but which does embed the TinyMCE scripts into the DLL can be downloaded here as a .NET 3.5 solution. If you have any improvements on it, please let me know. Download it here.

More...

First Impressions of MVC

by

[In which ASP.NET MVC is initially judged by its beta 1 cover, reappraised after the first few weeks on development, and pigeon-holed for now post-RC1. Or rather, here are my thoughts on using ASP.NET MVC to build a web site.]

Just before Christmas, I was asked to build a web site using the nascent ASP.NET MVC framework, which was in beta at the time. Two months later, it’s now at release candidate level and the final build is expected to go gold in March, so there’ll be the inevitable tweaking here and there, but for now, here are my general thoughts and impressions of using MVC as the ASP templating system rather than Webforms.

“Oooh shiny” turns quickly to “developer inertia”

It’s noticeable that of the two new ASP.NET packages, with the dynamic data stuff being the other, MVC has had by far the most hype. The alt.net crowd is very vocal when it wants to be and as webforms does not always play nicely, they were very happy to see MVC appear. The large amount of good will made me keen to use it to see what all the fuss was about: it produces clean code, is lightweight, creates SEO-friendly URLs, and stackoverflow runs happily on it, so those are quite good reasons. My jackdaw tendencies to grab anything shiny came to the fore. Then I started using it and developer inertia took hold.

One of the side-effects of MVC is that it also forces you to relearn foundation level knowledge - HTTP verbs, proper semantic, standards-compliant HTML (ok, not that tricky, but go with it), javascript (JQuery, Moo, MS AJAX or whatever flavour of library you care to learn on top of that too), file streaming and the rest - which WebForms shields you from. MVC currently (RC1) does you no favours on that line. Want to enable uploading a file to the site? Better get out your best file streaming code. Want to implement a tab panel or a wizard? Start searching for javascript libraries. Find yourself trying to implement the SelectedIndexChanged event on a dropdownlist? Can’t do it - there’s no server-side event model with MVC. I’ve mused on developer inertia before at a time of upgrading systems but not really experienced it when trying something new. It’s an odd feeling to relearn how to code things that a simple webform control would have done for me in seconds. I also know I’m coding quite naïvely again while I find my mental feet with the new way of thinking about site construction that MVC forces you to have.

Documentation

And some of that is due the lack of documentation around. Or, rather, the abundance of out of date blog posts detailing ways of accomplishing tasks in some CTP that have since become obsolete in more recent builds. Of course, the wealth of accurate MVC knowledge will only get better with time. For my part, I got the most value from the Walther\Litwin pair programming vids on asp.net, Phil Haack’s talk from PDC ’08 and the early access PDF of ASP.NET MVC in Action available from Manning Publications. The latter in particular pulled together several facts about the basic conventions for MVC development that I hadn’t really seen anywhere else, so I’ll definitely buy that when it’s in print. Props to Jeffrey Palermo, Ben Scheirman and Jimmy Bogard for that. Secondary thanks to the people on stackoverflow for coming across the problems I was having before I did and presenting solutions. Again, some of the answers are pitted against previous builds but if the solutions there didn’t work, the SO folks answered very promptly any requests for an update. They would be my first port of call now if there is an MVC problem that I can’t solve myself.

Intellisense

A by-product of doc-light frameworks is a heavier reliance on intellisense. We all know that javascript and latterly JQuery intellisense has been introduced into Visual Studio which is good, but currently the MVC intellisense seems to have been gazumped first by the need to recompile your site each time you need it to work in a new view, and by anonymous initializers. A lot of parameters are simply of type object which, unless you spot a matching blog post or some code in a video, you probably don’t realise means using an anonymous object initialiser and strings.

Case in point, Html.ActionLink is one of the more useful HTML helper functions in MVC, referencing the routing table for the site and generating the correct URLs for controller\action\parameter combinations on your site. Want to switch from extensionless URLs to .mvc or .aspx or back again? ActionLink notes the change and renders URLs appropriately. (v.g.) However, it has ten overloads.

MVC Intellisense for HTMl.ActionLink

Based on the intellisense caption pictured above, how would you complete the call to ActionLink? As it turns out, it looks like this

<%= Html.ActionLink(
"Development", "development", "about", new{}, new { accesskey="5", Class="darkredcaps", 
tabindex="7", title="About our development work"})

Once you see it, you go ‘ah!’ (Apart from the fact that the HTML class attribute must begin with a capital C else C# throws an error but as there is no standards checking inside server markup that’s OK.) but here’s hoping that Microsoft improves intellisense somehow to make it more obvious.

On the bright side

If this all seems a bit negative, I must also emphasize that there are definitely many bright sides to MVC. Full control on what a site presents to a browser is an obvious highlight but you have to like the fact that LINQ (to SQL or to Entities) is such a quick and easy way to create the data access layer, or ‘Model’ in the lingo. (Using some variant of the ‘repository pattern’ in your code is also a time saver looking forward. Ta to Rob Conery for that one.) And if you don’t like LINQ, then it’s easy to switch it out later on or right away as you prefer.

Another great and welcome addition for newcomers is the sample site created in the sample MVC. It does a great job of presenting sample code and, more importantly, includes the account controller with the code needed to implement a site using the ASP.NET membership provider - truly a gift. No roles, profiles or use of other providers, but those are much more straightforward. Just run aspnet_regsql to create a membership database, add the [Authorize] attribute to action methods you want to protect from anonymous users and you are good to go.

And, of course, there’s the backing of everything else in the (ASP).NET framework. The familiar providers, validation, exception handling, configuration files and deployment perks are all there along with several other ‘features’ of MVC I didn’t try but plan to use soon - the ability to write tests against each controller\action pair and partial views, the MVC equivalent of user controls.

Oh, and there’s no view state to double the size of your page to worry about. Did I mention this before? No? OK. No view state.

To MVC or not to MVC?

So would I use MVC again if I had the choice for a commercial application? For the time being, no. Apart from it still being in beta for the time being, I think it’s unfair on the client to produce code which is naively written without some experience to back it up. Unless a job had a very exacting set of instructions \ workflow that meant testing was a pre-requisite, I don’t think I would use it again for another six months until I’ve got more comfortable with it all. The release of the MVC source code on codeplex has meant that debugging problems has produced far more accurate and immediate diagnoses than would otherwise occur (Steve Sanderson details how to hook the source code up to your own efforts here) but despite that, I want to practice with this more and get a grip on things like Html.DropDownList and its SelectList ‘model counterpart’ (my term), [HandleError], partial views, ModelState, the pros and cons of alternate controller classes such as those in MvcContrib and likewise of alternate view engines such as NVelocity and nHaml. And read a few more books of course.

Upgrading to MVC RC1

I was going to write this the day that the RC1 build of ASP.NET MVC was released, so it seemed only natural to postpone that and make a few notes. It would seem that actually upgrading to the RC1 DLL is very straightforward, as are losing the code-behind files for your view classes. However it does appear that several features have been switched on in RC1 that weren’t before. Case in point - input validation (for dangerous values in text such as <html or script tags>) seems to have been switched on. For those curious, the answer is to switch it off at the controller level and not wonder why the site is ignoring web.config. (full details here).

RC1 also includes the MVC dlls for inclusion in your source control tree as bin deployment is still enabled for MVC rather than needing to install it into the GAC as the MVC installer does. It also includes an IIS script to map the .mvc file extension to the aspnet_isapi handler for those IIS6 admins who would rather not use a wildcard script map to allow extension-less URLs to work. Note however that Steve Sanderson and Duncan Smart demonstrated how to add the wildcard script map to an MVC site as a while and then remove it from those directories containing only static content (images, scripts etc) which was the main source of contention in this regard.

Going forward

As you can tell, my opinion of ASP.NET MVC thus far is mixed. I can appreciate its worth but am not so advanced an ASP.NET programmer that I’ve really hit a wall with webforms to hate it. Nor am I previously familiar with the MVC pattern enough to want instantly to use it to the exclusion of all else. I do know that it isn’t going away though and while webforms will continue to be my first choice of templating engine for ASP.NET, it’s only sensible to grok MVC as well. And Dynamic Data too - although that’s for another day.

First Impressions of MVC

by

[In which ASP.NET MVC is initially judged by its beta 1 cover, reappraised after the first few weeks on development, and pigeon-holed for now post-RC1. Or rather, here are my thoughts on using ASP.NET MVC to build a web site.]

Just before Christmas, I was asked to build a web site using the nascent ASP.NET MVC framework, which was in beta at the time. Two months later, it’s now at release candidate level and the final build is expected to go gold in March, so there’ll be the inevitable tweaking here and there, but for now, here are my general thoughts and impressions of using MVC as the ASP templating system rather than Webforms.

“Oooh shiny” turns quickly to “developer inertia”

It’s noticeable that of the two new ASP.NET packages, with the dynamic data stuff being the other, MVC has had by far the most hype. The alt.net crowd is very vocal when it wants to be and as webforms does not always play nicely, they were very happy to see MVC appear. The large amount of good will made me keen to use it to see what all the fuss was about: it produces clean code, is lightweight, creates SEO-friendly URLs, and stackoverflow runs happily on it, so those are quite good reasons. My jackdaw tendencies to grab anything shiny came to the fore. Then I started using it and developer inertia took hold.

One of the side-effects of MVC is that it also forces you to relearn foundation level knowledge - HTTP verbs, proper semantic, standards-compliant HTML (ok, not that tricky, but go with it), javascript (JQuery, Moo, MS AJAX or whatever flavour of library you care to learn on top of that too), file streaming and the rest - which WebForms shields you from. MVC currently (RC1) does you no favours on that line. Want to enable uploading a file to the site? Better get out your best file streaming code. Want to implement a tab panel or a wizard? Start searching for javascript libraries. Find yourself trying to implement the SelectedIndexChanged event on a dropdownlist? Can’t do it - there’s no server-side event model with MVC. I’ve mused on developer inertia before at a time of upgrading systems but not really experienced it when trying something new. It’s an odd feeling to relearn how to code things that a simple webform control would have done for me in seconds. I also know I’m coding quite naïvely again while I find my mental feet with the new way of thinking about site construction that MVC forces you to have.

Documentation

And some of that is due the lack of documentation around. Or, rather, the abundance of out of date blog posts detailing ways of accomplishing tasks in some CTP that have since become obsolete in more recent builds. Of course, the wealth of accurate MVC knowledge will only get better with time. For my part, I got the most value from the Walther\Litwin pair programming vids on asp.net, Phil Haack’s talk from PDC ’08 and the early access PDF of ASP.NET MVC in Action available from Manning Publications. The latter in particular pulled together several facts about the basic conventions for MVC development that I hadn’t really seen anywhere else, so I’ll definitely buy that when it’s in print. Props to Jeffrey Palermo, Ben Scheirman and Jimmy Bogard for that. Secondary thanks to the people on stackoverflow for coming across the problems I was having before I did and presenting solutions. Again, some of the answers are pitted against previous builds but if the solutions there didn’t work, the SO folks answered very promptly any requests for an update. They would be my first port of call now if there is an MVC problem that I can’t solve myself.

Intellisense

A by-product of doc-light frameworks is a heavier reliance on intellisense. We all know that javascript and latterly JQuery intellisense has been introduced into Visual Studio which is good, but currently the MVC intellisense seems to have been gazumped first by the need to recompile your site each time you need it to work in a new view, and by anonymous initializers. A lot of parameters are simply of type object which, unless you spot a matching blog post or some code in a video, you probably don’t realise means using an anonymous object initialiser and strings.

Case in point, Html.ActionLink is one of the more useful HTML helper functions in MVC, referencing the routing table for the site and generating the correct URLs for controller\action\parameter combinations on your site. Want to switch from extensionless URLs to .mvc or .aspx or back again? ActionLink notes the change and renders URLs appropriately. (v.g.) However, it has ten overloads.

MVC Intellisense for HTMl.ActionLink

Based on the intellisense caption pictured above, how would you complete the call to ActionLink? As it turns out, it looks like this

<%= Html.ActionLink(
"Development", "development", "about", new{}, new { accesskey="5", Class="darkredcaps", 
tabindex="7", title="About our development work"})

Once you see it, you go ‘ah!’ (Apart from the fact that the HTML class attribute must begin with a capital C else C# throws an error but as there is no standards checking inside server markup that’s OK.) but here’s hoping that Microsoft improves intellisense somehow to make it more obvious.

On the bright side

If this all seems a bit negative, I must also emphasize that there are definitely many bright sides to MVC. Full control on what a site presents to a browser is an obvious highlight but you have to like the fact that LINQ (to SQL or to Entities) is such a quick and easy way to create the data access layer, or ‘Model’ in the lingo. (Using some variant of the ‘repository pattern’ in your code is also a time saver looking forward. Ta to Rob Conery for that one.) And if you don’t like LINQ, then it’s easy to switch it out later on or right away as you prefer.

Another great and welcome addition for newcomers is the sample site created in the sample MVC. It does a great job of presenting sample code and, more importantly, includes the account controller with the code needed to implement a site using the ASP.NET membership provider - truly a gift. No roles, profiles or use of other providers, but those are much more straightforward. Just run aspnet_regsql to create a membership database, add the [Authorize] attribute to action methods you want to protect from anonymous users and you are good to go.

And, of course, there’s the backing of everything else in the (ASP).NET framework. The familiar providers, validation, exception handling, configuration files and deployment perks are all there along with several other ‘features’ of MVC I didn’t try but plan to use soon - the ability to write tests against each controller\action pair and partial views, the MVC equivalent of user controls.

Oh, and there’s no view state to double the size of your page to worry about. Did I mention this before? No? OK. No view state.

To MVC or not to MVC?

So would I use MVC again if I had the choice for a commercial application? For the time being, no. Apart from it still being in beta for the time being, I think it’s unfair on the client to produce code which is naively written without some experience to back it up. Unless a job had a very exacting set of instructions \ workflow that meant testing was a pre-requisite, I don’t think I would use it again for another six months until I’ve got more comfortable with it all. The release of the MVC source code on codeplex has meant that debugging problems has produced far more accurate and immediate diagnoses than would otherwise occur (Steve Sanderson details how to hook the source code up to your own efforts here) but despite that, I want to practice with this more and get a grip on things like Html.DropDownList and its SelectList ‘model counterpart’ (my term), [HandleError], partial views, ModelState, the pros and cons of alternate controller classes such as those in MvcContrib and likewise of alternate view engines such as NVelocity and nHaml. And read a few more books of course.

Upgrading to MVC RC1

I was going to write this the day that the RC1 build of ASP.NET MVC was released, so it seemed only natural to postpone that and make a few notes. It would seem that actually upgrading to the RC1 DLL is very straightforward, as are losing the code-behind files for your view classes. However it does appear that several features have been switched on in RC1 that weren’t before. Case in point - input validation (for dangerous values in text such as <html or script tags>) seems to have been switched on. For those curious, the answer is to switch it off at the controller level and not wonder why the site is ignoring web.config. (full details here).

RC1 also includes the MVC dlls for inclusion in your source control tree as bin deployment is still enabled for MVC rather than needing to install it into the GAC as the MVC installer does. It also includes an IIS script to map the .mvc file extension to the aspnet_isapi handler for those IIS6 admins who would rather not use a wildcard script map to allow extension-less URLs to work. Note however that Steve Sanderson and Duncan Smart demonstrated how to add the wildcard script map to an MVC site as a while and then remove it from those directories containing only static content (images, scripts etc) which was the main source of contention in this regard.

Going forward

As you can tell, my opinion of ASP.NET MVC thus far is mixed. I can appreciate its worth but am not so advanced an ASP.NET programmer that I’ve really hit a wall with webforms to hate it. Nor am I previously familiar with the MVC pattern enough to want instantly to use it to the exclusion of all else. I do know that it isn’t going away though and while webforms will continue to be my first choice of templating engine for ASP.NET, it’s only sensible to grok MVC as well. And Dynamic Data too - although that’s for another day.

Another film finished

by

From time to time, I am invited to help out with some film-making by my friends Dan and James. Indeed, early last year I spent a couple of days with them manning the camera for their current project Iniquity. Dan let me know last night that he and James have just finished editing Iniquity and have submitted it for inclusion at the Edinburgh Film Festival in June this year. So I’m crossing my fingers for them and hoping that one day soon I’ll get my own legitimate IMDB entry.

From the film’s website:

For Detective Jack Thompson, the system is failing around him. His decision - play by the book, or take the law into his own hands.

Plagued by the continuing media profile of a past case, Jack is trying to move on - make a difference. Then he meets Dennison Tophet - a man seemingly without a past, without a motive - but a man most definitely with an agenda...

You can also download a number of behind the scenes clips and the trailers from the film’s podcast page. Here's the trailer.