user1476956
user1476956

Reputation: 71

Html.BeginForm passing Model item value

Am using mvc4 and am calling another controller in my view using Html.BeginForm

It work fine!but here am using textbox to pass the value. How to modify this code so am using

@Html.DisplayFor(modelItem => item.UserName) ....instead of @Html.TextBox("UserName")

here my view :

image of it:enter image description here

                     @using OTMS.Models
        @model IEnumerable<OTMS.Models.UserProfile>

        @{
           ViewBag.Title = "Index";
        }

                <!-- Table Continer -->
        <div class="spacer_10px"></div>
        <div class="container clearfix">
            <div class="grid_12"> 
               <div class="table_wrapper table_gray">
        <table>

             <tr>
                <th>
                   <p>User Name</p>
                </th>
                 <th>
                   <p>Role</p>
                </th>
                 <th>
                   <p>Role</p>
                </th>
            </tr>


            @if (Model != null) {
        foreach (var item in Model) {
        <tr>


            <td>
                @Html.DisplayFor(modelItem => item.UserName)
            </td>

            <td>
              @using(Html.BeginForm("GetRoles", "Account",FormMethod.Post)){
              @Html.AntiForgeryToken()
            <div class="editor-label">Username : </div>
             @Html.TextBox("UserName") //here user will enter user name / I dont want user to enter that ,it should be done Automatically 



                  <div class="spacer_20px"></div>
                  <div class="button button-orange"> <span class=" form_button clearfix">
                  <input type="submit" class="submit" name="submit" value="Get Roles for this User" />
                  </span> </div>//by clicking that will pass the user name to controller (GerRole)/I dont want  button
        }


            </td>

            <td>

               @using (Html.BeginForm("Submit", "Account", FormMethod.Post))
           {
                     @Html.Hidden("userName", item.UserName)

                     @Html.DropDownList("selectedRole", (SelectList)ViewBag.Roles)

                     <div class="button button-orange"> <span class=" form_button clearfix">
                    <input type="submit" class="submit" name="submit" value="Update Change" />
                    </span> </div>
            }

            </td>
        </tr>

        }
            }
             </table>
                 </div> </div> 

here my controller :

   public ActionResult Index()
    {
        var model = _db.UserProfiles.ToList();

        ViewBag.Roles = new SelectList(Roles.GetAllRoles());

        return View(model);
    }

    [HttpPost]

    public ActionResult GetRoles(string UserName)
    {
        if (!string.IsNullOrWhiteSpace(UserName))
        {
            ViewBag.RolesForThisUser = Roles.GetRolesForUser(UserName);
            SelectList list = new SelectList(Roles.GetAllRoles());
            ViewBag.Roles = list;


        }
        return View("showrole");
    }

another view:

image of it : enter image description here

            @{
                ViewBag.Title = "showrole";
            }

            <h2>showrole</h2>
            @if(ViewBag.RolesForThisUser != null) {
                <text>
                <h3>Roles for this user </h3>
                <ol>
            @foreach (string s in ViewBag.RolesForThisUser){
                <li>@s</li>   
            }
                            </ol>
                </text>
            }

Upvotes: 1

Views: 2561

Answers (3)

Oleksii Aza
Oleksii Aza

Reputation: 5398

What you definetely need to do is to create a view model for your view, for me it looks something like this:

public class UserViewModel
{
    public string UserName {get;set;}
    public IEnumerable<string> UserRoles { get; set; }
}

Then in your index action you would return a list of these view models. You certainly could do it like this:

public ActionResult Index()
{
    var model = _db.UserProfiles.ToList()
                                .Select(u => new UserViewModel{
                                     UserName = u.UserName,
                                     UserRoles = Roles.GetRolesForUser(u.UserName)
                                                      .AsEnumerable()
                                })
                                .ToList();
    ViewBag.Roles = new SelectList(Roles.GetAllRoles());
    return View(model);
}

