Jquery Accordion Validation Not working when rendering Partial View through $.ajax call - validation

Hi friends,I am working on MVC 4 Razor and I am stuck in a situation
where Employee Personal Details form is to be filled in
steps(wizard)..for which i used jquery accordion control..for every
step i put an accordion..The html in each accordion section is
rendered from partial view through ajax call on every click of
respective accordion (i.e. <h3></h3> tag)..
On page load first/top accordion is active by default. My problem is
to restrict the user to click on next accordion until he/she fills the
presently active accordion correctly..
Here is my full code:
View:
#model XXX.ViewModels.PersonalDetailsViewModel
#{
ViewBag.Title = "PersonalDetails";
Layout = "~/Views/Shared/Template.cshtml";
}
#using (Html.BeginForm("Lifestyle", "Apply", FormMethod.Post, new { id = "personalDetailForm" }))
{
<div class="centerdiv margin_top20">
<div class="row">
#Html.ValidationSummary(true, "Please Correct the following errors:")
</div>
<div style="width: 1000px;">
<div id="Personalaccordion" class="acordion_div" style="padding: 10px; float: left;">
<h3 class="acordion_div_h3" onclick="javascript:PersonalModule.GetRenderingView('Apply/GetBasicDetailsView','personalDetailForm','BasicDetailsDiv');">
<p>
Basic Details<span id="BasicDetailsDivExp"></span>
</p>
</h3>
<div id="BasicDetailsDiv">
</div>
<h3 class="acordion_div_h3" onclick="javascript:PersonalModule.GetRenderingView('Apply/GetPersonalAddressView','personalDetailForm','PersonalAddressDiv');">
<p>
Address<span id="PersonalAddressDivExp"></span></p>
</h3>
<div id="PersonalAddressDiv">
</div>
</div>
<ul id="conlitue_ul" style="margin-top: 20px;">
<li style="margin-left: 140px;">
<input type="submit" class="compareBtn float_lt" value="Continue Buying >" id="continue" /></li>
</ul>
</div>
</div>
}
#Scripts.Render("~/bundles/PersonalDetails")
<script type="text/javascript">
PersonalModule.GetRenderingView('Apply/GetBasicDetailsView', '', 'BasicDetailsDiv');
</script>
My Controller:
public ActionResult PersonalDetails(int leadId)
{
var personalDetailsViewModel = LeadHelper.GetPersonalDetails(leadId);
return View(personalDetailsViewModel);
}
public ActionResult GetBasicDetailsView(PersonalDetailsViewModel personalDetailsViewModel)
{
if (personalDetailsViewModel.BasicDetails == null)
{
ModelInitializerHelper.InitilaizeBasicDetailsVModel(personalDetailsViewModel);
}
ModelInitializerHelper.InitializeBasicLookup(personalDetailsViewModel);
return PartialView("Personal/BasicDetails", personalDetailsViewModel);
}
public ActionResult GetPersonalAddressView(PersonalDetailsViewModel personalDetailsViewModel)
{
if (personalDetailsViewModel.PersonalAddressDetails == null)
{
ModelInitializerHelper.IntializePersonalAddressVModel(personalDetailsViewModel);
}
ModelInitializerHelper.InitializePersonalAddressLookup(personalDetailsViewModel);
return PartialView("Personal/PersonalAddress", personalDetailsViewModel);
}
My JS :
var PersonalModule = {
GetRenderingView: function (url, formId, containerID) {
var applicationurl = ApplicationRoot + '/' + url;
var objects = $('#BasicDetailsDivExp , #PersonalAddressDivExp' );
viewDivID = containerID;
GetAccordionView(applicationurl, formId, objects, containerID, 'accordion_plus', 'accordion_minus');
}
}
GetAccordionView: function (url, formId, objects, containerID, accordion_plus, accordion_minus) {
var formObjectData = null;
if (formId != undefined) {
formObjectData = $("#" + formId).serialize();
}
var renderView = function (data) {
$('#' + containerID).innerHtml = data;
}
ExpandAccordion(objects, containerID, accordion_plus, accordion_minus);
DoServerRequest(url, formObjectData, renderView);
}
ExpandAccordion: function (objects, spanIconID, accordion_plus, accordion_minus) {
var Objects = objects;
Objects.removeClass(accordion_minus);
Objects.addClass(accordion_plus);
$('#' + spanIconID + 'Exp').removeClass(accordion_plus).addClass(accordion_minus);
if (Browser.ie7) {
Objects.css("margin-top", "-22px");
}
}
DoServerRequest: function (url, data, funSuccess) {
$.ajax({
type: "POST",
url: url,
data: data,
async: false,
dataType: "json",
success: funSuccess,
error: function (errorResponse) {
if (errorResponse.readyState == 4 && errorResponse.status == 200) {
renderCurrentView(errorResponse.responseText)
}
else {
alert(errorResponse.responseText);
}
}
});
}
Please somebody help..I have heard lots of good thing about this forum
and this is my first Question...Thanks in advance..
I have removed my jquery validation attempt as it made the code
garbage thing Now I dont know what to write and where to write

