0

Model as below:

public class User
    {
        [DisplayName("ID")]
        [Range(0, 9999)]
        public int ID { get; set; }
public string Mask { get; set; }
}

And then controller returns IQueryable of above model

There are two views. Parent view and then partial view which renders each row from the Model

Main View

@model IQueryable<User>
@{
    var Array = Model.ToArray();

}
//Header here
            <tbody id="table-body-vlan">
                @{
                    for (var i = 0; i < Array.Length; i++)
                    {
                        Html.RenderPartial("_AddRow", Array [i], new ViewDataDictionary() { { "Index", i } });
                    }
                }
            </tbody>
        </table>
    </div>

    }

**And then partial view **

@model User
@{
    var index = ViewData["Index "];
}

<tr class="js-deletable-item" id="row-@index" data-id="@Model.ID" >

    <td class="editable">
        @Html.TextBoxFor(v => Model.ID, new {Name = "ID[" + index + "]", id = "id-" + Model.ID, Value = Model. ID > 0 ? Model. ID.ToString() : ""})
    </td>
    <td class="editable">
        @Html.TextBoxFor(v => Model.Name, new {Name = "Id[" + index + "].Name", data_val = "false" })
    </td>
</tr>

Issue as below: If there are 10 records in the IQueryable then client side validations applies only to first row.

e.g. if I type 101S for ID field in first row I gets the warning (By changing the background color) that invalid ID. But if I do same for second or other rows then I don't see background color change. Client side validations (defined through Data Annotations) are applying only for first row.

I guess after first row rendered it is not adding those Annotation related properties to the other rows.

user2739418
  • 1,623
  • 5
  • 29
  • 51
  • Your generating `name` attributes which have no relationship to your model (not sure what awful hacks you mus be using in the POST method to make this work. Use an `EditorTemplate` for typeof `User` (refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943) or if you really want to use a partial, then you need to pass the `HtmlFieldPrefix` - refer [this answer](https://stackoverflow.com/questions/29808573/getting-the-values-from-a-nested-complex-object-that-is-passed-to-a-partial-view/29809907#29809907) –  Sep 12 '17 at 22:31
  • And NEVER NEVER attempt to change the `name` or `value` attribute when using a `HtmlHelper` method –  Sep 12 '17 at 22:31
  • tx Stephen. Actually I have not written the code but fixing some of the bugs. Finally did resolve it with suggestions given here – user2739418 Sep 15 '17 at 07:59

1 Answers1

0

I suggest you take a look at Editor and Display Templates in MVC:

Create an editor template here : ~/Views/Shared/EditorTemplates/User.cshtml like this:

@model User
<tr class="js-deletable-item">
    <td class="editable">
        @Html.TextBoxFor(m => m.Id)
    </td>
    <td class="editable">
        @Html.TextBoxFor(m => m.Name)
    </td>
</tr>

This will automatically be rendered for each element of your model whenever you call EditorForModel.

In your controller, do a .ToList() on your IQueryable<User>() object, before sending to the view.

In the Main View:

@model IEnumerable<User>

<table>
    <thead>
        <tr>
            <td>Id</td>
            <td>Name</td>
        </tr>
    </thead>
    <tbody>
        @Html.EditorForModel()
    </tbody>
</table>

Much simpler and cleaner right? But the main advantage of using these templates is, they will automatically create appropriate name attributes. Something like:

<input data-val="true" name="[0].Id" value="" />
<span class="text-danger field-validation-valid" data-valmsg-for="[0].ID"></span> 

Each row gets a unique name attribute. In your code, all your rows have the same name="ID" and data-valmsg-for="ID". Because of this, only first row is getting validated.

The name attributes are also crucial when forms containing collections are being submitted. Otherwise, the User list will end being null when you submit (Refer).

If you don't want to use EditorTemplates, you'd have to do a for loop (not foreach) and populate the rows.

adiga
  • 34,372
  • 9
  • 61
  • 83