I am trying to get my clienside validation to work when using an ajax request in a jquery ui dialog.
This means I have no submit button and I do no post back. I could not figure out why I could not get it to work.
I posted this question . I been playing around with it can come to the conclusion is that for whatever reason I need to load up the jquery.validate.unobtrusive with my partial view. It makes no sense to me.
Is this a bug?
Edit
I also gone and posted the error on the asp.net codeplex
The added benefit to this is that if you wish you can just download my little sample application and try it out.
Or you can Follow these steps
Make an non empty asp.net mvc 3 application( I am using razor)
_Layout.cshtml
#ViewBag.Title
<script type="text/javascript">
$(function ()
{
$.get('/home/dialog', null, function (r)
{
var a = $("#dialog").dialog({
resizable: false,
height: 500,
modal: true,
buttons: {
"Delete all items": function ()
{
$('#testFrm').validate().form();
},
Cancel: function ()
{
$(this).dialog("close");
}
}
}).html(r);
});
$('#testFrm').live('submit',function (e)
{
e.preventDefault();
});
});
</script>
</head>
<body>
<div class="page">
<div id="header">
<div id="title">
<h1>My MVC Application</h1>
</div>
<div id="logindisplay">
#Html.Partial("_LogOnPartial")
</div>
<div id="menucontainer">
<ul id="menu">
<li>#Html.ActionLink("Home", "Index", "Home")</li>
<li>#Html.ActionLink("About", "About", "Home")</li>
</ul>
</div>
</div>
<div id="main">
#RenderBody()
<div id="footer">
</div>
</div>
</div>
</body>
</html>
ViewUserControl1 (Partial View) - Stick in Home View folder
#model MvcApplication1.Models.TestModel
#using (Html.BeginForm("test","Account",FormMethod.Post,new {#id="testFrm"}))
{
#Html.ValidationSummary()
#Html.TextBoxFor(x => x.Name)
}
Index (should exist replace with this)
#model MvcApplication1.Models.TestModel
#{
ViewBag.Title = "Home Page";
}
<h2>#ViewBag.Message</h2>
<p>
To learn more about ASP.NET MVC visit http://asp.net/mvc.
</p>
#DateTime.Now
<div id="dialog">
</div>
note the dialog id this will be where the ajax request of the partial view gets stored
Home Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
public ActionResult test()
{
return null;
}
public PartialViewResult Dialog()
{
return PartialView("ViewUserControl1");
}
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
}
}
TestModel.cs // view model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
namespace MvcApplication1.Models
{
public class TestModel
{
[Required()]
public string Name { get; set; }
}
}
web.config
<appSettings>
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
Now run the application. Click "Delete all items" and "Submit Query".
Nothing should happen. No validation pops up for me.
Now go and add this line to the Partial View(ViewUserControl1)
<script src="../../Scripts/jquery.validate.unobtrusive.js" type="text/javascript"></script>
#model MvcApplication1.Models.TestModel
#using (Html.BeginForm("test","Account",FormMethod.Post,new {#id="testFrm"}))
{
#Html.ValidationSummary()
#Html.TextBoxFor(x => x.Name)
<input type="submit" />
}
Now try again.
It should now come up with validation errors.
I think I found some sort of a work around. Even though I think a automatic way should be done for something so basic as making the validation work with partial views
Work around
This is not a bug. When you load a PartialView using Ajax, you must then parse the unobtrusive validation attributes included in the new elements you are loading.
See http://forums.asp.net/t/1651961.aspx/1?Unobtrusive+validation+not+working+on+form+loaded+by+Ajax
Related
My project was rebuilt into folders called "area", everything worked before and the user was authorized to the account management panel. After adding these areas, the project cannot see where it should go.
My structure project:
Structure in Area "Authorize":
I tried to work with a route for areas in Startup.cs:
...
services.AddMvc( options =>
options.EnableEndpointRouting = false)
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
...
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapAreaRoute(
name: "MyAreaAuthorize",
areaName: "Authorize",
template: "Authorize/{controller=Account}/{action=Index}/{id?}");
routes.MapAreaRoute(
name: "MyAreaManage",
areaName: "Authorize",
template: "Authorize/{controller=Manage}/{action=Index}/{id?}");
routes.MapAreaRoute(
name: "MyAreaAdminAccount",
areaName: "AdminAccount",
template: "AdminAccount/{controller=Admin}/{action=Index}/{id?}");
});
I also copied _ViewImports.cshtml to folders with views for each area.
My file looks like this:
#using Example
#using Example.Models
#using Example.AccountArea.Models
#using Microsoft.AspNetCore.Identity
#addTagHelper Example.TagHelpers.*, Example
#addTagHelper Identity.TagHelpers.*, Identity
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
View in Area "Authorize":
#using Example.AccountArea.Models;
#using Microsoft.AspNetCore.Identity;
#model Example.AccountArea.Models.AccountModel.LoginModel;
#inject SignInManager<UserApp> Sign
#{
ViewData["Title"] = "Zaloguj się";
}
<form asp-area="Authorize" asp-controller="Account" asp-action="Login" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div>
<input asp-for="Email" placeholder="Email" />
<span asp-validation-for="Email" class="text-danger margin-text-form"></span>
</div>
<div>
<input asp-for="Password" placeholder="Hasło" />
<span asp-validation-for="Password" class="text-danger margin-text-form"></span>
</div>
<div class="group">
<div class="checkbox">
<input type='checkbox' id='my-checkbox'>
<label for='my-checkbox'>#Html.DisplayNameFor(m => m.RememberMe)</label>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn-dark">Login</button>
</div>
<div class="group">
<p>
<a asp-area="Authorize" asp-controller="Account" asp-action="ForgotPassword">Forgot?</a>
</p>
<p>
<a asp-controller="Account" asp-action="Register">Register</a>
</p>
</div>
</form>
</section>
</div>
#section Scripts {
<partial name="_ValidationScriptsPartial" />
}
Controller Account in Area "Authorize:
The controller has included info for the class that it belongs to the "Authorize" area
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Authentication;
using System;
using Example.AccountArea.Models;
using Example.AccountArea.Models.AccountModel;
namespace Example.AccountArea.Controllers
{
[Area("Authorize")]
public class AccountController : Controller
{
...My code is irrelevant to the problem...
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> Login()
{
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginModel login)
{
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(login.Email, login.Password, login.RememberMe, false);
if (result.Succeeded)
{
_logger.LogInformation("...");
return RedirectToAction(nameof(ManageController.Index), "Manage");
}
if (result.IsLockedOut)
{
_logger.LogWarning("...");
return RedirectToAction(nameof(LockoutOptions));
}
else
{
ModelState.AddModelError(string.Empty, "...");
return View("../Home/Index");
}
}
// If we got this far, something failed, redisplay form
return View("../Home/Index", login);
}
...My code is irrelevant to the problem...
}
}
After starting the application, the login form is displayed to me, the links do not work, the message is similar to the one below, it does not pass data validation and after clicking "Log in" it displays:
Physical transition of pages on the browser:
From login:
To:
Please do not inform me that it is copied from and there are similar solutions because I tried to find solutions in other similar posts first!
Any ideas ?
Thank you if you help me..
You do have two Area routes for your Authorize with different default controllers... I believe you should only have one. Not sure if that's the cause of the issue though. But I think that would likely conflict, it also looks unnecessary because any controllers in that area will be included by default with the single route.
My aspnet core 2.2 app area registration looks like this:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "Admin",
template: "{area:exists}/{controller=Admin}/{action=Index}/{id?}");
...
Hi i have just started MVC 4 in c#, i am having issue in rendering partial view.
i have created model for the partial view and controller action in which i am just
sending a single string for the testing reasons but when i try to render it.
it just show the following error.
[NullReferenceException: Object reference not set to an instance of an object.]
here is my controller class.
enter code here
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using my_photos.Models;
namespace my_photos.Controllers
{
public class DefaultController : Controller
{
public ActionResult Index()
{
ViewBag.Massage = "Hello Word";
return View();
}
public ActionResult About() {
ViewBag.Message = "About Page";
return View();
}
public ActionResult _RightView() {
var model = new my_photos.Models.partial(){
Winner = "Shafee Jan"
};
//ViewData["name"] = model;
return View(model);
}
}
here is model class for partial view
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace my_photos.Models
{
public class partial
{
public string Winner { get; set; }
}
}
here my partial view
#model my_photos.Models.partial
<div class="body">
<div class="content">
<div class="header">
<h1 class="nav-heading">Data</h1>
<p class="paragraph" > Winner :#Model.Winner.ToString() </p>
</div>
</div>
<div class="bottom">
<div class="header">
</div>
</div>
</div>
and here is my main layout in shared folder
#model my_photos.Models.partial
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>_Layout</title>
<link href="#Url.Content("~/Content/Style/Site.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/Style/Side_barnav.css")" rel="stylesheet" type="text/css" />
</head>
<body>
<header>
<h3> Photos app</h3>
<p> In this app my major concerns are with the <strong>theaming</strong>!</p>
<div class="nav">
<ul class="main-menu">
<li>#Html.ActionLink("Home","Index", "Default")</li>
<li>#Html.ActionLink("About","About", "Default")</li>
<li>#Html.ActionLink("Contact","Contact", "Default")</li>
</ul>
</div>
</header>
<section>
#RenderBody()
#Html.Partial("~/Views/Shared/_partial.cshtml")
</section>
<footer>
<div class="fotter-menu">
<ul>
<li>#Html.ActionLink("Home","Index","Default")</li>
<li>#Html.ActionLink("About","About","Default")</li>
<li>#Html.ActionLink("Contact","Contact","Default")</li>
</ul>
<ul>
<li>#Html.ActionLink("Resources","Resources","Default")</li>
<li>#Html.ActionLink("Testimonial","Testimonial","Default")</li>
<li>#Html.ActionLink("Team","Team","Default")</li>
</ul>
<ul>
<li>#Html.ActionLink("Home","Index","Default")</li>
<li>#Html.ActionLink("Home","Index","Default")</li>
<li>#Html.ActionLink("Home","Index","Default")</li>
</ul>
</div>
</footer>
</body>
</html>
when ever i try to get value form the model it give me the following error.
kindly help me through this.
[NullReferenceException: Object reference not set to an instance of an object.]
This is happening because your model is null, as you can see, in actions About and Index there is no model being passed. Also partial is a keyword in C#, it will be better to have a more signifiant name.
To solve this you have to pass a model to every view that uses that layout that is expecting this model. In your case is null and an error is thrown.
public ActionResult Index()
{
ViewBag.Massage = "Hello Word";
var model = new my_photos.Models.partial(){
Winner = "Shafee Jan"
};
return View(model);
}
It is necesary to pass the model because on the below line of code the partial is rendered by default with the current view model.
#Html.Partial("_partial.cshtml", Model) #* Model is passed by default if there is no other parameter specified *#
I think what you really want to do is to call the _RightView action in your layout.
#Html.Action("_RightView", "Default")
Don't forget to modify the action to return a partial view and the passing of model in the other actions won't be necessary
public ActionResult _RightView() {
var model = new my_photos.Models.partial(){
Winner = "Shafee Jan"
};
//ViewData["name"] = model;
return PartialView("_partial", model);
}
hey this is not a big problem you are giving partial class reference to both layout and partial view.
so if you are access a _RightView Action it does't thrown a error because you are passing a object to view properly but when comes it partial view you are not passing object reference so just pass the model in
#Html.Partial("~/Views/Shared/_partial.cshtml",Model)
That's it
I am changing a create form to become a modal dialog and jquery Unobtrusive validation stops working and don't know how to fix it.
Index.cshtml has a link to trigger a modal dialog.
Create
#section scripts{
<script type="text/javascript">
$('#createCustomer').on('click', function () {
$.get('/Customer/Create', function (data) {
$('#modalContainer').html(data);
$('#myModal').modal({});
});
});
Create.cshtml is a partial view.
#model Demo.Web.Models.CustomerVm
#using (Html.BeginForm("Create", "Customer", FormMethod.Post, new { #id="createForm" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Customer</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
On the controller there is an actionmethod which returns a partial view for create form.
public ActionResult Create()
{
return PartialView("Create");
}
view modal
public class CustomerVm
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
before i changed it to be a modal dialog .. everything was working but now i don't know how to fix it. How can i make validation work with dialog? Obviously, I don't want to rewrite validation rules on client script .. i want to get it working from view model .. thanks.
Because the form is not added to the page when the page loads, the unobtrusive validation will not pick it up. There are two ways to fix this.
Include the form on the page during the initial load. This will cause the form to be recognized and validation will occur. You can throw the partial view in a hidden div. Then your JavaScript will just show the modal dialog.
Manually register the form with the unobtrusive validation after adding it to the page. Something like $.validator.unobtrusive.parse("#id-of-the-form");
If you are loading the dialog dynamically just register the unobtrusive validation in the containing element's change event:
$('#modal-container').change(
function() {
$.validator.unobtrusive.parse("#your-form-id");
});
In partialview of create page -> modal-header, model-body, modal-footer and javascript code in the <script>your code </script> - don't put <script>your code</script> in #section Scripts{} and it will work.
Just add the following scripts in your Create form view:
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")"
type="text/javascript">
</script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"
type="text/javascript">
</script>
Adding a new comment to share a more modern solution:
Use BundleConfig.cs in the App_Start folder of your MVC project.
namespace MySolution
{
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/Site.min.css",
"~/Content/bootstrap.min.css"));
bundles.Add(new ScriptBundle("~/Scripts/js").Include(
"~/Scripts/jquery-3.3.1.min.js",
"~/Scripts/jquery.validate.min.js",
"~/Scripts/jquery.validate.unobtrusive.min.js"));
}
}
}
I need to display the registration form and login form on the home page.
If validation fails on these two forms, I need to display proper errors on the home page.
But if there was no error, the user must be redirected to the secured Dashboard.
To accomplish this, I am using child action on the home page like this:
#Html.Action("Register", "Membership")
It work perfectly as expected if there are any errors, as it is able to re-render the partial view with the proper model that has validation state information.
But if there was no error, when it tries to redirect, it throws an error stating that:
Child actions are not allowed to perform redirect actions.
Is there any way around this? I am sure there is a way to put registration and login forms on the homepage. Most probably I don't know since I am quite new to ASP .Net MVC.
Could you point me in the right direction here?
One way to do this is to use ajax forms for the login and registration bits and, instead of returning a RedirectResult when the submission is valid, return some json which a bit of client-side script will watch out for and use to do a redirect for you.
Here's a simplified example.
Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
using MvcApplication12.Models;
namespace MvcApplication12.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Register()
{
return PartialView(new UserDetails());
}
[HttpPost]
public ActionResult Register(UserDetails details)
{
if (ModelState.IsValid)
{
return Json(new {redirect = true, url = Url.Action("Index","Dashboard")});
}
else
{
return PartialView(details);
}
}
}
}
Home page 'Index' view:
#{
ViewBag.Title = "Index";
}
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script type="text/javascript">
function checkForRedirect(data)
{
if (data.redirect && data.url)
{
location.href = data.url;
}
}
</script>
<p>Home page stuff.....</p>
<div id="RegistrationArea">
#Html.Action("Register")
</div>
<p> Home page stuff.....</p>
Registration form 'Register' partial view:
#model MvcApplication12.Models.UserDetails
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Ajax.BeginForm(new AjaxOptions()
{
HttpMethod = "POST",
Url = Url.Action("Register", "Home"),
OnSuccess = "checkForRedirect(data)",
UpdateTargetId = "RegistrationArea",
InsertionMode = InsertionMode.Replace
}))
{
#Html.LabelFor(m => m.UserName)
#Html.EditorFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
#Html.LabelFor(m => m.Password)
#Html.EditorFor(m => m.Password)
#Html.ValidationMessageFor(m => m.Password)
<input type="submit" />
}
You should not use the child actions in that context.
A solution to your problem could be to
place two forms in your page one for registration and one for login. The registration form posts to a Register action in a Membership controller, the login action posts to a Login action in the Membership controller.
In case an error occurs in one of the actions you can:
Show a dedicated Login/Registration page and use model/validation results to show error messages
Redirect to the URL/Action the user was coming from and show an error message you place in TempData
Without using javascript for redirect:
If you put forms inside your child views,Sometimes if you specify action name and controller name in Beginform helper(inside child view), this problem doesn't happen. for example I changed my child action view like this :
Before :
#using (Html.BeginForm())
{
...
}
After :
#using (Html.BeginForm("InsertComment", "Comments", FormMethod.Post, new { id = "commentform" }))
{
...
}
Now, You can put RedirectAction command inside "InsertComment" action and everything will work.
Two form in one page management:
1.Specify name for Submit button (Each form) (Ex: "submitvalue")
form1:
<input type="submit" value="login" name="submitValue" class="btn btn-success pull-right" />
form2:
<input type="submit" value="register" name="submitValue" class="btn btn-success pull-right" />
2.Make two action for these forms. (Ex: "Register" and "Login")
[HttpPost]
public ActionResult Login(LoginVM model, string submitValue)
{
if (submitValue == "login")
{
//Do Something
}
...
}
[HttpPost]
public ActionResult Register(RegisterVM model, string submitValue)
{
if (submitValue == "register")
{
//Do Something
}
...
}
If you click on register or login button in forms, both of actions are called but with "if" statement we determine whichone is our target.
I am beginner in asp.net mvc . I am going to connect an action of button in view.
but i cant. i work with web form, in fact i want to click on the button, create action will be called and insert the data.
my code is as following:
The Controller:
namespace BookStore.Controllers
{
public class BookController : Controller
{
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(book bookobj)
{
var dBook=new DBook();
dBook.Insertbook(bookobj);
return RedirectToAction("Index", "Home");
}
}
}
The View:
#model BookStore.Models.DomainObject.book
#{
ViewBag.Title = "Create";
}
<h2>insert data/h2>
#using(Html.BeginForm())
{
#Html.ValidationSummary(true);
<fieldset>
<div>
#Html.LabelFor(model=> model.book_name)
</div>
<div>
#Html.EditorFor(model => model.book_name)
</div>
<div>
#Html.LabelFor(model=>model.book_qty)
</div>
<div>
#Html.EditorFor(model=>model.book_qty)
</div>
<br/>
<div>
<input id="Button_craete_book" type="button" value="insert" />
</div>
</fieldset>
}
Change the button type to "submit":
<input id="Button_craete_book" type="submit" value="insert" />
That will post the form and values to the Edit method in the controller, as marked with the HttpPost attribute.