1

i try to search this problem, but could not find a solution for it, please help me:

my viewModel:

namespace webShop.ViewModels.Home
{
    public class RegisterUserViewModel
    {
        public UserDB User { get; set; }

        public UsersDetaile UsersDetaile { get; set; }

        public IEnumerable<state> state { get; set; }
    }
}

my model:

public partial class UserDB
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public string Roles { get; set; }
    public byte Status { get; set; }

    public virtual UsersDetaile UsersDetaile { get; set; }
}

public partial class UsersDetaile
{
    public int userID { get; set; }
    public Nullable<System.DateTime> BirthDate { get; set; }
    public string Mobile { get; set; }
    public string Tell { get; set; }
    public bool Gender { get; set; }
    public byte city { get; set; }
    public byte state { get; set; }
    public string postCode { get; set; }
    public string address { get; set; }

    public virtual City City1 { get; set; }
    public virtual State State{ get; set; }
    public virtual UserDB UserDB { get; set; }
}

and my controller:

[HttpGet]
public ActionResult Register()
{ 
    stateRepository stateRep = new stateRepository();
    var model = new RegisterUserViewModel();
    model.state = stateRep.Select().ToList();
    return View(model);
}

[HttpPost]
public ActionResult Register(RegisterUserViewModel user) //Problem: postback viewModel is null
{
   //My Code
}

and my register view

@model webShop.ViewModels.Home.RegisterUserViewModel

@using (Ajax.BeginForm("Register", "Home", new AjaxOptions { HttpMethod = "Post", Url = "/Home/Register" }))
{

  @Html.AntiForgeryToken()
  @Html.ValidationSummary(true)
  <h1 class="block-header">Register</h1>
      <div class="group">
          <label class="label">Name <span class="required">*</span></label>
          <div class="controls">
              @Html.TextBoxFor(p => p.User.Name, new { @class = "text" })
              @Html.ValidationMessageFor(p => p.User.Name)
          </div>
      </div>

    //....

  <div class="group">
        <label class="label">Address </label>
        <div class="controls">
            @Html.TextBoxFor(p => p.UsersDetaile.address, new { @class = "text" })
            @Html.ValidationMessageFor(p => p.UsersDetaile.address)
        </div>
  </div>

  <div class="form">
    <div class="group">
        <div class="controls">
             <button class="button">Submit</button>
        </div>
    </div>
  </div>
}

after press submit userDB and usersDetaile is null, what can i do?

mmz
  • 35
  • 1
  • 6

2 Answers2

7

When you have ViewModels with complex types... you need to call the default Constructor of the complex properties.

public class RegisterUserViewModel
{

    public RegisterUserViewModel() {
        User = new UserDB();
        UsersDetaile = new UsersDetaile();
    }

    public UserDB User { get; set; }

    public UsersDetaile UsersDetaile { get; set; }

    public IEnumerable<state> state { get; set; }
}

This way, the binder can load the properties values. You don't need anything else.

One thing that looks weird, at least, is that your ViewModel has a property called UsersDetaile that is the same name as the type. The same property is inside the UserDB. This could make YOU and the binder error prone.

Romias
  • 13,783
  • 7
  • 56
  • 85
  • This works, there is a [fiddle](https://dotnetfiddle.net/dAEPAO) – Max Brodin Dec 29 '14 at 19:09
  • I had a similar issue once and the constructor fixed it. It should work fine if you add the default constructor. – GWP Dec 29 '14 at 23:46
  • 3
    You do **not** need to add a default constructor that initializes the complex properties (the `DefaultModelBinder` does this by default)! The issue is that the parameter of the POST method is named `user` and the view model also has a property named `user` so it cant be bound. Change the method signature to `public ActionResult Register(RegisterUserViewModel model)` - or any other name other that the name of a property - and it will work fine. –  Jan 09 '15 at 06:24
  • This works! Thank you so much. – Nick Burggraaff Jan 18 '18 at 09:23
1

To bind nested ViewModels use templated helpers, they are similar to partial view. So to make your code work:

  • Create new folder EditorTemplates in your Home/View folder
  • Add 2 new files UsersDetaile.cshtml and UserDB.cshtml
  • Move your markup related to the classes to these files
  • In your main view put this instead: @Html.EditorFor(m => m.User) and @Html.EditorFor(m => m.UsersDetaile)
Max Brodin
  • 3,903
  • 1
  • 14
  • 23