If you are trying to validate data that has been added to form via Ajax after page load then you will need to use the rules method and add rules for these new elements. Jquery Validate has no way of knowing about them otherwise.
Example
Once you have loaded your new content via Ajax you need to find each element and add the necessary rules to them.
$('#yourDiv').find(".newElements").rules("add", {
required: true,
messages: {
required: "Bacon is required"
}
});
If you are using unobtrusive validate you may need to add your new elements to that also. See this SO question for more details.
Validating the Form
To check if the fields are valid, you will need to validate the form on click. This can be done using .validate(). You can then check if the form validated using .valid()
Example
$('#yourForm').validate();
if(!$('#yourForm').valid()) {
alert('Bacon is required');
}

Related

MVC Core ajax and return result is a view

MVC Core, NET 5, not razor pages.
On a view I have three select components (bootstrap-select). I populate them via ViewModel.
"Get request -> Controller -> return View(viewModel);"
What I want...
When I changed value in any select component I do a post request (ajax) to the same controller (other method) and return view with repopulated data.
"'Post request -> Controller -> return View(changedModel);"
As I understood when I did ajax request I should handle it result in success and other cases.
What I should to do to reload page with new data?
Is it possible to achive this with this approach?
Yes, this is possible and you do not need to reload the page, just append the returned html to wherever you want it.
$.ajax({
type: "POST",
url: {your_url},
dataType: "html",
success: function (html) {
$("#someDiv").html(html);
}
});
What I should to do to reload page with new data?
If the post action return the same view as the get action and you want to reload the whole page, I think there is no need to use ajax. You can just redirect to post action with a form submission. If the view returned by the post action is a partialview you want render to the current view, you can use it like that in #cwalvoort answer.
Based on advices of cwalvoort and mj1313
I did:
Render main page with partials. ViewModel transfered to a partial as a parameter
On main page I added eventListners to controls with JS.
When control changes - ajax request to backend happens Controller/GetPartialView
Result from ajax replace html in partial section
Programmatically show needed components, re-add eventListners
PS Really need to learn Blazor or UI Framework :)
Code samples:
// JS
document.addEventListener("DOMContentLoaded", function (event) {
BindSelectActions();
});
function BindSelectActions() {
$('#selectGroups').on('hidden.bs.select', DoPartialUpdate);
$('#selectCompanies').on('hidden.bs.select', DoPartialUpdate);
$('#selectPeriods').on('hidden.bs.select', DoPartialUpdate);
}
function DoPartialUpdate(e, clickedIndex, isSelected, previousValue) {
// ToDo: Implement common script with "CallBackend" function
$.ajax({
type: "POST",
url: 'https://localhost:44352/TestController/TestGetPartial',
// no data its a stub at the moment
// data: $('#form').serialize(),
success: function (data, textStatus) {
$("#testControls").html(data);
$('#selectGroups').selectpicker('show');
$('#selectCompanies').selectpicker('show');
$('#selectPeriods').selectpicker('show');
BindSelectActions();
}
});
}
// Controllers
[HttpGet]
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
public async Task<IActionResult> Main()
{
// ViewModel = _helper -> _mediator -> query -> context
return await Task.Run(() => View(new TestViewModel()));
}
[HttpPost]
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
public IActionResult TestGetPartial(TestViewModel model)
{
// ViewModel = _helper -> _mediator -> query -> context
var result = new TestViewModel();
result.IsPageReload = "yes";
result.TestCollection = new string[] { "A", "B", "C" };
result.Companies = new List<SelectListItem> { new SelectListItem { Value = "999",
Text = "Test" } };
// ModelState.Clear();
return PartialView("_TestPartial", result);
}
// Main and partial views
#model TestViewModel
#{
ViewData["Title"] = "Test";
}
<div id="testControls">
#await Html.PartialAsync("_TestPartial", Model)
</div>
#section Scripts {
<script type="text/javascript" src="~/js/test.js" asp-append-version="true">
</script>
}
#model TestViewModel
<form>
<div class="d-flex flex-row justify-content-between mt-4">
<div><select id="selectGroups" asp-for="Groups" asp-items="Model.Groups"
class="selectpicker" data-live-search="true" data-style="btn-outline-dark"
title="Group"></select></div>
<div><select id="selectCompanies" asp-for="Companies" asp-items="Model.Companies"
class="selectpicker" data-live-search="true" data-style="btn-outline-dark"
title="Company"></select></div>
<div><select id="selectPeriods" asp-for="Periods" asp-items="Model.Periods"
class="selectpicker" data-live-search="true" data-style="btn-outline-dark"
title="Period"></select></div>
<div><button type="button" class="btn btn-outline-dark">Import</button></div>
</div>
</form>
<div>
#{
if (null != Model.TestCollection)
{
foreach (var item in Model.TestCollection)
{
<p>#item</p>
<br>
}
}
}
</div>

