Noah Blumenthal's Blog

July 27, 2009

jQuery $.extend() method with plugin called multiple times (note to self: RTFM!)

Filed under: Uncategorized — noahblu @ 4:22 pm

 

jQuery’s $.extend() method is used to merge two (or more) objects.  It’s very useful in plugin development since it can be used to merge user defined options with default options for a plugin.  I ran into an issue today trying to debug a plugin I wrote (jquery inline row editor) whereby settings were getting all screwed up if it was used multiple times on a page (ie a page with multiple editable tables).  I’m ashamed to say it, but it took me a while of debugging before realized what the issue was.  Note to self: RTFM!!!

Take the following snippet:

   1: $.fn.inplacerowedit = function(options) {

   2:     var ops = $.extend($.fn.inplacerowedit.defaults, options);

   3:     .....

   4: }

Now what I didn’t take into account is that the $.extend() method doesn’t just spit out a merged object based on all the parameters, it merges all objects sent in as parameters into the first parameter.  So in this example above, ops == $.fn.inplacerowedit.defaults which itself is a combination of what it started out as and the options parameter.  Well that now makes sense why things got screwed up when this was called multiple times, huh?

So the solution was to set the first parameter of the $.extend() method to a blank object {} and have jQuery append EVERYTHING to that and set THAT to ops like so:

   1: $.fn.inplacerowedit = function(options) {

   2:     var ops = $.extend({}, $.fn.inplacerowedit.defaults, options);

   3:     .....

   4: }

OR I suppose you could just declare ops and then use that as the first parameter.

July 10, 2009

jQuery plugin to edit table row (inline)

Filed under: jQuery — noahblu @ 6:00 pm

I just uploaded a jQuery plugin to turn a regular (non-souped-up) table’s rows into inline editable.  The url is http://code.google.com/p/jquery-inline-editor/

There are some instructions there too.  Feel free to modify.

Pretty simple but might save you some time if you’re going in this direction.

Retrieve OR Instantiate ModelBinder

Filed under: Uncategorized — noahblu @ 2:25 am

Sometimes you want your model binder to retrieve an object if it exists or instantiate it if it doesn’t.  For instance I have a create page and an edit page for my models so on the create page I want the model to be instantiated but I also have an edit page that posts back the ID of the model and I’d love the entity to be retrieved from the DB for further edits.  SO…..

I created a ModelBinder that actually takes two different model binders and tries to bind with each.  If it works the first time, great, otherwise try the backup.  In my case that’s Retrieval with a backup of Instantiate.  This could be used for many different purposes though, so don’t let the class name throw you off:

   1: public class RetrieveOrInstantiateModelBinder : IModelBinder

   2: {

   3:     private IModelBinder _retrievalBinder;

   4:     private IModelBinder _instantiationBinder;

   5:     public RetrieveOrInstantiateModelBinder(IModelBinder retrievalBinder, IModelBinder instantiationBinder)

   6:     {

   7:         _retrievalBinder = retrievalBinder;

   8:         _instantiationBinder = instantiationBinder;

   9:     }

  10:     #region IModelBinder Members

  11:  

  12:     public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)

  13:     {

  14:         object obj = _retrievalBinder.BindModel(controllerContext, bindingContext);

  15:         if (obj == null)

  16:             obj = _instantiationBinder.BindModel(controllerContext, bindingContext);

  17:  

  18:         return obj;

  19:     }

  20:  

  21:     #endregion

  22: }

Model Binder that retrieves from DB

Filed under: Uncategorized — noahblu @ 2:20 am

Many times I need a model binder that will retrieve my model from a repository so that I can perform updates.  Here’s what I came up with.

   1: public class EntityRetrievalBinder<T, TRepository> : IModelBinder

   2:     where TRepository : IRepository<T>

   3: {

   4:     #region IModelBinder Members

   5:  

   6:     public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)

   7:     {

   8:         var name = bindingContext.ModelName + ".ID";

   9:         ValueProviderResult idResult;

  10:         try

  11:         {

  12:             if (bindingContext.ValueProvider.TryGetValue(name, out idResult))

  13:             {

  14:                 Guid id = new Guid(idResult.AttemptedValue);

  15:                 var repository = StructureMap.ObjectFactory.GetInstance<TRepository>();

  16:                 T obj = repository.FindById(id);

  17:                 if (obj == null)

  18:                     throw new ArgumentException("Object not found");

  19:                 return obj;

  20:             }

  21:         }

  22:         catch (Exception e)

  23:         {

  24:         }

  25:         return null;

  26:     }

