Validation in Partial View not working in MVC 4 - asp.net-mvc

I have a #Html.ValidationMessageFor(model => model.FirstName) in Partial view that is not functioning properly. The text box's contained within the loaded Partial View have the "Required" Data Annotation on them and the associated message displays right away. How can I avoid this? It doesn't even validate.
Partial View Code
#{ Html.EnableClientValidation(); }
#*#{ ViewContext.FormContext = new FormContext(); }*#
#using (Html.BeginForm("ActionName", "ControllerName"))
{
<div>
#Html.TextBoxFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
....//some more HTML
}
Main View Code
<div class="modal" id="modalId" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
</div>
<div class="modal-body" id="modalbodyId">
#Html.Partial("PartilViewName")
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div>
I have tried the following things so far.
1. Added the following line of code in Partial View
#{ ViewContext.FormContext = new FormContext(); }
2.Both ClientValidationEnabled and UnobtrusiveJavaScriptEnabled are set to true in web.config
3.Added the following script tags in BundleConfig.cs
<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>
In all the posts that I have seen I need to use an AJAX call like the below code.
However I am not sure on how to use it.
$("#create").click(function () {
var form = $("#create_person").closest("form");
form.removeData('validator');
form.removeData('unobtrusiveValidation');
$.validator.unobtrusive.parse(form);
$.ajax({
url: "/Person/CreateOrUpdate",
type: "POST",
data: $("#create_person").serialize(),
cache: false
});
});
Code Courtsey

Try adding the model you use for your partial view as a property in the model of the view the partial is created in.
public class MainViewModel
{
// properties
public PartialViewModel PartialVm { get; set; }
}
Then when you render your partial, pass it the PartialViewModel property.
#Html.Partial("PartialViewName", Model.PartialVm)

Related

View call to another view in MVC

I have created a popup view(EmployeeRegistration.cshtml) using Bootstrap for registration and its Action method. But I want to get this popup view from another view(EmployeeList.cshtml). Can I do it? If yes then How? Any code please.
//EmployeeList.cshtml
#Html.ActionLink("Create New", "Registration", "Registration", new
{
#class = "openDialog",
data_dialog_id = "aboutDialog",
data_dialog_title = "Create Employee"
})
<div id="gridposition" style="width: 100%;">
#{
#grid1.GetHtml(mode: WebGridPagerModes.All,
//code to display employee list on grid
}
</div>
Below is Registration.cshtml
#using (Html.BeginForm())
{
<div class="modal fade mymodal" id="openDialogDiv">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
//code here to pop up
</div>
</div>
</div>
I want to show popup on click of ActionList as shown above
Create a a div in your EmployeeList.cshtml to hold the html returned from Registration.cshtml
<div id="result"></div>
Make your Registration.cshtml as a partial view.
Use this anchor tag.
Create New
Make an ajax request to get the popup content and onsuccess, populate the div with the returned html and open the modal popup.
<script>
function funName()
{
$.ajax({
url: 'yoururl',
type: 'GET',
dataType: 'html',
success: function(data) {
$('#info').html(data);
$('#mymodal').modal('show');
},
error: function() {}
});
}
I think There are two options :
1. Forget about Registration.cshtml and put the below code in EmployeeList.cshtml:
<button type="button" class="openDialog">Create New</button>
<form class="modal fade mymodal" id="openDialogDiv" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
//code here to pop up
</div>
</div>
</div>
</form>
then show the form using jquery:
$('.openDialog').click(function(){
$('#openDialogDiv').modal();
});
2.create new action method in your controller which returns EmployeeRegistration.cshtml as partial view, let me name it DisplayRegistration() , now you can use ajax call, to DisplayRegistration() and display EmployeeRegistration.cshtml.
Please note that I changed Html.ActionLink to <button> tag

Partial view doesn't load inside current view

So I have this partial view:
#model QueryQuestionManager.Models.Domain.Answer
<script src="~/Scripts/DynamicList.js"></script>
<div class="editorRow">
#using (Html.BeginCollectionItem("Answers"))
{
<div>
#Html.LabelFor(x => x.AnswerText)
#Html.EditorFor(x => x.AnswerText)
</div>
delete
}
</div>
I want to load this partial view in my main view when someone clicks the link:
#model QueryQuestionManager.Models.Domain.Question
#{
ViewBag.Title = "Create";
}
<script src="~/Scripts/DynamicList.js"></script>
<br />
#using (Html.BeginForm(new { #class = "form", role = "form" }))
{
<div class="form-group">
<div class="editor-label">
#Html.LabelFor(m => m.QuestionText)
</div>
<div class="form-control">
#Html.TextBoxFor(m => m.QuestionText)
#Html.ValidationMessageFor(m => m.QuestionText)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.Category)
</div>
<div class="form-control">
#Html.TextBoxFor(m => m.Category)
#Html.ValidationMessageFor(m => m.Category)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.Answers)
</div>
<br />
<div id="editorRows">
#foreach (var item in Model.Answers)
{
#Html.Partial("EditorRow", item);
}
</div>
#Html.ActionLink("Add another...", "BlankEditorRow", "Question", new { id = "addItem" })
<br />
<input type="submit" value="Save" class="btn btn-success" />
</div>
}
<br />
<div>
#Html.ActionLink("Back to List", "Index", "Home")
</div>
This is the action result from the controller
public ActionResult BlankEditorRow()
{
return PartialView("EditorRow", new Answer());
}
And then I have a javascript file for the dynamic adding and deleting partial views.
$('#addItem').click(function () {
$.ajax({
url: this.href,
cache: false,
success: function (html) {
$('#editorRows').append(html);
}
});
return false;
});
$('a.deleteRow').live('click', function () {
$(this).parents('div.editorRow:first').remove();
return false;
});
But for some reason my partial view doesn't load inside my current view and it opens only the partial view.
Am I forgetting something?
I'm thinking you don't want that action link. I believe your jQuery click handler has the correct approach, but your action link is linking to your new URL (Question/BlankEditorRow) and you don't want that. Rather you just need to fetch this html, and insert it as you do, but WITHOUT navigating the main page to that URL.
Instead of the ActionLink, use an anchor tag and a hidden field.
<a id="addItem" href="#" />
<input type="hidden" id="partialViewAction" value="#Url.Action("BlankEditorRow","ControllerName")"
Now in your ajax call, instead of using the href property of the anchor, use the value of the hidden field.
url: $('#partialViewAction').val()

