1

I have a problem that I cannot seem to resolve

I have the following models setup:

public class LogModel
{
    public LogModel()
    {
        this.Log = new List<LogItemModel>();
    }
    public List<LogItemModel> Log { get; set; }
    public TeamModel Winner { get; set; }
    public TeamModel Runnerup { get; set; }
}
public class LogItemModel : BaseModel
{
    public int TeamID { get; set; }
    public string TeamName { get; set; }
    public int TeamPosition { get; set; }
}

Displaying it in my view as follows:

@using (Ajax.BeginForm("SubmitLog", new AjaxOptions { OnSuccess = "onSuccess" }))
{
   @model List<MyPredictor.Models.Log.LogItemModel>
   @for (int i = 0; i < Model.Count; i++)
   {

       @Html.HiddenFor(m => m[i].TeamID, new { @class = "selected_team_id", dataposition = i })
       @Html.HiddenFor(m => m[i].TeamName, new { @class = "selected_team_name" })
       @Html.HiddenFor(m => m[i].TeamPosition, new { @class = "selected_team_position", dataposition = i, @value = i })
   }
}

I am also rendereing the rest of the model, but that is not important, as it is working correctly. For testing, this is my method to acceept the post:

[HttpPost]
public JsonResult SubmitLog(LogModel log)
{
    return Json(log);
}

Then once I press the submit button, the response from the method is:

{"Log":[],"Winner":{"ID":1,"Name":"Blues","Image":null},"Runnerup":{"ID":14,"Name":"Stormers","Image":null}}

The log list is always empty and I am not sure why. Because if I look in the POST tab on firebug, I can see all the values being posted:

%5B0%5D.TeamID=14&%5B0%5D.TeamName=Stormers&%5B0%5D.TeamPosition=1&%5B1%5D.TeamID=13&%5B1%5D.TeamName=Sharks&%5B1%5D.TeamPosition=2&%5B2%5D.TeamID=6&%5B2%5D.TeamName=Crusaders&%5B2%5D.TeamPosition=3&%5B3%5D.TeamID=-1&%5B3%5D.TeamName=&%5B3%5D.TeamPosition=4&%5B4%5D.TeamID=-1&%5B4%5D.TeamName=&%5B4%5D.TeamPosition=5&%5B5%5D.TeamID=-1&%5B5%5D.TeamName=&%5B5%5D.TeamPosition=6&%5B6%5D.TeamID=-1&%5B6%5D.TeamName=&%5B6%5D.TeamPosition=7&%5B7%5D.TeamID=-1&%5B7%5D.TeamName=&%5B7%5D.TeamPosition=8&%5B8%5D.TeamID=-1&%5B8%5D.TeamName=&%5B8%5D.TeamPosition=9&%5B9%5D.TeamID=-1&%5B9%5D.TeamName=&%5B9%5D.TeamPosition=10&%5B10%5D.TeamID=-1&%5B10%5D.TeamName=&%5B10%5D.TeamPosition=11&%5B11%5D.TeamID=-1&%5B11%5D.TeamName=&%5B11%5D.TeamPosition=12&%5B12%5D.TeamID=-1&%5B12%5D.TeamName=&%5B12%5D.TeamPosition=13&%5B13%5D.TeamID=-1&%5B13%5D.TeamName=&%5B13%5D.TeamPosition=14&%5B14%5D.TeamID=-1&%5B14%5D.TeamName=&%5B14%5D.TeamPosition=15&Winner.ID=1&Winner.Name=Blues&Winner.Image=&Runnerup.ID=14&Runnerup.Name=Stormers&Runnerup.Image=&X-Requested-With=XMLHttpRequest

EDIT

I found a strange solution that works, but I am not sure it is ideal:

[HttpPost]
public JsonResult SubmitLog(List<MyPredictor.Models.Log.LogItemModel> log, LogModel model)
{
    model.Log = log;
    return Json(model);
}
NightStalker
  • 113
  • 3
  • 11

3 Answers3

0

Try

