1

I'm having a view to use update roles for user and I want to pass a list of values of roles in my for loop from View to RoleViewModels in my Controller. How can I do it ?

UserViewModels:

public class UserViewModels
{
    // ...
    [DisplayName("Role")]
    public List<RoleViewModels> ListRoles { get; set; }
}

Controller:

[HttpPost]
public ActionResult Edit(UserViewModels userViewModels)
{
    return View(userViewModels);
}

my view:

@for (int i = 0; i < Model.ListRoles.Count(); i++)
            {
                <label style="display:block">
                    @Html.CheckBoxFor(model => model.ListRoles[i].Selected)
                    @Html.HiddenFor(model => model.ListRoles[i].Id)
                    @Html.LabelFor(model => model.ListRoles[i].RoleName, Model.ListRoles[i].RoleName)
                </label>
            }

ajax script:

<script>
        $(document).ready(function () {
            $("#btnUpdate").click(function (e) {
                e.preventDefault();

                var data = {
                    Id: $("#Id").val(),
                    UserName: $("#UserName").val(),
                    Active: $("#Active:checked").val(),
                    // ListRoles: **get values here ???**
                };
                $.ajax({
                        type: "POST",
                        url: "@Url.Action("Edit", "User")",
                        data: data,
                        dataType: 'json',
                        success: function (result) {
                            alert('Update successful !');
                        },
                    });
            });
        })
    </script>
2
  • Use a Class and then Get the value on click of the class Commented Dec 1, 2015 at 10:41
  • 2
    Don't you want to wrap your inputs with form and then just use jquery .serialize()? It's cleaner Commented Dec 1, 2015 at 10:47

2 Answers 2

1

From my experience I believe the best way to use built in HTML Helpers and Model binding is to either use it the way it expects you to or do it all manually.

The code you have shown seems to be mixing the manual part and the built in part together . There are two ways you could solve this issue , depends on what you like

Option #1 : MVC way

In this case we use the HTML helpers and the model binders that are in MVC to get the UserViewModels back in your controller .

<form id="myform">
@for (int i = 0; i < Model.ListRoles.Count(); i++)
            {
                <label style="display:block">
                    @Html.CheckBoxFor(model => model.ListRoles[i].Selected)
                    @Html.HiddenFor(model => model.ListRoles[i].Id)
                    @Html.LabelFor(model => model.ListRoles[i].RoleName, Model.ListRoles[i].RoleName)
                </label>
            }
</form>

and then submit the form using

$.ajax({
                        type: "POST",
                        url: "@Url.Action("Edit", "User")",
                        data: $("#myFormId").serialize(),

                        success: function (result) {
                            alert('Update successful !');
                        },
                    });

The import part in this is data: $("#myFormId).serialize(),

MVC is not the best at handling arrays , check this post by phil hack http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/ to understand how the model binder works and what you need to do to make it work correctly.

Option #2 Manual

    <form id="myform">
        @for (int i = 0; i < Model.ListRoles.Count(); i++)
                    {
                        <label style="display:block">
                          <input type="checkbox" id= "chk@i" >
 <input type="hidden" id= "hiddenIdField@i" >
 <input type="hidden" id= "hiddenRoleName@i" >

                        </label>
                    }
        </form>

Then while constructing the object back you need to recreated the entire model

var data = new Object();
data.Id = $("#Id").val();
data.UserName =  $("#UserName").val();
data.Active = $("#Active:checked").val();
data.ListRoles  = [];
var firstRole = new Object();
firstRole.PropertyName = $("#correctId").val();
..
..
data.ListRoles.push(firstRole );

You need to make sure that the names of properties are exactly same as the array.

Option #2 is lot of manual work and if you are having to do that a lot in code , you may want to consider using client side MVC framework instead of the HTML helper based MVC framework.

Hope this helps.

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

Comments

1

Well, here's what i was talking about.

Wrap your inputs with form tag:

<form id="your-form-id">
        @for (int i = 0; i < Model.ListRoles.Count(); i++)
        {
            <label style="display:block">
                @Html.CheckBoxFor(model => model.ListRoles[i].Selected)
                @Html.HiddenFor(model => model.ListRoles[i].Id)
                @Html.LabelFor(model => model.ListRoles[i].RoleName, Model.ListRoles[i].RoleName)
            </label>
        }
</form>

And then you can fo it much simpler in your js code:

<script>
        $(document).ready(function () {
            $("#btnUpdate").click(function (e) {
                e.preventDefault();

                //here is your serialization
                var data = $("#your-form-id").serialize();

                $.ajax({
                        type: "POST",
                        url: "@Url.Action("Edit", "User")",
                        data: data,
                        dataType: 'json',
                        success: function (result) {
                            alert('Update successful !');
                        },
                    });
            });
        })
    </script>

1 Comment

thank you have answered me. But I don't want to use $("#formName").serialize() because It will get all values in form to pass to controller. In some cases I only want to get specific values to pass to controller and I prefer use to this way to get values. var data = @Model.ListRoles; $.each(data, function(){ this.Id; this.Selected; })

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.