-1

I am making my MVC application. I am creating a form, with a table in it. A table is supposed to contain users and grades that they have (something like mark sheet at schools). I want the marks to be modifable, so I made them of type TextBox with default value as in database, but apparently, when I press "Apply changes" button, the controller sees the list of all marks as null. Why is it so?
My View (a part of it):

@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@model ClassDeclarationsThsesis.Models.ClassesViewViewModel


@{
    ViewBag.Title = "ClassesView";
}
<h2>ClassesView</h2>
<select id="sel">
    <option value="week">Current week</option>
    <option value="total">Total</option>
</select>
@{
    int i = 0;
    int inside = 0;
}
@using (Html.BeginForm("ClassesView", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
        <div id="week">
        <table border="1" width="500">
            <tr>
                <th>Surname</th>
                <th>Name</th>
                @foreach (var task in Model.current)
                {
                    <th>@task.name</th>
                }
                <th>Total</th>
            </tr>
            @{
                int counter = 0;
                int counter1 = 0;
            }
            @foreach (var user in Model.curr_users)
            {

                if (user.user_type.Replace(" ", String.Empty) == 1.ToString())
                {

                    <tr>
                        <th>@user.surname</th>
                        <th>@user.name</th>
                        @foreach (var task in Model.current)
                        {
                            foreach (var grade in Model.grading)
                            {
                                if (user.user_id == grade.user_id)
                                {
                                    if (task.task_id == grade.task_id)
                                    {
                                        inside = task.value;
                                        i = i + task.value;
                                        counter1++;
                                    }

                                }

                            }
                            <th>@Html.TextBoxFor(m => m.points[counter + counter1 - 1], new { @class = "form-control", @Value = @inside, style = "width:50px;" })</th>
                            inside = 0;
                        }
                        <th>
                            @i
                        </th>
                        @Html.HiddenFor(m => m.class_id)
                        @Html.HiddenFor(m => m.student_id)
                    </tr>
                }
                i = 0;
                counter++;
            }
        </table>
        <input type="submit" class="btn btn-default" value="Apply changes" />

    </div>
                }

points that I used here is List<int> in ClassesViewViewModel. What am I doing wrong?
EDIT:
Added the controller:

public ActionResult ClassesView(ClassesViewViewModel value)
{
    ClassDeclarationsDBEntities4 entities = new ClassDeclarationsDBEntities4();
    ClassesViewViewModel model = new ClassesViewViewModel();
    model.users = entities.Users.ToList();
    model.tasks = entities.Tasks.ToList();
    model.group_id = value.group_id;
    model.class_id = value.class_id;
    model.grading = entities.Gradings.ToList();
    model.s_u = entities.Subjects_Users.ToList();
    model.t = new List<ClassDeclarationsThsesis.Classes.Task>();
    model.current = new List<ClassDeclarationsThsesis.Classes.Task>();
    model.curr_users = new List<ClassDeclarationsThsesis.Classes.User>();
    DateTime max = DateTime.MinValue;
    foreach (var task in model.tasks)
    {
        if (task.class_id == model.class_id)
        {
            model.t.Add(new ClassDeclarationsThsesis.Classes.Task(task.task_id, task.class_id, task.name, task.points, task.deadline));
        }


    }
    foreach (var task in model.t)
    {
        if (DateTime.Compare(task.deadline, max) > 0)
        {
            max = task.deadline;
        }
    }
    foreach (var task in model.t)
    {
        if (DateTime.Compare(task.deadline, max) == 0)
        {
            model.current.Add(task);
        }
    }
    foreach (var s_u in model.s_u)
    {
        if (s_u.class_id == model.class_id && s_u.group_id == model.group_id)
        {
            foreach (var user in model.users)
            {
                if (user.user_id == s_u.user_id)
                {
                    model.curr_users.Add(new ClassDeclarationsThsesis.Classes.User(user.name, user.surname, user.user_id, user.user_type, user.email, user.password));
                }

            }
        }

    }

    if (ModelState.IsValid)
    {
        for(int i=0;i<model.points.Count();i++)
        {
            //getting null here
        }
    }
    else
    {
        return View(model);
    }


    return View(model);
}
Maciej Miśkiewicz
  • 301
  • 1
  • 4
  • 20
  • Show us your controller code please. – Yogi Jan 16 '17 at 07:01
  • @Yogi please see the edit. – Maciej Miśkiewicz Jan 16 '17 at 07:03
  • 1
    It's hard to tell with this code, but probably because your indices are non sequential and/or do not start with zero. For the model binding to work, list indices must begin with zero and be sequential with no gaps. – GSerg Jan 16 '17 at 07:04
  • Your controller does not make sense either. You first build the model manually (like you would from a `get` action to return the model to a view), then you call `ModelState.IsValid` (like you would from a `post` where you receive an already built model from outside), then you return view(model) like it's a `get` again, and in the entire process the only values you are using from the bound model are `group_id` and `class_id`. Make up your mind. – GSerg Jan 16 '17 at 07:08
  • You cannot use a `for` loop to generate form controls for a collection - refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943). And never set the `value` attribute when using the `HtmlHelper` methods –  Jan 16 '17 at 07:09
  • @StephenMuecke `points` is a `list` and they are using `m => m.points[counter + counter1 - 1]` which does generate indices. – GSerg Jan 16 '17 at 07:11
  • @GSerg Yes, but it will never get correct 2-way model binding (and as you have noted, the `if` blocks means that indexers are likely not zero-based and consecutive) –  Jan 16 '17 at 07:13
  • 1
    @StephenMuecke Yes, they most likely have messed up indices, but I always thought the approach was correct in principle (i.e. having an `IList` and using `EditorFor(m => m.list[index])`). It certainly has fixed the naive `foreach` loops and provided two-way binding. I am aware of editortemplate-based ways and [I like them](http://stackoverflow.com/q/25333332/11683), but can it be said this one is not correct? – GSerg Jan 16 '17 at 07:21
  • @GSerg, There can be problems if OP would need to return the view (if say `ModelState` was invalid) because of the way the `HtmlHelper` metohds use values of `ModelState`. Using a custom `EditorTemplate` (in which case all that's needed is `EditorFor(m => m.List)`) or a `for` loop is always best –  Jan 16 '17 at 07:26

2 Answers2

1

1) You should change the "value" as "model" at HttpPost action method.

public ActionResult ClassesView(ClassesViewViewModel model)

2) There are a lot of line at your action method.You should learn repository and service patterns.Briefly you should put the db reading,inserting,updating line in a repository class.You should make repository classes for each entities.Business logic ( validation etc ) must be in the service classes.

Mehmet
  • 680
  • 5
  • 14
-1

Okay so I found the answer. I changed value in controller to model and also corrected the counter in view to ensure that the values are consecutive, starting from 0. Thank you for your support.

Maciej Miśkiewicz
  • 301
  • 1
  • 4
  • 20
  • 1
    Then why have you accepted an answer that has nothing to do with you issue - changing the parameter name has nothing to do with it (unless you model has a property name `value` which it does not appear to have) –  Jan 16 '17 at 07:41
  • @StephenMuecke it did have a property name `value` As stated in edit. Changing it was not the full sollution, so I added my solution, which worked. – Maciej Miśkiewicz Jan 16 '17 at 07:46
  • 1
    Cant see anything in your edit which suggest you have a property named `value` :) –  Jan 16 '17 at 07:52