nested partial View calling HttpPost method 2 times

I have seen this question being asked few times here , but solution I saw are not generic , they are related to their specific code ..
I need to rectify the Work done by previous developer , the flow of ajax calls are wrong in code
In my Situation I have views like :
1.Index (Main View)
2.ParentCategoryList (partial View inside Index)
3. AddChild (partial View inside ParentCategoryList )
4. childCategorytree (Seperate View )
Problem is that from 2nd nested View (AddChild ) , whhen i click on save button ,httpost method is calling twice
My Index View
<div>
<div class="content" id="divparent">
</div>
<div class="content" id="dvChild">
</div>
</div>
its script
#section scripts{
<script type="text/javascript">
$('document').ready(function () {
//------------
$.get('#Url.Action("ParentCategoryList", "List")', function (data) {
$("#divparent").html("");
$("#divparent").html(data);
});
})
function addnewchild(url) {
$.get(url, function (data) {
$("#dvChild").html("");
$("#dvChild").html(data);
});
}
</script>
}
First Partial View inside Index (ParentCategoryList.cshtml)
#foreach (Bmsa.UI.Models.ListsResultModel data in Model)
{
<tr> <td><a onclick="addnewchild('#Url.Action("AddChild",
"List", new { id = #data.listID })')" >
</a> </td></tr> } </tbody> </table>
2nd Nested Partial View inside ParentCategoryList
#using (Ajax.BeginForm("AddChild", "List", new AjaxOptions
{
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "dvChild"
}))
{
<div > <input type="submit" value="Save" /></p></div>}
and Controller methods
public ActionResult ParentCategoryList()
{
//Code
return PartialView("ParentCategoryList", categoryList); }
//GET Operation to Load this View
public ActionResult AddChild(int id)
{
ViewBag.ParentID = id;
ListsAddModel addchild = new ListsAddModel();
addchild.parentListId = id;
return PartialView("AddChild", addchild);
}
[HttpPost] (**this method is calling twice--this is the problem** )
public ActionResult AddChild(ListsAddModel model,int id)
{
//Code
return RedirectToAction ("ChildCategoryListTree", new { id = model.parentListId });
}
and childCategorytree Partial view (also blank one)
I am not able to prevent this method to called twice . I tried e.preventDefault() in $.ajax call , but it is not working ...
I have tried to minimise the code , I think the problem is in RedirectToAction , but I am not sure
Any Help would be appreciated

Returning ValidationSummary in Partial View to Ajax error handler - nothing else getting rendered