Ajax missunderstanding, or an error?

Can you please explain me how should i use Ajax properly.
I have an easy example in Asp.Net MVC:
This is my layout view
<html>
<head>
//scripts
</head>
<body>
<div id="header">
<div class="logo">
<img id="LogoImg" src="http://www.ruralcomshow.com/wpontent/uploads/2014/06/Midwest-Data-Center-Logo-175x75.png" />
</div>
</div>
<div class="wrapper">
<div class="left-side">
//some navigation
</div>
<div id="right-side">
#RenderBody()
</div>
</div>
<div id="footer">
<div class="clearfix">
//some footer
</div>
</div>
</body>
</html>
This is my controller:
public class HomeController : Controller
{
public PartialViewResult Ajax()
{
return PartialView();
}
public ActionResult Index()
{
return View();
}
}
This is Ajax partial view:
<h2>This is how it's done</h2>
#Html.ActionLink("back :C","Index","Home")
This is Index view:
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#Ajax.ActionLink("Go, go Ajax!", "Ajax", "Home", new AjaxOptions { UpdateTargetId = "right-side", InsertionMode = InsertionMode.Replace})
So, as I understood when i click Ajax ActionLink my whole page should not rerender, and the only thing that should change is div with id "right-side"? So the problem is that the whole page always gets rerendered.
Am I doing something wrong? Or is this a problem of my understanding?
Include jquery and unobtrusive-ajax at the bottom of the page as shown :-
</footer>
#Scripts.Render("~/bundles/jquery")
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
#RenderSection("scripts", required: false)
</body>
</html>

Ajax.BeginForm not working with Html.ValidationSummary

