I want to be able to pass information from my view model to my controller via JSON in hidden textboxes. I'm working with polygons in the Google maps API. As the user edits the polygon, I am storing the vertices in a hidden input via javascript.
var p = mypolygon.getPath().getArray();
var s = '';
for (var i = 0; i < p.length; i++)
s += ((i > 0) ? ', ' : '') + '{ lat: ' + p[i].lat() + ', lng: ' + p[i].lng() + ' }';
$('#@Html.IdFor(m => m.GeofencePoints)').val('[' + s + ']');
It results in this:
<input id="GeofencePoints" name="GeofencePoints" type="hidden" value="[{ lat: 38.221276965853264, lng: -97.6892964859955 }, { lat: 38.21294239796929, lng: -97.68770861825868 }, { lat: 38.2122680083775, lng: -97.67782997884831 }, { lat: 38.220434074436966, lng: -97.67787289419255 }]">
I would like to have the following view model bound to the view:
public class MyMapViewModel
{
public GoogleMapPoint[] GeofencePoints {get;set;}
public string OtherProperty {get;set;}
}
public class GoogleMapPoint
{
public double lat {get;set;}
public double lng {get;set;}
}
This is a little different from examples I've seen since I only want one of my properties posted as Json. Can anybody point me in the right direction? I know I could just pass it along as a string and serialize/deserialize on my own. However, I was hoping for an elegant customer model binder solution.
UPDATE
I figured out a generic solution based on this post I found: http://mkramar.blogspot.com/2011/05/mvc-complex-model-postback-bind-field.html
public class JsonBindableAttribute : Attribute
{
}
public class MyModelBinder : DefaultModelBinder
{
protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
{
if (propertyDescriptor.Attributes.OfType<Attribute>().Any(x => (x is JsonBindableAttribute)))
{
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).AttemptedValue;
return JsonConvert.DeserializeObject(value, propertyDescriptor.PropertyType);
}
return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
}
}
In my model:
[JsonBindable]
[UIHint("GoogleMapPoints")]
public GoogleMapPoint[] GeofencePoints { get; set; }
And then in global.asax Application_Start()
ModelBinders.Binders.DefaultBinder = new MyModelBinder();
Unfortunately this only gets me so far. This binds form values to my class just fine. However, it doesn't solve rendering a property as Json. As you can see, I created a custom editor GoogleMapPoints.cshtml which I basically have to recreate for every class I'll have as jsonbindable.
@model IEnumerable<GoogleMapPoint>
@Html.Hidden("", Newtonsoft.Json.JsonConvert.SerializeObject(Model))
Does anybody know of a way to have a generic custom editor that would pay attention to attributes rather than types so that EditorFor for properties colored with my JsonBindable attribute always render as Json in a hidden field regardless of type/class?