Using Javascript Bootbox with Ajax.BeginForm In ASP.NET - asp.net-mvc

In view page:
#using (Ajax.BeginForm("UpdateAccount", "AccountInfo", new AjaxOptions {
HttpMethod = "POST",
AllowCache = false,
OnSuccess = "accountUpdateRequestSuccess",
OnFailure = "formSubmissionFailed",
OnBegin = "validateAccountInformation"
}))
validateAccountInformation function is stated below:
function validateAccountInformation() {
if (error.length > 0) {
showErrorNotification(errorListHtml);
return false;
}
else {
if ( Some Conditions ) {
bootbox.confirm({
title: "Confirm",
size: "medium",
message: "Some Message",
callback: function (result) {
if (result) {
Some Code
}
else {
Some Code
}
}
});
}
}
When Save button is clicked, at first validateAccountInformation function is called. If there's no error it will raise a Bootbox. If Bootbox OK button is clicked it'll submit the form with certain values or if Bootbox CANCEL button is clicked it'll submit the form with certain values different than before.
Now, the problem I'm facing is, when user clicks SAVE button it goes to validateAccountInformation function. And if there is no errors it calls Bootbox.Confirm. What I've expected that form submission will be held until some OK/CANCEL button is clicked in Bootbox. But it does not wait for Bootbox. Meaning Bootbox callback function is never called. It might have something to do with AJAX being asynchronous.
I've used javascript confirm method. And this method does hold form submission.
function validateAccountInformation() {
if (error.length > 0) {
showErrorNotification(errorListHtml);
return false;
}
else {
if ( Some Conditions ) {
if (confirm("check")) {
some code
}
}
}
}
Is there some way where I can use Bootbox Confirmation box with Ajax Begin Form as per scenario described above?

I've changed the flow and have been able to integrate Bootbox.
What I've done is, I've omitted the onBegin function. So my view page looks like this
#using (Ajax.BeginForm("UpdateAccount", "AccountInfo", new AjaxOptions {
HttpMethod = "POST",
AllowCache = false,
OnSuccess = "accountUpdateRequestSuccess",
OnFailure = "formSubmissionFailed",
}))
Now I've added a function which is fired by onclick event of this forms summit button. And integrated validateAccountInformation function and Bootbox within this function. Now the important part here is, this function always returns false. By returning false I've managed to hold on the form submission. Now the onClick event function looks like
$(document).on('click', '#btn-edit-account-save', function () {
var submit = validateAccountInformation();
some code
if (submit == true) {
if (some condition)
{
$('Form').submit();
}
else
{
bootbox.confirm(
{
title: "Confirm",
size: "medium",
message: "Some Message",
callback: function (result)
{
if (result)
{
$('Form').submit();
}
else
{
some code
}
}
});
}
}
return false;
});

Related

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?

actionlink should not submit if the check box was not checked

