Mr Jones
Mr Jones

Reputation: 1198

How to pass an entire ViewModel back to the controller

I have a ViewModel that contains two objects:

public class LookUpViewModel
{
    public Searchable Searchable { get; set; }
    public AddToSearchable AddToSearchable { get; set; }
}

The two contained models look something like this:

public class Searchable
{
    [Key]
    public int SearchableId { get; set; }
    public virtual ICollection<AddToSearchable> AddedData { get; set; }
}

public class AddToSearchable
{
    [Key]
    public int AddToSearchableId { get; set;}
    [Required]
    public int SearchableId { get; set; }
    [Required]
    public String Data { get; set; }
    [Required]
    public virtual Searchable Searchable { get; set; }
}

I have a view that uses my LookUpViewModel and receives input to search for a SearchableId. If the Searchable object is found, a LookUpViewModel object is created and passed to the View. The view then displays editor fields for AddToSearchable.Data. Once submitted, I want the LookUpViewModel to be passed to an action method to handle all the back-end code. The only problem is, the LookUpViewModel passed to my action method contains a null reference to Searchable and a valid reference to AddToSearchable.. i.e. I'm missing half of my data.

Here's an example of what my view looks like:

@model HearingAidTrackingSystem.ViewModels.LookUpViewModel

@using (Html.BeginForm("LookUp", "Controller", "idStr", FormMethod.Post))
{
    <input type="text" name="idStr" id="idStr"/>
    <input type="submit" value="Search" />
}

@if (Model.Searchable != null && Model.AddToSearchable != null)
{
    using (Html.BeginForm("AddMyStuff", "Controller"))
    {
        Html.HiddenFor(model => model.Searchable.SearchableId);
        Html.HiddenFor(model => model.Searchable.AddedData);
        Html.HiddenFor(model => model.AddToSearchable.AddToSearchableId);
        Html.HiddenFor(model => model.AddToSearchable.SearchableId);
        Html.HiddenFor(model => model.AddToSearchable.Searchable);

        <div class="editor-field">
            @Html.EditorFor(model => model.AddToSearchable.Data)
            @Html.ValidationMessageFor(model => model.AddToSearchable.Data);
        </div>                                    

        <input type="submit" value="Submit" />
    }
}

and here are my action methods:

public ActionResult LookUp(LookUpViewModel vm)
{
    return View(vm);
}

[HttpPost]
public ActionResult LookUp(string idStr)
{
    int id = /*code to parse string to int goes here*/;

    Searchable searchable = dal.GetById(id);
    LookUpViewModel vm = new LookUpViewModel { Searchable = searchable, 
                                               AddToSearchable = new AddToSearchable() };
    //When breakpoint is set, vm contains valid references
    return View(vm);
}

[HttpPost]
public ActionResult AddMyStuff(LookUpViewModel vm)
{
    //**Problem lies here**

    //Do backend stuff
}       

Sorry for the lengthy post. I tried my best to keep it simple. Any suggestions you may have.. fire away.

Upvotes: 6

Views: 12423

Answers (1)

Kirill Bestemyanov
Kirill Bestemyanov

Reputation: 11964

Two methods to fix it:

  1. You can add to do HiddenFor() for all properties of Model.Searchable.

  2. You can use serialization to transfer your Model.Searchable into text presentation and repair it from serialized form in controller.

Update: The problem is: You need to use @Html.HiddenFor(), not Html.HiddenFor();.

Upvotes: 7

Related Questions