I'm calling a method from Ajax that updates a some content in the page by loading up a partial view & setting a contained property appropriately.
This all works ok but I'm having problems with server side validation using the ValidationSummary control. I'm using an approach suggested elsewhere to stick the ValidationSummary in a partial view. (I've actually got client side validation turned off & I'm trying to get server side validation to work using the same validation summary that client side validation uses)
When there is a validation error, ajax error handler should update the contents of a div with the partial view that is returned.
All this works ok in the sense that the validation summary is rendered with the expected error messages except for the fact that the nothing else is getting displayed on the page other than the partial view containing the validation summary and its containing elements. i.e. no siblings / of the div are getting rendered
I reaslly haven't got a clue what's going on. Intersetingly, if I comment out the line in the error handler that updates the div with the partial, I see the form in its entirety again.
I'm using an ExceptionFilter:
public class ValidationErrorAttribute : FilterAttribute, IExceptionFilter
{
public virtual void OnException(ExceptionContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (filterContext.Exception != null)
{
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
filterContext.HttpContext.Response.StatusCode =
(int)System.Net.HttpStatusCode.BadRequest;
//return the partial view containing the validationsummary and set the ViewData
//so that it displays the validation error messages
filterContext.Result = new PartialViewResult { ViewName = "validation",
ViewData = filterContext.Controller.ViewData };
}
}
}
when there's a validation error, throw a validationexception which will
trigger the OnException method of the filter
//Controller
[HttpPost]
[ValidationErrorAttribute]
public ActionResult Save(ConsumptionData consumptionData)
{
if (ModelState.IsValid)
{
var dto = Mapper.Map<ConsumptionData, ConsumptionDataDto>(consumptionData);
var refId = _personalProjectionRepository.AddPersonalProjectionRecord(dto);
consumptionData.ReferenceId = refId;
return PartialView("Reference", consumptionData);
}
else
{
throw new ValidationException();
}
}
The validation partial view:
#model PersonalProjection.Web.Models.ConsumptionData
#Html.ValidationSummary()
and the jquery:
$('form').submit(function () {
var form = $(this);
if (form.valid())
{
$.ajax({
url: form.attr("action"),
type: "POST",
dataType: "html",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({
SiteId: $('#siteid').val(),
ElectricityConsumption: $('#electricityconsumption').val(),
ElectricitySpend: $('#electricityspend').val(),
GasConsumption: $('#gasconsumption').val(),
GasSpend: $('#gasspend').val()
}),
success: function (result) {
$('#rightPanelSection').html(result);
},
error: function (jqXHR) {
$('#validationSummary').html(jqXHR.responseText);
}
});
}
return false;
});
and the index.cshtml markup
<div class="panel panel-outcome">
#using (Html.BeginForm("Save", "Home", FormMethod.Post, (object)new { ID =
"projectionForm" }))
{
<div id="validationSummary"/>
<div id="topPanelSection" class="panel-section">
#Html.LabelFor(m => m.SiteId, new { id = "siteidlabel" })
#Html.TextBoxFor(m => m.SiteId, ViewBag.TextBoxDisabled ? (object)new { id =
"siteid", disabled = true, maxlength = 9, #class = "input-disabled", #Value =
ViewBag.SiteId } : new { id = "siteid", maxlength = 9 })
<span id="errorText" class="error-text" />
</div>
<div id="leftPanelSection" class="panel-section">
<div class="column-heading">
<span class="column-heading-left">Total Cost</span>
<span class="column-heading-right">Total Consumption</span>
</div>
<div class="panel-section-row">
#Html.LabelFor(m => m.ElectricitySpend, new { id = "electricitylabel" })
<span>£</span>
#Html.TextBoxFor(m => m.ElectricitySpend, new { #class = "textbox-right-
margin", id = "electricityspend" })
#Html.TextBoxFor(m => m.ElectricityConsumption, new { #class = "textbox-
left-margin", id = "electricityconsumption" })
<span>kWhs</span>
</div>
<div class="panel-section-row">
#Html.LabelFor(m => m.GasSpend, new { id = "gaslabel" })
<span>£</span>
#Html.TextBoxFor(m => m.GasSpend, new { #class = "textbox-right-margin", id =
"gasspend" })
#Html.TextBoxFor(m => m.GasConsumption, new { #class = "textbox-left-margin",
id = "gasconsumption" })
<span>kWhs</span>
</div>
<div class="panel-section-row">
<button type="reset" id="resetbutton">Reset Form</button>
<button type="submit">Generate Reference Id</button>
</div>
</div>
<div id="rightPanelSection" class="panel-section">
#Html.Partial("Reference", Model)
</div>
}
I'm fairly new to Ajax so this is probably a schoolboy error but here goes:
It's because when I use this jquery
$('#validationSummary').html(jqXHR.responseText);
To update this
<div id="validationSummary"/>
it doesn't like the closing tag & it messes up
Change to this
<div id="validationSummary">
</div>
And it works ok.

Ajax form submission with Valums plugins in asp.net mvc 3