i was set action link asp.net mvc grid.
like below.
when click on action link it is going to javascript function,
there i was set return false ,this false for page should not submit to action.
but cursor is going controler correspond action.
how to prevent this.
if check box was not checked only popup raise and page should not submited to action.
below is my code function actionlink:
grid.Column("Title",
format: #<text>#Html.ActionLink((string)item.Title,
"Details", "Home", new { id = item.ID }, new { onclick = "getValueUsingClass1()" })</text>),
function getValueUsingClass1() { debugger;
$(".myCssClass:checked").each(function ()
{ chkArray.push($(this).val());
var selected;
selected = chkArray.join(',') + ",";
if (selected.length > 1)
{ alert("You have selected " + selected); }
else { alert("Please at least one of the checkbox"); }
return false;
});
}
To return from function you can use return false or e.preventDefault(). You have returned from .each function take that statement outside .each or use e.preventDefault()
grid.Column("Title",
format: #<text>#Html.ActionLink((string)item.Title,
"Details", "Home", new { id = item.ID }, new { onclick = "getValueUsingClass1(event)" }
function getValueUsingClass1(e) { debugger;
$(".myCssClass:checked").each(function (){
chkArray.push($(this).val());
var selected;
selected = chkArray.join(',') + ",";
if (selected.length > 1)
{
alert("You have selected " + selected);
}
else { alert("Please at least one of the checkbox"); }
});
e.preventDefault();
//OR
return false;
}

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.

How to manage MVC AJAX responses when in a jQuery dialog

Here is my problem:
Inside a jQuery dialog I have the following code:
<%:Ajax.ActionLink("Yes", "SendClaim", "Claim", new { id = Model.ExpenseId }, new AjaxOptions { UpdateTargetId = "dialog" }, new { #class = "button" })%>
When stuff fails in the controller based on roles I return a partial view that replaces the existing dialog (see UpdateTargetId = "dialog").
When everything works I want to do a redirect to another page (an index of all claims) to stop the user performing additional actions but this entire page is rendered inside the jQuery dialog due to it being an ajax request with an update id.
What is the correct way to approach the problem?
I'm a bit of a novice, but I find I have more control with the following approach instead of using Ajax.ActionLink. Hopefully it helps and I have understood what you want to do correctly.
Claim Controller:
[AcceptVerbs(HttpVerbs.Post)]
public Json Send(int expenseId)
{
// Check user stuff
if(valid)
// do stuff
return new Json(true, JsonRequestBehavior.AllowGet);
else
return new Json(false, JsonRequestBehavior.AllowGet);
}
jQuery
function submitClaim() {
$.ajax({
url: "/Claim/Send",
type: "POST",
dataType: "json",
data: { 'expenseId': <%=Model.ExpenseId> },
success: function (data) {
if(data) { // if successful, redirect
document.location = "Claim/Index";
}
else { //load your partial view into your dialog
$("#idOfYourDialog").load('Claim/Error/');
}
},
error: function (xhr) { }
});
}
html
Submit
Returned an 'All OK' dialog and had the following javascript when the user clicks the ok button:
function redirect() {
document.location = "<%:(String)ViewBag.Redirect %>";
}
$(document).ready(function() {
$(".ui-dialog-titlebar-close").click(function() {
redirect();
});
});
Seems unavoidable - you can't seem to do an RedirectToAction when the controller action has been called from Ajax.ActionLink as the response will be stuck into the updatetargetid.

Delete with confirmation and redirect on success

Here's the behavior I'm looking for:
User selects a record from an index view, which redirects to that record's detail view.
User clicks a link to delete the currently displayed record.
A modal dialog asks for confirmation of the delete.
User presses the Confirm button.
The associated controller action method is executed, which is supposed to delete the record.
User is returned to the index view, where the deleted record is no longer displayed.
I am using ASP.NET MVC 1.0 as the primary framework, the dialog component from the jQuery UI, and LINQ-to-SQL to handle database interaction. Steps one through four execute just fine. Step five, however, retrieves the record, but doesn't delete it. Step six executes, but the record is still displayed in the list.
Here is the code for the delete link:
<% if (Model.CanDelete())
{ %>
<%= Html.ActionLink("Delete", "Delete", new { id = Model.Package_ID },
new { onclick = string.Format("deletePackage({0}); return false;", Model.Package_ID) })%> |
<% } %>
Here is the code for the onclick handler:
function deletePackage(packageID) {
createDialogContent(); // The HTML for the dialog content is set in this method
$.getJSON('/Spectrum/Package/DetailsJSON/' + packageID, function(json) {
$('p.message').html('Delete <strong>' + json.Description + '</strong>?');
});
$('div.confirm').attr('title', 'Delete Package');
$('div.confirm').dialog({
draggable: false,
modal: true,
overlay: {
backgroundColor: '#000',
opacity: 0.5
},
resizable: false,
buttons: {
'Confirm': function() {
$(this).dialog('destroy').remove();
$.post('/Spectrum/Package/Delete/' + packageID);
// The next line used to be: $.get('/Spectrum/Package/Index');
window.location.href = '/Spectrum/Package/Index';
},
Cancel: function() {
$(this).dialog('destroy').remove();
}
}
});
}
Here is the code for the delete controller method:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(int id)
{
Package package = RepositoryManager.Package().GetPackage(id);
PackageDeleteViewModel viewModel = new PackageDeleteViewModel
{
Package_ID = package.Package_ID
};
RepositoryManager.Package().PackageDelete(viewModel); // see code below
return new EmptyResult();
}
Finally, here is the repository method for the delete:
public void PackageDelete(PackageDeleteViewModel data)
{
Package package = RepositoryManager.Package().GetPackage(data.Package_ID);
if (package.BrokerageOrderPackages.Count == 0
&& package.ManagementOrderPackages.Count == 0
&& package.Seeds.Count == 0)
{
db.Packages.DeleteOnSubmit(package); // This branch is being executed
db.SubmitChanges();
}
else
{
throw new RulesException("Package cannot be deleted.", "PackageDelete");
}
}
I don't think I'm pushing the envelope here or getting too fancy. One area of concern: In the Confirm button handler of the onclick method, the first version would delete the record successfully, but not redirect to the Index view. With the current version, the delete fails silently, but the redirection occurs. Firefox/Firebug reported 200's for the Index GET in both situations. The behavior is similar in both Firefox and IE.
$.post is an async ajax request, if you reload the page the call gets cancelled. You should reload the page on its callback function parameter:
$.post('/Spectrum/Package/Delete/' + packageID,
null,
function(json){
if (json.success) {
window.location.href = '/Spectrum/Package/Index';
} else {
// jquery dialog call or
alert(json.errorMessage);
}
},
'json');
And the controller code:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(int id)
{
try {
// Validation and deletion code
} catch exception ex {
return Json(new {errorMessage = ex.Message, success = false});
}
return Json(new {success = true});
}

Resources