0

I have a basic Create / Edit / Delete / Index format created by MVC with my class (ClassA). The class contains a list of objects (ClassB).

When I call the view to edit the object I can edit all the members of ClassA (textfields etc), but how can I edit the list of objects and then still have them returned back to the post action?

When I try and create and iterate through the objects and add them to the form, it is not returned with the object (ClassA) and the list of objects is empty.

Please help. What is the best practice for doing this?

Below is an example

 public ActionResult Edit(int id)
    {
        ClassA objA = db.ClassAs.Single(a => a.id == id);

        objA.myListOfBs.Add(new ClassB());

        return View(objA);
    }

     [HttpPost]
    public ActionResult Create(ObjectA obj)
    {
        obj.myListOfBs <--- this is empty! :(
        if (ModelState.IsValid)
        {
        }

        return View(obj);
      }

Model classes are :

class ClassA {
        int id;
    List<ClassB> myListOfBs;
 }

 class ClassB {
    int id;
    string name;
 }

Here is my View

@model MyProject.Models.ClassA

@{
    ViewBag.Title = "ClassA Object";
}
@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Objects</legend>

        @Html.EditorFor(model => model.myListOfBs)

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}
4
  • Could you please post your model classes? Commented Mar 14, 2013 at 12:59
  • stackoverflow.com/questions/15049463/… Commented Mar 14, 2013 at 13:00
  • Your issue is almost certainly in your view. Could you post it please? I'm guessing you are using a foreach loop to iterate through the list, and not respecting the mvc model binders naming requirements' Commented Mar 14, 2013 at 13:10
  • changed it to use the @Html.EditorFor but it still wont pass any to the Post Action :( Commented Mar 14, 2013 at 13:52

3 Answers 3

1

Found out why this was happening. It was a mistake by me but one I didnt realise would be causing it.

The object within my main object was declared

class ClassA {
 public ClassB country;
}

instead of

class ClassA {
 public ClassB country {get; set;}
}

So it seems it has to be a property to correctly bind the objects.

MAIN ISSUE RESOLVED HERE

I would also like to add that although adding the set/get tags allow the passing of an object through to the post, it would still not work with a list inside an object.

I did finally found out how to do this here (ASP.NET MVC 3 Binding to a Collection inside an Object) where basically you need to map to the specific item in the Model

Example:

 @for (int i = 0; i < Model.myListOfBs.Count; i++)
 {
     <div>
        @Html.LabelFor(m => Model.myListOfBs[i].name )
    </div>
    <div>
        @Html.TextBoxFor(m => Model.myListOfBs[i].name )
    </div>
 }

Mapping explicitly to the array location did the trick. As you can't explicitly map to an item of a list using foreach it fails.

Also if you are like me and using Entity Framework you are most likely going to have to use ViewModels to access array elements.

Sign up to request clarification or add additional context in comments.

Comments

0

I've seen this before. The easiest way to do this (with this example structure) is:

ViewModel:

public string CompanyName { get; set; }
public List<ViewModelOfObjects> SubObjects { get; set; }

Like you can see, your sub-objects should have their own ViewModel, then you can do this in your View.

@model YourMainViewModel

@Html.EditorFor(model => model.CompanyName)

// MVC is clever enough to work this out and list all the sub-Views, even if they are hidden fields and not editable.
@Html.EditorFor(model => model.SubObjects)

4 Comments

I dont completely understand this, the SubObjects are replaced by a different type? do I have to create a different model and copy the data from ClassB object to ViewModelOfClassB object?
The SubObjects are a ViewModel within their own right. Say, if it is a Customer object, it would be a new CustomerViewModel, with the same properties (but as a ViewModel) as the Customer object. Then MVC would be able to relate these sub-objects to your main object.
I'm afraid this still didn't work. It still nulls out the list when it fires the post event. Although I tried creating a List of strings, and view it on the view with @Html.EditFor and this worked! It passed it through correctly and the list wasnt null on the postback. I thought the ViewModel was just the same as Model, but where the structure has changed and you dont want to modify your base model?
Additional: I changed it so the subobject was just a single object of a different type and not a list, and this gets posted (found with fiddler). but doesnt get attached to the main.
0

The way I have done this in the past is using a naming convention that the model binder can recognise to bind collections.

For example in your case you could have the following in your view:

@model ClassA
int index = 0;
@foreach (var classB in Model.myListOfBs)
{
    //Notice the use of "obj", this matches the name of your model parameter in your post action
    @Html.Hidden("obj.myListOfBs.Index", index)
    @Html.TextBox("obj.myListOfBs[" + index + "].name", classB.name)
    index++;
}

When posting this form to your action, the model binder will use the indexing naming convention detailed above to bind each of the fields to the myListOfBs collection in your model.

Alternatively, as @thedixon has noted, the MVC framework can create the field names automatically (I'm not sure this is possible in all versions of ASP.NET MVC):

@Html.EditorFor(model => model.myListOfBs)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.