MVC: used partial view for jquery modal popup, issues with validation - asp.net-mvc

So i have a button in a view that opens up a modal pop up form. This modal pop up form is a partial page. My issue with this is that:
Whenever I don't fill up the required fields on the form, the TryUpdate check will obviously fail, but it will just refresh the whole page cuz of the line "window.location.reload" on the jquery. What I wanted to do is that instead of refreshing, it would still stay as it is (the page with the modal showing) and validation summary or validations will show up saying, this and that are required. Is this possible or am I complicating stuff with it?
<script type="text/javascript">
$(document).ready(function () {
$(function () {
$('#modal-link').click(function () {
var href = this.href;
$('#load-modal').dialog({
modal: true,
draggable: false,
position: "top",
open: function (event, ui) {
$(this).load(href, function (result) {
$('#new-academy-form').submit(function () {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (json) {
window.location.reload(true);
},
error: function (data) {
var errmessage = '<div class="error-repo">Error</div>';
$('#messages').html(errmessage);
}
});
return false;
});
});
}
});
return false;
});
});
});
</script>
This is the button:
<div class="width3">
<%: Html.ActionLink("Submit New", "Create", "Propose", null, new { #class = "results", id = "modal-link" })%>
</div>
This is the action:
public ActionResult Create()
{
return PartialView(Propose.LoadDetails(context, null));
}
[HttpPost]
public ActionResult Create(FormCollection formCollection)
{
Propose propose= new Propose ();
if(TryUpdateModel(propose, "Propose ")){
context.Propoe.Add(propose);
context.SaveChanges();
var proposals = new System.Text.StringBuilder();
return Json(new { propose= proposals});
}
return PartialView(Propose.LoadDetails(context, null));
}

You can return a flag from your action.
var data = new {isSuccess, new { propose= proposals}};
return Json(data , JsonRequestBehavior.AllowGet);
and then use it in jquery like
success: function (data) {
if(data.isSuccess){
window.location.reload(true);
}
else{
// write code to show validation summary and no reload.
}
}

Related

My partial view does not refresh after AJAX call

I am having an issue not able to refresh my Partial view.
my cshtml page page
<script type="text/javascript">
$(document).ready(function () {
$('#btncreate').click(function () {
var projectid = $("#txtprojectid").val();
$.ajax({
url: '/Projects/CreateFinanceItems?pid=' + Id,
datatype: 'json',
type: "POST",
success: function (response) {
alert("record created successfully");
if (response != null) {
window.close();
refreshpartial();
}
}
})
});
function refreshpartial()
{
$.ajax({
url: '/Projects/PartialItem?id=' + "Test",
datatype: 'json',
success: function (response) {
$("#displayproContainer").html(response);
},
error: function (xhr, ajaxOptions, thrownError) {
}
})
}
});
</script>
I can see record created successfully alert message, but when it goes to refreshpartial method my partialview does not refresh with Added data. I put the alert in success function it does not hit.
Partialview DIV ID #displayproContainer
$("#displayproContainer").html(response);
Controller code
[OutputCache(Duration = 0)]
public PartialViewResult PartialItem(string id)
{
// Logic to Insert data
return PartialView(viewModel);
}
Something I am missing here?

Kendo Control calls Controller's action method only from the main page. It does not call it from another page

I have an index.cshtml view that uses a shared layout:
#{
Layout = "~/Views/Shared/_LoginLayout.cshtml";
}
This index.cshtml view is displayed when user opens the Login page of the application. It works with the Login controller
This layout generates a partial view that defines a Kendo.DropDownList:
#Html.Partial("_CultureSelector")
This is the _CultureSelector view with a dropdown list:
<script>
function onCultureChange(e) {
ChangeCulture(e, this);
}
function onDataBound(e) {
var combo = $("#culture").data("kendoDropDownList");
$(combo.dataItems()).each(function () {
if (this.IsDefault) {
e.sender.value(this.Value);
}
});
}
</script>
<label for="culture">Choose culture:</label>
#(Html.Kendo().DropDownList()
.Name("culture")
.DataValueField("Value")
.DataTextField("DisplayText")
.DataSource(dataSource =>
{
dataSource.Read(read =>
{
read.Action("PopulateCultures", "CultureSelector");
}).Events(e => e.Error("CheckError"));
})
.Events(events =>
{
events.Select("onCultureChange").DataBound("onDataBound");
})
)
I have a controller called "CultureSelector" with a method "ChangeCulture":
public JsonResult ChangeCulture(string selectedCulture)
{
Session["SiteUICulture"] = selectedCulture;
Session["hasCultureChanged"] = true;
GlobalCulture.SetCultureCookie(selectedCulture);
Session["CultureDropDownSelected"] = true;
return Json(new { success = true }, JsonRequestBehavior.AllowGet);
}
When I change the value in dropdown, this method is called, but ONLY on Login page.
This is an Ajax call to "ChangeCulture" method:
function ChangeCulture(e, cultureDropDown) {
var loginUrl = document.location.origin + '/Login';
var returnUrl = document.location.pathname + document.location.search;
if (e.item) {
var selectedCulture = cultureDropDown.dataItem(e.item);
$.ajax(
{
url: "CultureSelector/ChangeCulture",
type: "GET",
contentType: "application/json; charset=utf-8",
datatype: "json",
data: { "selectedCulture": selectedCulture.Value },
success: function (response) {
if (response.success) {
alert("test");
window.location.href = returnUrl;
}
}
}
)
}
}
When I change the dropdown valued on Login Page string "test" is printed on Ajax success, when on "Forgot Password" page, it is not printed.
Login page has "Forgot Password" link and when it is clicked, "ForgotPassword" page is opened.
This page uses the same layout:
#{
Layout = "~/Views/Shared/_LoginLayout.cshtml";
}
So, the same dropdown list is generated. PopulateCultures method is called.
But, when changing the value in dropdown, CultureChange method is not called.
What am I missing here?