but I wouldn't. It's because with this code you're doing one aditional query for every user just to get his roles. I think you need to add roles table to your EntityFramework model and try to do this with single query. So you need to extend your UserProfile with roles:

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }

    public ICollection<UserRoles> UserRoles { get; set; }
}

[Table("webpages_Roles")]
public class UserRoles
{
    [Key]
    public int RoleId { get; set; }
    public string RoleName { get; set; }

    public ICollection<UserProfile> UserProfiles { get; set; }
}

Then update your DbContext with info about many to many relationship between UserProfils and UserRoles:

public class UsersContext : DbContext
{
    public UsersContext()
        : base("DefaultConnection")
    {
    }

    public DbSet<UserProfile> UserProfiles { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<UserRoles>()
        .HasMany<UserProfile>(r => r.UserProfiles)
        .WithMany(u => u.UserRoles)
        .Map(m =>
        {
            m.ToTable("webpages_UsersInRoles");
            m.MapLeftKey("UserId");
            m.MapRightKey("RoleId");
        });
    }
}

After that in your index action - you can simply do:

    var model = _db.UserProfiles.Select(u => new UserViewModel()
    {
        UserName = u.UserName,
        UserRoles = u.UserRoles.Select(ur=>ur.RoleName)
    }).ToList();

And it will be one query instead of several in cycle.

EDIT: Your model changed so you need to change @model IEnumerable<OTMS.Models.UserProfile> to @model IEnumerable<OTMS.Models.UserViewModel> And then:

@foreach(var user in Model)
{
    //display user
    @foreach(var role in user.UserRoles)
    {
        //display roles with @role
    }
}

If you want to use DisplayTemplates - you can move logic for displying user into template. For this you need to create view by path ~/Views/Shared/DisplayTemplates/UserViewModel.cshtml

@model OTMS.Models.UserViewModel
//display user
@foreach(var role in user.UserRoles)
{
     //display roles with @role
}

then in Index.cshtml you can change code to this:

@foreach (var user in Model)
{
    @Html.DisplayFor(n => user)
}

Upvotes: 1

super
super

Reputation: 2328

Try this:

Controller

[HttpPost]
public ActionResult GetRoles(string UserName)
{
    if (!string.IsNullOrWhiteSpace(UserName))
    {
        ViewBag.RolesForThisUser = Roles.GetRolesForUser(UserName);
        SelectList list = new SelectList(Roles.GetAllRoles());
        ViewBag.Roles = list;
    }
    return View("......");
}

View

@ViewBag.Name
@using(Html.BeginForm("GetRoles", "Account")){
@Html.AntiForgeryToken()
<div class="editor-label">Username : </div>
@Html.TextBox("UserName")
<div class="spacer_20px"></div>
<div class="button button-orange">
    <span class=" form_button clearfix">
        <input type="submit" class="submit" name="submit" value="Get Roles for this User" />
    </span>
</div>
}

Here is the DEMO

Upvotes: 0

Shekhar Pankaj
Shekhar Pankaj

Reputation: 9145

First and for All ,The Main Confusion is with this Helper..have a Breif Look here

  • Use HiddenFor when you want to provide posted data that the user does not need to be aware of."

  • Use DisplayFor when you want to show records but not allow them to be editted.

  • Use TextBoxFor when you want to allow user input or allow the user to edit a field. `

Now your question is Like this.. How can i use displayfor to hit my controller!!!!

You could accomplish this with a duo of HiddenFor and DisplayFor. Use HiddenFor to have the values ready to be posted, and DisplayFor to show those values.

so to meet your Requirement

<div class="editor-label"> Username : </div>
@Html.TextBox("UserName") 

Replace

<div class="editor-label"> Username : </div>
@Html.HiddenFor(modelItem=>item.username)
@Html.DisplayFor(modelItem=>item.username) 

Remember Displayfor Renders Only Label In the Browser,to post it back to Controller you need HiddenFor

Upvotes: 0

Related Questions