[HttpPost]
public JsonResult SubmitLog(List<MyPredictor.Models.Log.LogItemModel> log)
{
    return Json(log);
}

Assuming your array is setup correctly in your form, the binding model has to be a POCO (Plain Old C# Object) for the default binder to work.

beautifulcoder
  • 10,832
  • 3
  • 19
  • 29
  • What about the `Winner` and `Runnerup` properties? The model already is a POCO. – David Dec 26 '13 at 13:05
  • Thanks for the reply. If I do that, it works, but I also need the rest of the model: – NightStalker Dec 26 '13 at 13:07
  • I would recommend using a custom binder solution. This way, it keeps the binding logic encapsulated somewhere without convoluting your controller code. – beautifulcoder Dec 26 '13 at 19:12
  • @David, POCOs are simple flat objects. The original `Log` model is a complex object. – beautifulcoder Dec 26 '13 at 19:14
  • @beautifulcoder: POCOs are objects that aren't encumbered with framework decorations or other such complexities. Having a `List<>` as a property is still a plain simple object using only core language components. There's nothing complex about it. – David Dec 26 '13 at 19:17
  • @David, interesting discussion. Is `List<>` part of the .NET framework? My understanding is POCOs are not made of objects tightly coupled to a specific framework. – beautifulcoder Dec 27 '13 at 20:49
  • @beautifulcoder: Yes, `List<>` (and lots of other generic collections) have been part of the .NET Framework since 2.0. POCOs are objects which aren't coupled to a framework, but I don't think *the .NET Framework* is included in that category, since C# itself uses the .NET Framework. In the same sense, POCOs can also include properties of type `System.String` or `System.Object` which are also classes in the .NET Framework. – David Dec 27 '13 at 20:54
  • @David, everything is in the CLR of course but I think the POCO definition is only in regards to basic types. The definition was taken from POJOs and they don't include anything that inherits from Java SE. I believe `List` is in fact inheriting from `IList` in the .NET framework. – beautifulcoder Dec 27 '13 at 21:02
  • @beautifulcoder: There's a lot more discussion here: http://stackoverflow.com/questions/250001/poco-definition The main point of the POCO (or POJO) concept is to be portable, not bound to any specific framework external to the core language. Collections are part of the core .NET implementation and are portable across all platforms. They're not bound to the .NET Framework any more than the CLR itself is (which is the "C" in "POCO"). This is contrasted to something like a hydrated EF object or CSLA object, which is bound to those frameworks. – David Dec 27 '13 at 21:08
  • @David, looks like the definitions are rather ambiguous as to whether to include lists and other objects as part of a POCO object. In terms of MVC, I don't recommend tightly coupling models with other models. The point is to separate concerns and keep the software agile. – beautifulcoder Dec 27 '13 at 21:21
0

Just replace

@model List<MyPredictor.Models.Log.LogItemModel>

with

@model MyPredictor.Models.Log.LogModel

and then in the for:

@for (int i = 0; i < Model.Log.Count; i++)

the hiddens:

@Html.HiddenFor(m => m.Log[i].SomeProperty ...

However, I still don´t know where the Winner and Runnerup properties are.

lante
  • 7,192
  • 4
  • 37
  • 57
  • It was like that first. But did not work, that is when I saw another article saying to do it the way I am doing now, but also does not work – NightStalker Dec 26 '13 at 14:36
  • try: `@Html.HiddenFor("Log[" + i + "].SomeProperty...` and the rest of the hidden data. The problem is the name of the hidden. I would like to see the whole view – lante Dec 26 '13 at 14:40
0

Follow this article which explains model binding clearly and help you to bind the list properly

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

the key thing is to set the proper index

<input type="hidden" name="Log.Index" value="cold" />
    <input type="hidden" name="Log[cold].TeamID " value="your value" />
    <input type="hidden" name="Log[cold].TeamName " value="your value" />

here cold is the index of the list you can set any values as an index but it should be unique.

Anto Subash
  • 3,140
  • 2
  • 22
  • 30