1
votes

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>
            }
3
Why do you want to use @Html.DisplayFor? Why not @Html.EditorFor? - Oleksii Aza
i want to show the value only ..without input field and without submit button .. - user1476956
It's not clear for me what you want to archieve. You want the form which is calling another controller, but you don't want submit button, but how do you plan to post data to controller? Or the code with @Html.DisplayFor(modelItem => item.UserName) is not working and you are wondering how to use it rightly? - Oleksii Aza
no the code working see Q again I update it .am using submit button to go to another view ..and I dont want that I want to show them in the table and same view and I dont know how! - user1476956
It seems that I understand what you are trying to archeive. Bassically you want to get rid of Get roles for this user button and just make the third column work. It's important to know if you have role or roles for current user inside UserProfile when you are quering it with _db.UserProfiles.ToList()? - Oleksii Aza

3 Answers

1
votes

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)
}
0
votes

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

0
votes

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