Question

I have this model:

public class TaskCreation
{
    public task_description task_desc { get; set; }
    public List<Metric> metric { get; set; }
    public List<Context> context { get; set; }
    public int scenarioId { get; set; }
    public short meas_id { get; set; }

}
public class Metric
{
    public string name { get; set; }
    public string value { get; set; }
}
public class Context
{
    public string name { get; set; }
    public string values { get; set; }
    public string upper_bound { get; set; }
    public string lower_bound { get; set; }
}

And this is my controller methods:

public ActionResult CreateTask2()
    {
        TaskCreation tc = new TaskCreation();
        tc = TempData["TCObject"] as TaskCreation;
        return View(tc);
    }
    [HttpPost]
    public ActionResult CreateTask2(TaskCreation TaskCreation)
    {
        //some code
    }

So the view receives a TaskCreation object and there are fields to enter a value for each metric and values, upper and lower bound for each context but in the [httppost] CreateTask2 the metric and context objects are null! Others attributes in the task_description object are binded correctly! How I can solve it?

This is my view:

@model Project.Models.TaskCreation
@using (Html.BeginForm("CreateTask2", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })) 
{
@Html.AntiForgeryToken()

<div class="form-horizontal">

    <hr />
    @Html.ValidationSummary(true)
 <div class="form-group">
        @Html.LabelFor(model => model.task_desc.Is_valid, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.task_desc.Is_valid)
            @Html.ValidationMessageFor(model => model.task_desc.Is_valid)
        </div>
    </div>
    <br />
    <div class="form-group">
        @Html.LabelFor(model => model.task_desc.repeat_interval, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.task_desc.repeat_interval)
            @Html.ValidationMessageFor(model => model.task_desc.repeat_interval)
        </div>
    </div>
    <div class="form-group">
        <p>Enter the metrics values:</p>
    </div>
    @foreach(var m in Model.metric)
    {
        <div class="form-group">
        @Html.Label(m.name, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(x => m.value, new { placeholder = "Value" })
            @Html.ValidationMessageFor(x => m.value)
        </div>
            <br />
    </div>
    }
    <div class="form-group">
        <p>Choose the constraints for each context:</p>
    </div>
        @foreach(var c in Model.context)
    {
            <div class="form-group">
                @Html.Label(c.name, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    <table>
                        <tr>
                            <td>
                                @Html.TextBoxFor(con => c.lower_bound, new { placeholder = "Lower Bound" })
                                @Html.ValidationMessageFor(con => c.lower_bound)<br />
                                @Html.TextBoxFor(con => c.higher_bound, new { placeholder = "Upper Bound" })
                                @Html.ValidationMessageFor(con => c.higher_bound)
                            </td>
                            <td>OR</td>
                            <td>
                                @Html.TextBoxFor(con => c.values, new { placeholder = "Selected Values Separated by Spaces" })
                                @Html.ValidationMessageFor(con => c.values)
                            </td>
                            <br />
                        </tr>
                    </table>
                </div>
            </div>
    }
     <div class="form-group">
          <div class="col-md-offset-2 col-md-10">
              <input type="submit" class="btn btn-default" />
          </div>
     </div>
</div>
}

Thank You

Was it helpful?

Solution

Instead of Foreach, use For loop -

  @for( int i = 0; i < Model.metric.Count; i++)
    {
        <div class="form-group">
        @Html.Label(Model.metric[i].name, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(m => m.metric[i].value, new { placeholder = "Value" })
            @Html.ValidationMessageFor(m => m.metric[i].value)
        </div>
            <br />
    </div>
    }

Similarly you can go ahead for context property too.

UPDATE: Please check below sample on how to get the properties of Child Models in the Parent model. We can use FOR loop to iterate the child models. If we use For loop, we can get the values of child model on the server side without any extra work. Check below sample -

Lets say we have following Model -

public class DataModel
{
    public string Name { get; set; }
    public string Email { get; set; }
    public List<XhrViewModel> eles { get; set; }
}

public class XhrViewModel
{
    public string data1 { get; set; }
    public string data2 { get; set; }
}

and then we have following controller action which will return create view -

    public ActionResult CreateData()
    {
        DataModel m = new DataModel();
        m.eles = new List<XhrViewModel>();
        m.eles.Add(new XhrViewModel());
        m.eles.Add(new XhrViewModel());
        m.eles.Add(new XhrViewModel());
        return View(m);
    }

And the create view is pretty simple -

@model Rami.Vemula.Dev.Mvc.Controllers.DataModel

@{
    ViewBag.Title = "CreateData";
}

<h2>CreateData</h2>

@using (Html.BeginForm("SubmitData", "Home", FormMethod.Post))
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>DataModel</h4>
        <hr />
        @Html.ValidationSummary(true)

        <div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name)
                @Html.ValidationMessageFor(model => model.Name)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Email, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Email)
                @Html.ValidationMessageFor(model => model.Email)
            </div>
        </div>

        @for (int i = 0; i < Model.eles.Count; i++)
        {
            <div class="form-group">
                @Html.LabelFor(model => model.eles[i].data1, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.eles[i].data1)
                    @Html.ValidationMessageFor(model => model.eles[i].data1)
                </div>
            </div>
        }

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" id="ClickMe" class="btn btn-default" />
            </div>
        </div>
    </div>
}

If you check in the above View, I used FOR loop instead of Foreach to render the child Model properties i.e., xhrViewModel.

And on click of the submit button, you will hit SubmitData controller action -

    public ActionResult SubmitData(DataModel m)
    {
        return View();
    }

Now when we run the application -

enter image description here

then on submit button, you get the values in the SubmitData controller action in this way -

enter image description here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top