I changed a couple things for this post, but basically the logic is simple.  What this does is just retrieve the repository from StructureMap and then try to run the Find() method which takes a Guid ID as its only parameter.  Either this will return a null (if no ID was posted) or an object of type T OR it might throw an exception if the user posted an ID but that ID was not found.  I’ll show you in the next post how I tie everything together.

Changed site template

Filed under: Uncategorized — noahblu @ 2:15 am

I’m toying with a Code Snippet plugin for Live Writer that allows me to insert code snippets that are actually legible (check the previous post to see).  However, this wasn’t working well with my last template so I changed templates.

ASP.NET Custom Model Binder Template

Filed under: Uncategorized — noahblu @ 2:09 am

I have found that I build a lot of the same logic into my Model Binders.  I typically use Reflection to either instantiate a new object or call a method on a Factory that will do that for me.  So I’ve put together a ModelBinder using the Template pattern to help accomplish this more easily.

First, the Template:

   1: public abstract class ReflectionModelBinder : DefaultModelBinder

   2:     {

   3:         private IModelBinderValidator _validator = null;

   4:         public ReflectionModelBinder() { }

   5:         public ReflectionModelBinder(IModelBinderValidator validator)

   6:         {

   7:             _validator = validator;

   8:         }

   9:         protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)

  10:         {

  11:             ParameterInfo[] parameters = GetParameters();

  12:             List<object> paramValues = new List<object>();

  13:             IModelBinder binder;

  14:             string oldModelName = bindingContext.ModelName;

  15:             foreach (ParameterInfo param in parameters)

  16:             {

  17:                 string name = CreateSubPropertyName(oldModelName, param.Name);

  18:                 bindingContext.ModelType = param.ParameterType;

  19:                 bindingContext.ModelName = name;

  20:                 if (!System.Web.Mvc.ModelBinders.Binders.TryGetValue(param.ParameterType, out binder))

  21:                     binder = System.Web.Mvc.ModelBinders.Binders.DefaultBinder;

  22:                 object model = binder.BindModel(controllerContext, bindingContext);

  23:                 paramValues.Add(model);

  24:             }

  25:             bindingContext.ModelType = modelType;

  26:             bindingContext.ModelName = oldModelName;

  27:             object obj = CreateModel(paramValues.ToArray());

  28:  

  29:             if (_validator != null)

  30:                 _validator.Validate(bindingContext, obj);

  31:  

  32:             return obj;

  33:         }

  34:         protected abstract ParameterInfo[] GetParameters();

  35:         protected abstract object CreateModel(object[] parameters);

  36:     }

(don’t mind the IModelBinderValidator, that’ll have to be another post, but you can probably figure it out)

So now I have this template.  Here’s an example of how I can bind a model by using a Factory (I have a Lease object with a LeaseFactory  that creates the lease and all the associated charges like back rent etc.):

   1: public class LeaseReflectionModelBinder : ReflectionModelBinder

   2: {

   3:     public LeaseReflectionModelBinder(IModelBinderValidator validator) : base(validator)

   4:     {

   5:         _createLeaseMethod = typeof(LeaseFactory).GetMethod("CreateLease", BindingFlags.Static | BindingFlags.Public);

   6:     }

   7:     private MethodInfo _createLeaseMethod;

   8:  

   9:     protected override ParameterInfo[] GetParameters()

  10:     {

  11:         return _createLeaseMethod.GetParameters();

  12:     }

  13:  

  14:     protected override object CreateModel(object[] parameters)

  15:     {

  16:         return _createLeaseMethod.Invoke(null, parameters);

  17:     }

  18: }

Easy, huh?

July 7, 2009

Connections to SQL Server files (*.mdf) require SQL Server Express 2005 to function properly

Filed under: Uncategorized — noahblu @ 4:34 pm

Setup a new machine with VS2008 & SQL Server Express 2008 and was surprised when I got the following error when trying to run against an mdf file:

Connections to SQL Server files (*.mdf) require SQL Server Express 2005 to function properly

Well I have SQL Server Express 2008 installed!  And my other machines don’t have this problem.  Next step was to try installing SP1 — doh, that’ll fix it, right?  WRONG!  Same error.

After 30 min of googling, I stumbled upon this MS article http://support.microsoft.com/kb/957944 .  Cause?

This problem occurs because Visual Studio 2008 SP1 incorrectly detects some registry keys for a 64-bit installation of SQL Server Express 2008.

So the issue is that I’m running a 64bit SQL Server instance.

There’s a hotfix too.  But there’s no link (it took me 5 min of searching the page to finally figure this out and RTFM) — you have to call MS and have them send it to you.  That’s not terrible and it only took my a few min, but it was kind of a pain.

In case you have this issue, you can save yourself some time by dialing the direct number to the department that can help you: 1-800-936-4900.

Blog at WordPress.com.