1

I have a complex model that I am passing to my view and it works well for display but as soon as I pass it back it is all null. My model is as follows

public class LeavingShopSetupViewModel
{
    public LeavingShopSetupViewModel()
    {

    }
    ...Additional constructor here....

    public BasicSetupAccessor BasicSetupAccessor { get; set; }

    public SetupAcessor SetupAcessor { get; set; }

    public FrontSuspensionAccessor FrontSuspensionAcessor { get; set; }

    public RearSuspensionAccessor RearSuspensionAccessor { get; set; }

    public BrakeAccessor BrakeAccessor { get; set; }

    public void SaveSetup()
    {
        ...Save code.....
    }
}

Each of the objects is comprised of simple objects such as doubles, strings, ints....

My view is as follows w/ javascript code

@using RIS.Models.EventModels
@model LeavingShopSetupViewModel
<script type="text/javascript">
    $(function() {
        $("#submit_btn").click(function() {
            var form = $('#setupForm');
            $.ajax({
                type: 'post',
                url: "@Url.Action("SaveSetup","Events")",
                data: form.serialize()
            });
            return false; // <-- cancel the default event
        });

    });
</script>
<form id="setupForm">
    <fieldset>
        <legend>Leaving Shop Setup</legend>
        <div class="row-fluid">
            <div class="span4">
                ...Boilerplate code.....
                @BuildSheetHelpers.DoubleTextBox("FARB Link Length", Model.BasicSetupAccessor.SwayBarLinkLengthLF, Model.BasicSetupAccessor.SwayBarLinkLengthLR)
                @BuildSheetHelpers.DoubleTextBox("Bump Stop Gap", Model.BasicSetupAccessor.BumpStopGapL, Model.BasicSetupAccessor.BumpStopGapR)
                @BuildSheetHelpers.DoubleTextBox("Total BS Height", Model.BasicSetupAccessor.BumpRubberHeightTotalL, Model.BasicSetupAccessor.BumpRubberHeightTotalR)
            ...plenty more code that is all similar to this.....
            </div>
        </div>
    </fieldset>
    <a class="btn btn-primary" id="submit_btn">Save Setup</a>

    @Html.HiddenFor(model => model.SetupAcessor)
    @Html.HiddenFor(model => model.BasicSetupAccessor)
    @Html.HiddenFor(model => model.BrakeAccessor)
    @Html.HiddenFor(model => model.FrontSuspensionAcessor)
    @Html.HiddenFor(model => model.RearSuspensionAccessor)
</form>

And my helper function is as follows

@helper DoubleTextBox(string displayTag, double? left, double? right)
{
    <div class="row-fluid form-inline">
        <input type="text" class="span4 data" value="@left"/>
        <label  class="span4 pagination-centered">@displayTag</label>
        <input type="text" class="span4 data" value="@right"/>
    </div>
}

The SaveSetup action is just

public ActionResult SaveSetup(LeavingShopSetupViewModel setup)
    {
        setup.SaveSetup();
        return null;
    }

When I put a break point in the above action the setup variable contains only nulls. How can I pass the full model back?

PlTaylor
  • 7,345
  • 11
  • 52
  • 94
  • You're not handling the ajax complete event. – jrummell Apr 03 '12 at 18:51
  • I'm more worried about the fact that when I put a breakpoint in my SaveSetup action the model it returns contains only nulls. – PlTaylor Apr 03 '12 at 18:53
  • If you show your action method, we might be able to help. – jrummell Apr 03 '12 at 18:54
  • As soon as you asked the first question I realized I hadn't included it. It's there at the end now with a better formatted question. – PlTaylor Apr 03 '12 at 18:55
  • What data is being posted in your ajax request? You can see it in Chrome dev tools or Firebug in FF. – jrummell Apr 03 '12 at 18:57
  • Fiddler is reporting "SetupAcessor=RIS.DataLayer.Events.SetupAcessor&BasicSetupAccessor=RIS.DataLayer.Setups.BasicSetupAccessor&BrakeAccessor=RIS.DataLayer.Setups.BrakeAccessor&FrontSuspensionAcessor=RIS.DataLayer.Setups.FrontSuspensionAccessor&RearSuspensionAccessor=RIS.DataLayer.Setups.RearSuspensionAccessor" Where is that in Chrome dev tools? Different question but I'm still learning my way around Chrome Dev tools. – PlTaylor Apr 03 '12 at 19:00
  • Those look like type names, you should have separate hidden fields for each simple property. Consider using an EditorTemplate. – jrummell Apr 03 '12 at 19:06
  • Chrome Menu -> Tools -> Developer tools, Network tab. – jrummell Apr 03 '12 at 19:06
  • Is there anyway to do something similar with @helper functions? I am passing 2 properties into the helper function and it lays it out the way I want it to. There is no great way for me to break down the objects into pair or reduce the amount of objects to non-complex objects. – PlTaylor Apr 03 '12 at 19:22

2 Answers2

0

Based on your comments, I would recommend replacing your helpers with EditorTemplates. Editor templates are partial views that are used with the @Html.EditorFor() helper.

This question recommends Brad Wilson's blog post tutorial. It doesn't use Razor, but everything else is the same for MVC3.

So you would define an EditorTemplate for each type you need to display, and then replace all of the hiddens with editors:

@Html.EditorFor(model => model.SetupAcessor)
@Html.EditorFor(model => model.BasicSetupAccessor)
@Html.EditorFor(model => model.BrakeAccessor)
@Html.EditorFor(model => model.FrontSuspensionAcessor)
@Html.EditorFor(model => model.RearSuspensionAccessor)

Additionally, that's a lot of hidden fields on a form. You may want to consider persisting these values server side instead with SQL/Cache/Session/etc.

Community
  • 1
  • 1
jrummell
  • 42,637
  • 17
  • 112
  • 171
  • unfortunately the input boxes are intermingled on the form from each object so I don't think the EditorFor will work. – PlTaylor Apr 03 '12 at 19:39
0

I figured this out with some modification to my helper function to include a name and id so the jquery.serialize() will serialize the properties correctly. I am having to also write a viewmodel that isn't complex and some generic methods for the helper function make it all work nicely. That code is below for future reference. The info for the generic helper functions was found here on stackoverflow

@functions
{
    public static HelperResult DoubleTextBox<T>(T targeObject, string label, Expression<Func<T, double?>> leftTarget, Expression<Func<T, double?>> rightTarget) 
    { 
        var leftExpr = (MemberExpression)leftTarget.Body; 
        var leftProp = (PropertyInfo)leftExpr.Member; 
        var leftValue = leftProp.GetValue(targeObject, null);
        var rightExpr = (MemberExpression)rightTarget.Body; 
        var rightProp = (PropertyInfo)rightExpr.Member; 
        var rightValue = rightProp.GetValue(targeObject, null);

        return DoubleTextBox(label, leftValue, leftProp.Name, rightValue, rightProp.Name);
    } 
}
@helper DoubleTextBox(string displayTag, object leftValue, string leftName, object rightValue, string rightName)
{    
    <div class="row-fluid form-inline">
        <input type="text" class="span4 data" value="@leftValue" id="@leftName" name="@leftName"/>
        <label  class="span4 pagination-centered">@displayTag</label>
        <input type="text" class="span4 data" value="@rightValue" id="@rightName" name="@rightName"/>
    </div>
}
Community
  • 1
  • 1
PlTaylor
  • 7,345
  • 11
  • 52
  • 94