ASP.NET MVC form on a Partial View

I have page witha table and a button. When I push the button a partial view loads into a div. On the partial view there is an ajax form which sends back the partial view with validation error in case of wrong form data but I want to remove the partial view and refresh the table in case of successful insertion.
The form header:
#using (Ajax.BeginForm("RequestInsert", "Home", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "requestForm" }, new { id = "reqins" }))
The jQuery submit event handler on the host page:
$(document).on('submit', '#reqins', function (e) {
e.preventDefault();
let data = $("form :input").serializeArray();
$.ajax({
url: '#Url.Action("RequestInsert", "Home")'
,type: "POST"
,data: { "__RequestVerificationToken": token, "model": data }
})
.done(function (data) {
$("#requestForm").html("");
table.search('').columns().search('').draw();
})
.fail(function (jqXHR, textStatus) {
alert("fail");
});
});
I am a little confused with the partial view and ajax form.
Since your objective is checking validation status from AJAX response, you can use if condition against AJAX response as shown below:
$('#reqins').submit(function (e) {
e.preventDefault();
let data = $('form :input').serializeArray();
$.ajax({
url: '#Url.Action("RequestInsert", "Home")',
type: 'POST',
data: { "__RequestVerificationToken": token, "model": data },
success: function (result) {
// check valid response
if (result.invalid) {
$('#requestForm').html(result.form);
}
else {
$('#requestForm').html(result);
table.search('').columns().search('').draw();
}
},
error: function (jqXHR, textStatus) {
alert("fail");
}
});
});
Then inside controller action you can return both validation status and partial view using Controller.Json() with RenderViewToString() extension method provided here:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RequestInsert(ViewModel model)
{
// perform validation here
// assume IsValid is a boolean returned from validation status
if (IsValid)
{
// successful validation, return empty form
return PartialView("FormPartialView");
}
else
{
// validation failed, return failure status and previously-filled form
return Json(new { invalid = true, form = RenderViewToString(PartialView("FormPartialView", model)) });
}
}
try this and remove the Ajax Helper
$('#reqins').on('click', function () {
let data = $("form :input").serializeArray();
$.ajax({
url: '#Url.Action("RequestInsert", "Home")'
,type: "POST"
,data: data
,success:function (result) {
$("#requestForm").html(result);
}});
});
modify your action to this
public JsonResult RequestInsert()
{
try
{
return Json(new { success = true, result = PartialView("Prtialview") });
}
catch (Exception ex)
{
return Json(new { success = false, result = ex.ErrorMessage });
}
}
and then modify the client side as following
$('#reqins').on('click', function () {
let data = $("form :input").serializeArray();
$.ajax({
url: '#Url.Action("RequestInsert", "Home")'
,type: "POST"
,data: data
,success:function (result) {
if(result.succuss)
{
$("#requestForm").html(result);
}
else
{
alert("Error");
}
}});
});

