3

I am developing an Asp.Net mvc application. In my project there are two forms in a single view like this:

enter image description here

To use multiple forms in a single view, there is a problem for validation using data annotation. First I found this link for using multiple forms in single view asp.net MVC 4 multiple post via different forms. Following answer of that link, I can add multiple forms. But I cannot validate using data annotation with that approach. So I googled for another solution.

This link (http://geekswithblogs.net/MightyZot/archive/2013/11/11/html.validationsummary-and-multiple-forms.aspx) also just the same, I have to add validation logic in controller. I found another solution (http://bluetubeinc.com/blog/2012/10/validating-multiple-forms-the-asp-dot-net-mvc3-way-using-strongly-typed-views). I thought this solution will solve my problem to validation using data annotation. But one thing to notice is that it is working with Ajax Form. But I followed that link and I am still having problem.

These are my view models:

public class AuthVM
    {
        public LoginViewModel LoginForm { get; set; }
        public RegisterViewModel RegisterForm { get; set; }
    }
public class LoginViewModel
    {
        [Required]
        [Display(Name = "Email")]
        public string Email { get; set; }

        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }
    }

    public class RegisterViewModel
    {
        [Required]
        [Display(Name = "User name")]
        public string UserName { get; set; }

        [Required]
        [DataType(DataType.Password)]
        [MaxLength(70)]
        public string Email { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    }

This is my controller and actions for login and register:

public class AccountController: Controller
{

[AllowAnonymous]
        public ActionResult Create(string returnUrl)
        {
            ViewBag.ReturnUrl = returnUrl;
            AuthVM model = new AuthVM
            {
                RegisterForm = new RegisterViewModel(),
                LoginForm = new LoginViewModel()
            };
            return View("Auth",model);
        }

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
           //check modelstate and continue
        }

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Register(RegisterViewModel model)
        {
            //check modelstate and continue
        }

}

This is my view:

<section id="form">
    <!--form-->
    <div class="container">
        <div class="row">
            <div class="col-sm-4 col-sm-offset-1">
                <div class="login-form">
                    <!--login form-->
                    <h2>Login to your account</h2>
                    @using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, null))
                    {
                        @Html.AntiForgeryToken()
                        @Html.ValidationSummary()
                        @Html.TextBoxFor(x => x.LoginForm.Email, new { placeholder = "Email" })
                        @Html.PasswordFor(x => x.LoginForm.Password, new { placeholder = "Password" })
                        <button type="submit" class="btn btn-default">Login</button>
                    }
                </div><!--/login form-->
            </div>
            <div class="col-sm-1">
                <h2 class="or">OR</h2>
            </div>
            <div class="col-sm-4">
                <div class="signup-form">
                    <!--sign up form-->
                    <h2>New User Signup!</h2>
                    @using (Html.BeginForm("Register", "Account", FormMethod.Post))
                    {
                        @Html.AntiForgeryToken()
                        @Html.ValidationSummary()
                        @Html.TextBoxFor(x => x.RegisterForm.UserName, new { placeholder = "Display Name" })
                        @Html.TextBoxFor(x => x.RegisterForm.Email, new { placeholder = "Email" })
                        @Html.PasswordFor(x => x.RegisterForm.Password, new { placeholder = "Password" })
                        @Html.PasswordFor(x => x.RegisterForm.ConfirmPassword, new { placeholder = "Retype password" })
                        <button class="btn btn-primary">Register</button>
                    }
                </div><!--/sign up form-->
            </div>
        </div>
    </div>
</section><!--/form-->
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

But when I submit the form, model state is always invalid because values are always null even if I input correct values. For example, I login, then form will submit to post login action, but value are always null.

enter image description here

Why is that always null? How can I bind to get correct values? How can I validate multiple forms in a single view (strongly typed view) using data annotation?

4
  • Its null because the model in your view is AuthVM, but the parameter in your POST method is LoginViewModel (not AuthVM) and LoginViewModel does not contain a property named RegisterForm Commented Jul 9, 2016 at 10:53
  • I tried add RegisterForm property to AuthVM. Not working as well. If I bind using AuthVM data annotation will validate both forms. So please how can I solve it? Commented Jul 9, 2016 at 11:03
  • You can use public asyn<ActionResult> Login [Bind(Prefix="RegisterForm")](LoginViewModel model) But I would question why you are creating a page like that (instead of having a Login view that includes a link to a Register view) Commented Jul 9, 2016 at 11:07
  • 1
    I also do not want to do that. But I have to follow silly designer as possible. Thanks so much for your support. I got that. Commented Jul 9, 2016 at 11:16

1 Answer 1

2

As @stephen-muecke says doing this will work:

public async Task<ActionResult> Register([Bind(Prefix="RegisterForm")]RegisterViewModel model)
        {
            //check modelstate and continue
        }

If you don’t want to do that then you can create a partial view for each form and pass the model required for that form to that partial view.

<section id="form">
    <!--form-->
    <div class="container">
        <div class="row">
            <div class="col-sm-4 col-sm-offset-1">
                <div class="login->
                     @Html.Partial("_LoginForm", Model.LoginForm)
                </div><!--/login form-->
            </div>
            <div class="col-sm-1">
                <h2 class="or">OR</h2>
            </div>
            <div class="col-sm-4">
                <div class="signup-form">
                     @Html.Partial("_RegisterForm", Model.RegisterForm)
                </div><!--/sign up form-->
            </div>
        </div>
    </div>
</section><!--/form-->
Sign up to request clarification or add additional context in comments.

Comments

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.