I am trying to use the Ajax.BeginForm to post data to a controller. In the case of specific errors, the form should re-render and display the custom error message that was added to the ModelState. For some reason, the error message is not displaying. I am even trying the following test case which is not working, am I missing something?
Edit.cshtml:
#using (Ajax.BeginForm("Edit", "UserInformation", FormMethod.Post, new AjaxOptions { HttpMethod = "Post", InsertionMode = InsertionMode.Replace, UpdateTargetId = "divFormContainerMain", LoadingElementId = "divPreLoader", OnSuccess = "onSuccess" }))
{
<div id="divPreLoader" style="display:none; text-align: center"><img src="#Url.Content("~/Content/images/preLoader.gif")" alt="" /></div>
<div id="divFormContainerMain">
#Html.Partial("_EditPartialView", Model)
</div>
<div class="buttonContainerBottom">
<span class="buttonContainerInner">
<input type="submit" id="btnSave" name="buttonPress" value="save" class="orangeButton" />
</span>
</div>
}
_EditPartialView.cshtml:
#Html.ValidationSummary(false)
<div id="divFormContainerUserInformation" class="formContainer">
<div class="labelContainer">
#Html.LabelFor(m => m.UserName)
</div>
<div class="elementContainer">
#Html.TextBoxFor(m => m.UserName, new { style = "width: 200px" })
#Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="labelContainer">
#Html.LabelFor(m => m.Name)
</div>
<div class="elementContainer">
#Html.TextBoxFor(m => m.Name, new { style = "width: 200px" })
#Html.ValidationMessageFor(m => m.Name)
</div>
<div class="labelContainer">
#Html.LabelFor(m => m.EmailAddress)
</div>
<div class="elementContainer">
#Html.TextBoxFor(m => m.EmailAddress, new { style = "width: 200px" })
#Html.ValidationMessageFor(m => m.EmailAddress)
</div>
.
.
.
.
.
.
</div>
UserController:
[HttpPost]
public ActionResult Edit(UserModel userModel)
{
ModelState.AddModelError("", "This is a test");
return PartialView("_EditPartialView", userModel);
}
Where are your scripts added? In the _layout.cshtml or in the view itself? How are you loading the view? Is it with an ajax request to show a partial view?
If you are loading the partial view through ajax or as a partial view, maybe it could be that the partial view was not yet loaded in the jquery DOM model tree.
I would try the following. Change
<div id="divFormContainerMain">
#Html.Partial("_EditPartialView", Model)
</div>
to
<div id="divFormContainerMain">
#Html.Partial("_EditPartialView", Model)
<script src="/Scripts/jquery.validate.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>
</div>
or
<div id="divFormContainerMain">
#Html.Partial("_EditPartialView", Model)
#Scripts.Render("~/bundles/jqueryval") //if you have a bundle for it
</div>
My advice is anyway to load the validate and unobtrusive scripts only when you need them and not in the _layout.cshtml page.
Also don't forget to enable the following appSettings in the web.config
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
Make sure that you have included the jquery.unobtrusive-ajax.js script to your view after jquery itself. Otherwise the Ajax.BeginForm helper won't do what you think it does:
<script type="text/javascript" src="#Url.Content("~/scripts/jquery-YOUR-VERSION.js")"></script>
<script type="text/javascript" src="#Url.Content("~/scripts/jquery.unobtrusive-ajax.js")"></script>

How do I share (model) data with the layout view and partials in the layout?

I have a partial view(strongly typed)a1 defined within my Master Layout view(A). I then have a sub view(B) who itself is a layout view but nested within the Master Layout view. Then I have a page view from which is invoked and loaded with model data. How do I pass data within this data up to the Partial view nested in the Master Layout view please?
Shared/_Layout.cshtml (Master Layout)
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<header>
#RenderPage("~/Views/Shared/PartialViews/Shared/_headerView.cshtml")
</header>
</body>
</html>
Shared/_Layout.cshtml (SubLayout)
#{
ViewBag.Title = "Blog";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#if (IsSectionDefined("BlogHeaderContent"))
{
<div class="blogHeader">
#RenderSection("BlogHeaderContent", required: false)
</div>
}
#RenderBody()
Views/Blogs/blogindex.cshtml (Blog View)
#model MyModels.Blog
#{
ViewBag.Title = " See Blog";
}
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Blog</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Body)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Body)
#Html.ValidationMessageFor(model => model.Body)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Couple of options:
First, I feel it's kinda of hacky, but you could populate a property the ViewData/ViewBag. It's hacky (in my opinion) because it's not strongly typed, you don't know what object would be put in there.
Secondly, still a little hacky, you could have your layout and partial have a (strongly?) typed model of Object. They attempt to check and see if it has the data you are looking for (via reflection or an interface).
Thirdly, less hacky but really restrictive, you can create an interface that all your view models have to derive from, then your Layout and Layout Partial can use that for a Model. The problem becomes any other developer who doesn't know that your view models need to derive from a specific interface will blow up the app.
Last, probably the best solution, (assuming that your layout-partial doesn't care what is executing), create a controller with an ChildOnly attribute (Any method that is marked with ChildActionOnlyAttribute can be called only with the Action or RenderAction HTML extension methods.). This is the best because it implements the Separation of concerns. The Sublayout doesn't care what view is executing and the view knows nothing about whats happening in the layout.
public class LayoutController
{
[ChildOnly]
public ActionResult SubLayout()
{
// Get Some Model Data
var SubLayoutViewModel model = new SubLayoutViewModel();
return this.View(model)
}
}
Layout.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<header>
#Html.RenderAction("Layout", "SubLayout")
</header>
</body>
</html>
SubLayout.cshtml
#model SubLayoutViewModel
#Model.SomeData.ToString() // or whatever
#if (IsSectionDefined("BlogHeaderContent"))
{
<div class="blogHeader">
#RenderSection("BlogHeaderContent", required: false)
</div>
}
#RenderBody()
Copy the data from your strongly-typed model to the ViewBag similarly to how the title is being set in the ViewBag in your view:
ViewBag.Title = "See Blog";
You can put other data in there, then access it later in your layout and partial views.

Resources