Knockout js, mvc 5 project - bind client ViewModel to the controller action

Could you please help me with this. I'm successfully getting data from the server ViewModel. However when I try to save client ViewModel from the view to the Controller Save action. I'm getting empty ViewModel. In the sample what I'm using was used JavaScriptSerializer. However this is not recommended to use in ASP.NET Core MVC project since there are Newtonsoft extension. Could you please help me to adopt below code to work?
#{
ViewBag.Title = "Details";
}
#{
var data = #Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model));
}
#section scripts
{
<script src="~/lib/knockout/dist/knockout.js"></script>
<script src="~/lib/knockout-mapping/knockout.mapping.js"></script>
<script src="~/js/realtyvm.js"></script>
<script type="text/javascript">
$(function () {
var realtyViewModel = new RealtyViewModel(#Html.Raw(data));
ko.applyBindings(realtyViewModel);
});
</script>
}
/* Realty Client ViewModel */
(function () {
RealtyViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
self.save = function () {
$.ajax({
url: "/App/Save/",
type: "POST",
data: ko.toJSON(self),
contentType: "application/json",
success: function (data) {
if (data.realtyViewModel != null)
ko.mapping.fromJS(data.realtyViewModel, {}, self);
}
});
}
}
})();
This how looks controller actions:
public ActionResult Create()
{
RealtyViewModel realtyViewModel = new RealtyViewModel();
return View(realtyViewModel);
}
public JsonResult Save(RealtyViewModel realtyViewModel)
{
Realty realty = new Realty();
realty.Title = realtyViewModel.Title;
realty.Description = realtyViewModel.Description;
realty.RealtyType = realtyViewModel.RealtyType;
_repository.InsertRealty(realty);
_repository.Save();
realtyViewModel.MessageToClient = string.Format("{0} realty has been added to the database.", realty.Title);
return Json(new { realtyViewModel });
}
Update, I opened XHR request, here is details:
Request payload
{Id: 0, Title: "Te", Description: "te", RealtyType: "te", MessageToClient: null}
Description:"te" Id:0 MessageToClient:null RealtyType:"te" Title:"Te"
Response:
{"realtyViewModel":{"id":0,"title":null,"description":null,"realtyType":null,"messageToClient":" realty has been added to the database."}}
I've resolved this issue by specifying from where coming data, by adding [FromBody] to post action.
public JsonResult Save([FromBody]RealtyViewModel realtyViewModel)
{
Realty realty = new Realty();
realty.Title = realtyViewModel.Title;
realty.Description = realtyViewModel.Description;
realty.RealtyType = realtyViewModel.RealtyType;
_repository.InsertRealty(realty);
_repository.Save();
return Json(new { realtyViewModel });
}

MVC - Load [HttpPost] view into Jquery/Ajax modal window

