jmogera
jmogera

Reputation: 1759

MVC3 Postback doesn't have modified data

So I have the following code:

@model Project.Models.ViewModels.SomeViewModel
@using (Html.BeginForm("SomeAction", "SomeController", new { id = Model.Id}))
        {
            for(int i = 0; i < Model.SomeCollection.Count(); i++)
            {
                @Html.HiddenFor(x => Model.SomeCollection.ElementAt(i).Id)
                <div class="grid_6">
                    @Html.TextAreaFor(x => Model.SomeCollection.ElementAt(i).Text, new { @style = "height:150px", @class = "grid_6 input" })
                </div>
            }
            <div class="grid_6 alpha omega">
                <input type="submit" value="Next" class="grid_6 alpha omega button drop_4 gravity_5" />
            </div>
        }

On the Controller Side I have the following:

[HttpPost]
        public ActionResult SomeAction(int id, SomeViewModel model)
        {

            return PartialView("_SomeOtherView", new SomeOtherViewModel(id));
        }

My View Model is set up like this:

public class SomeViewModel
{
        public SomeViewModel()
        {

        }
        public IEnumerable<ItemViewModel> SomeCollection { get; set; }

}

public class ItemViewModel{

      public ItemViewModel(){}

      public int Id {get;set;}

      public string Text{get;set;}

}

The SomeCollection is always empty when SomeAction if performed. What do I have to do in order to show the updated values by users. Text Property and Id field.

Upvotes: 1

Views: 566

Answers (3)

Phillip Schmidt
Phillip Schmidt

Reputation: 8818

Well, for one thing, why do you have both the model AND id, a property of model, sent back to the controller? Doesn't that seem a bit redundant? Also, you're using a javascript for loop in the view. It'd be much easier to just use @foreach.

Anyway, your problem is that when you tell an action to accept a model, it looks in the post for values with keys matching the names of each of the properties of the model. So, lets say we have following model:

public class Employee
{
   public string Name;
   public int ID;
   public string Position;
}

and if I'm passing it back like this:

@using(Html.BeginForm("SomeAction", "SomeController"))
{
     <input type="text" name = "name" [...] />    //in your case HtmlHelper is doing this for you, but same thing
     <input type="number" name = "id" [...] />
     <input type="submit" name = "position" [...] />
}

To pass this model back to a controller, I'd have to do this:

Accepting a Model

//MVC matches attribute names to form values
public ActionResult SomethingPosted(Employee emp)
{
    //
}

Accepting a collection of values

//MVC matches parameter names to form values
public ActionResult SomethingPosted(string name, int id, string postion)
{
    //
}

or this:

Accepting a FormCollection

//same thing as first one, but without a strongly-typed model
public ActionResult SomethingPosted(FormCollection empValues)
{
    //
}

So, here's a better version of your code.

Your new view

@model Project.Models.ViewModels.SomeViewModel
@{
    using (Html.BeginForm("SomeAction", "SomeController", new { id = Model.Id}))
        {
            foreach(var item in Model)
            {
                @Html.HiddenFor(item.Id)
                <div class="grid_6">
                    @Html.TextAreaFor(item.Text, new { @style = "height:150px", @class = "grid_6 input" })
                </div>
            }
            <div class="grid_6 alpha omega">
                <input type="submit" value="Next" class="grid_6 alpha omega button drop_4 gravity_5" />
            </div>
        }
}

Your new action

[HttpPost]
public ActionResult SomeAction(int Id, string Text)
{
    //do stuff with id and text
    return PartialView("_SomeOtherView", new SomeOtherViewModel(id));
}

or

[HttpPost]
public ActionResult SomeAction(IEnumerable<ItemViewModel> SomeCollection)  //can't use someviewmodel, because it doesn't (directly) *have* members called "Id" and "Text"
{
    //do stuff with id and text
    return PartialView("_SomeOtherView", new SomeOtherViewModel(id));
}

Upvotes: 0

Shyju
Shyju

Reputation: 218952

Use an EditorTemplate

Create an EditorTemplate folder under your Views/YourcontrollerName and create a view with name ItemViewModel.cshtml

enter image description here

And Have this code in that file

@model  Project.Models.ViewModels.ItemViewModel
<p>
 @Html.EditorFor(x => x.Text) 
 @Html.HiddenFor(x=>x.Id)
</p>

Now from your Main view, call it like this

@model  Project.Models.ViewModels.SomeViewModel
@using (Html.BeginForm("SomeAction", "Home", new { id = Model.Id}))
{
    @Html.EditorFor(s=>s.SomeCollection)
    <div class="grid_6 alpha omega">
        <input type="submit" value="Next" class="grid_6 alpha omega button drop_4 gravity_5" />
    </div>
}

Now in your HTTPPOST method will be filled with values.

I am not sure what you want to do with the values( returning the partial view ?) So not making any comments about that.

Upvotes: 2

David Hirst
David Hirst

Reputation: 2012

I am not sure you have posted all the code.

Your action method does not do anything, since it returns a partial view (for some reason from a post call, not an ajax request) using a new model object.

Your effectively passing a model back to the action and then discarding it, and returning a new model object. This is the reason your collection is always empty, its never set anywhere.

Upvotes: 0

Related Questions