I have used Valums uploader plugins for file uploads in asp.net mvc 3. Following is the views which have form fields and ajax query upload button inside form. I am not sure that I am doing it right or not. What I have to change on view so that When I Choose the file to upload the form field's value is also send.
Views:
<link href="#Url.Content("~/Content/css/fileuploader.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Content/js/fileuploader.js")" type="text/javascript"></script>
#using (Html.BeginForm("Upload","AjaxUpload")) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Upload Image File</legend>
<div class="editor-label">
#Html.Label("Select Language")
</div>
<div>
#Html.DropDownList("Language1", (SelectList) ViewBag.lang)
</div>
<div class="editor-label">
#Html.Label("Select Category")
</div>
<div>
#Html.DropDownList("ParentCategoryID", ViewBag.ParentCategoryID as SelectList)
</div>
<div id="file-uploader">
<noscript>
<p>
Please enable JavaScript to use file uploader.</p>
</noscript>
</div>
</fieldset>
}
**<script type="text/javascript">
var uploader = new qq.FileUploader
({
element: document.getElementById('file-uploader'),
action: '#Url.Action("upload")', // put here a path to your page to handle uploading
allowedExtensions: ['jpg', 'jpeg', 'png', 'gif'], // user this if you want to upload only pictures
sizeLimit: 4000000, // max size, about 4MB
minSizeLimit: 0 // min size
});
</script>**
How Can I passed the value of form to controller of HTTPOST Action So that I can save data to the database. Here, I have Upload action which save the data in database but I don't know to retrieve to those value send by form post.
HttpPost Action
[HttpPost]
public ActionResult Upload(HttpPostedFileBase qqfile)
{
var wav = new PlayWav
{
Name = ***filename***,
CategoryID = ***value from category dropdown select list***,
UserID = repository.GetUserID(HttpContext.User.Identity.Name),
LanguageID = int.Parse(***value from language dropdown select list***),
UploadDateTime = DateTime.Now,
ActiveDateTime = DateTime.Now,
FilePath = "n/a"
};
if (qqfile != null)
{
// this works for IE
var filename = Path.Combine(Server.MapPath("~/App_Data/Uploads"), Path.GetFileName(qqfile.FileName));
qqfile.SaveAs(filename);
return Json(new { success = true }, "text/html");
}
else
{
// this works for Firefox, Chrome
var filename = Request["qqfile"];
if (!string.IsNullOrEmpty(filename))
{
filename = Path.Combine(Server.MapPath("~/App_Data/Uploads"), Path.GetFileName(filename));
using (var output = System.IO.File.Create(filename))
{
Request.InputStream.CopyTo(output);
}
**db.PlayWavs.Attach(wav);
db.SaveChanges();**
return Json(new { success = true });
}
}
return Json(new { success = false });
}
Didn't you read the documentation? There's a whole section entitled Sending additional params. Even an example is given:
var uploader = new qq.FileUploader({
element: document.getElementById('file-uploader'),
action: '/server-side.upload',
// additional data to send, name-value pairs
params: {
param1: 'value1',
param2: 'value2'
}
});

How to update DIV in _Layout.cshtml with message after Ajax form is submitted?

Currently I have a Razor View like this:
TotalPaymentsByMonthYear.cshtml
#model MyApp.Web.ViewModels.MyViewModel
#using (#Ajax.BeginForm("TotalPaymentsByMonthYear",
new { reportName = "CreateTotalPaymentsByMonthYearChart" },
new AjaxOptions { UpdateTargetId = "chartimage"}))
{
<div class="report">
// MyViewModel fields and validation messages...
<input type="submit" value="Generate" />
</div>
}
<div id="chartimage">
#Html.Partial("ValidationSummary")
</div>
I then display a PartialView that has a #Html.ValidationSummary() in case of validation errors.
ReportController.cs
public PartialViewResult TotalPaymentsByMonthYear(MyViewModel model,
string reportName)
{
if (!ModelState.IsValid)
{
return PartialView("ValidationSummary", model);
}
model.ReportName = reportName;
return PartialView("Chart", model);
}
What I'd like to do is: instead of displaying validation errors within this PartialView, I'm looking for a way of sending this validation error message to a DIV element that I have defined within the _Layout.cshtml file.
_Layout.cshtml
<div id="message">
</div>
#RenderBody()
I'd like to fill the content of this DIV asynchronously. Is this possible? How can I do that?
Personally I would throw Ajax.* helpers away and do it like this:
#model MyApp.Web.ViewModels.MyViewModel
<div id="message"></div>
#using (Html.BeginForm("TotalPaymentsByMonthYear", new { reportName = "CreateTotalPaymentsByMonthYearChart" }))
{
...
}
<div id="chartimage">
#Html.Partial("ValidationSummary")
</div>
Then I would use a custom HTTP response header to indicate that an error occurred:
public ActionResult TotalPaymentsByMonthYear(
MyViewModel model,
string reportName
)
{
if (!ModelState.IsValid)
{
Response.AppendHeader("error", "true");
return PartialView("ValidationSummary", model);
}
model.ReportName = reportName;
return PartialView("Chart", model);
}
and finally in a separate javascript file I would unobtrusively AJAXify this form and in the success callback based on the presence of this custom HTTP header I would inject the result in one part or another:
$('form').submit(function () {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result, textStatus, jqXHR) {
var error = jqXHR.getResponseHeader('error');
if (error != null) {
$('#message').html(result);
} else {
$('#chartimage').html(result);
}
}
});
return false;
});

Resources