The way my code works currently is when a button is pressed variables are passed and Jquery unhides a modal window and makes an AJAX call to get the [HttpGet] portion of my Controller Action. This loads a form in the modal window. The modal has a save and cancel button, when the save button is pressed the form is submitted with ajaxSubmit. On successful save something is saved to the database, then a url is created and passed back to jquery and user is redirected with window.location.href.
What I'd like to have happen is when the save button is pressed the [HttpPost] part of controller action will make some logic choices, and if a certain condition is met within the action then return PartialView(model) is returned back to the modal window with an error message or pop up so that the user doesn't have to retype their information and understands why the save didn't go through and can edit quickly and try save again.
The Jquery:
var createNewClaimSetup = function () {
$(selectors.btnCreateNewClaim).live('click', function () {
var serialNumber = $(this).attr(attributes.serialNumber);
var spaRegistrationId = $(this).attr(attributes.spaRegistrationId);
var customerNumber = $(this).attr(attributes.customerNumber);
var customerStatementName = $(this).attr(attributes.customerStatementName);
$(selectors.serialNumberHidden).val(serialNumber);
$(selectors.spaRegistationIdHidden).val(spaRegistrationId);
$(selectors.customerNumberHidden).val(customerNumber);
$(selectors.customerStatementName).val(customerStatementName);
$(selectors.dialog).attr(attributes.title, 'Create New Claim');
$.ajax ({
url: inputs.warrantyClaimCreateUrl,
type: "GET",
data: {
serialNumber: serialNumber,
customerNumber: customerNumber
},
cache: false,
success: function (result) {
$(selectors.dialog).html(result.toString());
$(selectors.dialog).dialog ({
resizable: false,
height: 600,
width: 850,
modal: true,
buttons: {
'Save': function () {
// check to see if a value has been entered for problem description before submitting form
//
if(!$('#AddProblemModel_ProblemDesc').val().length==0 && (!$('#ClaimPrefix').val().length==0 || $('#chkManualClaimNum').is(':checked')))
$(selectors.createNewClaimForm).ajaxSubmit({
cache: false,
success: function (data) {
if (data.length == 0) {
location.reload();
$(selectors.dialog).dialog('close');
} else {
$(selectors.dialog).dialog('close');
window.location.href = data.redirectToUrl;
}
}
});
else{
return alert('You must select a prefix and enter a description for the problem before saving');
}
},
Cancel: function () {
$(this).dialog('close');
}
}
});
}
});
});
}
Controller Action GET (edited for brevity):
public virtual ActionResult WarrantyClaimCreateNew(string serialNumber, string customerNumber, string customerStatementName)
{
WarrantyClaimModel model = wcs.CreateNewClaimInfo(serialNumber, customerNumber, false);
ViewBag.InvalidPrefix = false;
ViewBag.DupeWaNum = false;
return View(model);
}
Controller Action POST (edited for brevity):
[HttpPost]
public virtual ActionResult WarrantyClaimCreateNew(WarrantyClaimCreateNewModel model)
{
if (ModelState.IsValid)
{
WaNumberDupeModel WAdupe = new WaNumberDupeModel(model.WarrantyClaimNumber);
// Rebuild WarrantyClaimModel object to pass back to view
WarrantyClaimModel model2 = wcs.CreateNewClaimInfo(model.SerialNumber, model.CustomerNumber, false);
// check if prefix is valid
if (WAdupe.DupeType == WaDupeType.InvalidPrefix)
{
ViewBag.InvalidPrefix = true;
return PartialView(model2);
//return Json(new { Url = Url.Action("WarrantyClaimCreateNew", model2) });
}
// check if wa number already exists
if (WAdupe.DupeExists)
{
ViewBag.DupeWaNum = true;
return PartialView(model2);
}
// create/save the new claim
if (wcs.CreateNewWarrantyClaim(model))
{
var redirectString = "WarrantyClaimDetail?warrantyClaimNumber=" + model.WarrantyClaimNumber;
if (Request.IsAjaxRequest())
{
return Json(new { redirectToUrl = redirectString }, JsonRequestBehavior.AllowGet);
}
return RedirectToAction(Actions.WarrantyClaimDetail(newClaimNumber));
}
return RedirectToAction(Actions.WarrantyClaimSaveFail());
}
else
{
return View(model);
}
}
Alerts In View If Conditions In Controller Action Met:
<%if (ViewBag.InvalidPrefix == true) { %>
alert("Please choose a valid prefix for your warranty claim number.");
<% } %>
<%if (ViewBag.DupeWaNum == true) { %>
alert("Warranty Claim Number already exists, please choose another manual WA number or try again.");
<% } %>
I haven't even been able to reload the view refreshed in the modal at all, let alone with changed to the bound model intact.
I know that the first part of the AJAX call (type: "GET") uses the URL to go into the controller action GET and gets back the return View(model) then converts it to HTML and sets the modal window HTML to it. I've been assuming that the ajaxSubmit goes back to the controller and gets the POST version of the action, and that the data part of success: function (data) should be the view return if condition is met and the built JSON URL to redirect to if it's not.
I've tried setting the modal html to data and making sure the controller invalid prefix condition is met, however the content in the modal window never seems to refresh. I'll also need to figure out how to logically tell in JQUERY if the controller returned a view or a URL through JSON but I don't think that will be hard to figure out.
I've read through a dozen or so mvc jquery ajax modal similar questions and they've helped but not
Thanks for any help shedding some light on how I might accomplish what a want here.
Sort of a partial answer to what I was looking for. I realize now my main stumbling block was to have my test alerts before building the modal window as "return alert(whatever)" which was obviously returning the alert and not running the rest of the code, dumb.
The solution I have working now is a pretty bad hack. I have it rebuild the modal and attach the POST view data to it. However this isn't looped so if you save and fail again I've set it to alert the user save failed again and to retry, then the modal closes and they can start again from scratch.
Tomorrow I'll see about turning this into a looping rather than nested structure.
New "working" JQuery code:
var createNewClaimSetup = function () {
$(selectors.btnCreateNewClaim).live('click', function () {
var serialNumber = $(this).attr(attributes.serialNumber);
var spaRegistrationId = $(this).attr(attributes.spaRegistrationId);
var customerNumber = $(this).attr(attributes.customerNumber);
var customerStatementName = $(this).attr(attributes.customerStatementName);
$(selectors.serialNumberHidden).val(serialNumber);
$(selectors.spaRegistationIdHidden).val(spaRegistrationId);
$(selectors.customerNumberHidden).val(customerNumber);
$(selectors.customerStatementName).val(customerStatementName);
$(selectors.dialog).attr(attributes.title, 'Create New Claim');
$.ajax ({
url: inputs.warrantyClaimCreateUrl,
type: "GET",
data: {
serialNumber: serialNumber,
customerNumber: customerNumber
},
cache: false,
success: function (result) {
$(selectors.dialog).html(result.toString());
$(selectors.dialog).dialog ({
resizable: false,
height: 600,
width: 850,
modal: true,
buttons: {
'Save': function () {
// check to see if a value has been entered for problem description before submitting form
//
if(!$('#AddProblemModel_ProblemDesc').val().length==0 && (!$('#ClaimPrefix').val().length==0 || $('#chkManualClaimNum').is(':checked')))
$(selectors.createNewClaimForm).ajaxSubmit({
cache: false,
success: function (data) {
if (data.length == 0) {
location.reload();
$(selectors.dialog).dialog('close');
} else if(data.redirectToUrl) {
$(selectors.dialog).dialog('close');
window.location.href = data.redirectToUrl;
} else {
$(selectors.dialog).html(data.toString());
$('#chkManualClaimNum').attr('checked','checked');
$('#manualClaimInfo').toggle();
$(selectors.dialog).dialog ({
resizable: false,
height: 600,
width: 850,
modal: true,
buttons: {
'Save': function () {
if(!$('#AddProblemModel_ProblemDesc').val().length==0 && (!$('#ClaimPrefix').val().length==0 || $('#chkManualClaimNum').is(':checked')))
$(selectors.createNewClaimForm).ajaxSubmit({
cache: false,
success: function (data) {
if (data.length == 0) {
location.reload();
$(selectors.dialog).dialog('close');
} else if(data.redirectToUrl) {
$(selectors.dialog).dialog('close');
window.location.href = data.redirectToUrl;
} else {
alert('Save failed again. Please start over.');
$(selectors.dialog).dialog('close');
}
}
});
},
Cancel: function () {
$(this).dialog('close');
}
}
});
}
}
});
else{
return alert('You must select a prefix and enter a description for the problem before saving');
}
},
Cancel: function () {
$(this).dialog('close');
}
}
});
}
});
});
}
This does at least show how to pass the POST view back to the modal window.

Resources