This is my objective:
Custom Bootbox dialog opens to specify a value. User specifies a value, clicks Save and the value is passed to web application via Ajax call.
Web application validates the value and either sends back a "success" message if validation was passed and database was updated or sends back a "failure" message with a reason for a validation failure.
If "success" message was received dialog closes, otherwise it opens again and displays validation message below user input. User can change the input and click Save again or press Cancel to dismiss the dialog.
MCVE (note that while(bContinue == true) is commented out to show that it works without a loop and there is no validation message anywhere but it will be a part of a Message variable (this variable will be updated in Save callback function after an Ajax call)):
$(document).on("click", ".alert", function(e) {
var Message = "<label class='control-label col-sm-1' style='width:30px;' for='assignmentname'>"+"Assignment "+"</label>"
+ "<input type='text' id='assignmentname' class='form-control' style='float: left; max-width:800px;' value='Initial value'>"
var bContinue = true;
//while(bContinue == true)
{
bootbox.dialog({
size: "large",
message: Message,
title: "Edit Assignment",
buttons: {
save:
{
label: "Save",
className: "btn btn-success",
callback: function() {
// perform Ajax call to the web application
// and set bContinue to true or false depending on
// return value
bContinue = true;
}
},
cancel:
{
label: "Cancel",
className: "btn btn-default",
callback: function() {
// exit out of the loop
bContinue = false;
}
}
}
});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script src="https://github.com/makeusabrew/bootbox/releases/download/v4.4.0/bootbox.min.js"></script>
<p><a class="alert" href=#>Click here</a></p>
The problem is - as soon as while(bContinue == true) is un-commented the dialog never opens.
Expected MCVE behavior: dialog opens and if Save is clicked it closes and re-opens. If Cancel is clicked - dialog closes.
The problem is not in the Bootbox , the problem is in the while loop which keep looping very fast without waiting the Bootbox to load, and it make the whole browser hang :)
So you will need to change your logic, may be put the Bootbox dialog in a function and make it call the function again on save.
Or may be using promises: How to use confirm alert and return an AJAX promise?
Related
I am using JQuery-UI dialog to load an MVC partial view
Here is some sample code:
$(function () {
function fSetupDialogs() {
$("#dialog-popup").dialog({
autoOpen: false,
resizable: true,
modal: true
});
}
});
$('body').on('click', '.popup-Edit',
function (e) {
url = $(this).data("url");
$("#dialog-popup")
.load(url)
.html("<img src='/content/images/Spinner.gif'>")
.dialog("option", "title", "Edit " + url.split("/").pop())
.dialog('open');
}
);
This works pretty well despite some occasional weird scrollbars and stuff.
The problem is when the view throws an error, I can't work out how to inspect it and display it inside the jqueryui panel
So if the view returns a 500 or 401 error, I'd like to capture that and show it in the dialog. Right now what happens is that the spinner GIF just sits there forever. If I open the F12 console I can see the error in there.
I have tried using the .error event handler which does capture it and pop up a messagebox. But I want to display inside the popup:
// This pops up an error alert
$("#dialog-popup")
.load(url)
.error(alert("error"))
.html("<img src='/content/images/Spinner.gif'>")
.dialog("option", "title", "Edit " + url.split("/").pop())
.dialog('open');
How do I display something inside the dialog? This has no effect - the spinner stays in there
// This has no effect - I want to see the words "error"
$("#dialog-popup")
.load(url)
.error($("#dialog-popup").html("error"))
.html("<img src='/content/images/Spinner.gif'>")
.dialog("option", "title", "Edit " + url.split("/").pop())
.dialog('open');
For bonus points, how do I use the javascript error object to identify 401, 500 whatever? - I haven't got to that yet.
I looked through my own code and found the answer.
The load method takes a callback argument that can be used to do what I need
I wrote a function called popupComplete that is called when the load is finished.
// This loads a partial MVC view into the popup
$("#dialog-popup")
.load(url,popupComplete)
.html("<div align='middle'><img src='/content/images/Spinner.gif'></div>")
.dialog("option", "title", "New")
.dialog("open");
// when the load is complete, this is called
// which optionally displays an error inside the popup
function popupComplete(response, status, xhr) {
if (status === "error") {
var msg =
"<BR><BR><BR><H3 style='text-align: center;'><span style='color: red;' class='glyphicon glyphicon-fire'></span> Confound it!<BR><BR>" +
xhr.status + " " + xhr.statusText +
"<BR><BR>" + (xhr.status == 401 ? "Try logging in again" : "") +
"</B></H3>";
$("#dialog-popup").html(msg);
}
}
On my website I have a navigation and a main content area. When you click on a navigation link, the content inside the main content area always gets loaded via ajax. If you click the link "Contact", a text gets loaded which contains a link for a jQuery dialog which contains the contact form.
The problem: When you load the website and navigate to the contact form area, the validation works perfectly fine. However, if you navgiate away to another content area (= another content gets loaded via ajax) and then go back to the contact form area and click the submit button (WITHOUT reloading the page in between), validation fails, gets ignored and the form action gets executed. If you reload the page and then navigate to the contact form area, everything works again.
I cannot make sense of this behaviour. What is weird: Validating another form in the content area which is NOT opened in a jQuery dialog always works, no matter what you had clicked before. So it must be because of the jQuery dialog popup and Ajax. Who can make sense of this problem?
Here comes my code:
HTML:
open form test popup
<div id="popup-form-test">
<form id="form-test" action="somelink">
<input type="text" placeholder="testtext eingeben" name="testText"></input>
<input type="submit" value="submit">
</form>
</div>
JS:
var dialogTest = $("#popup-form-test").dialog({
autoOpen: false,
modal: true,
close: function () {
console.log('closed');
}
});
$("#open-popup-form-test").on("click", function () {
dialogTest.dialog("open");
});
$('#form-test').validate({
debug: true,
rules : {
testText: {
required: true
}
},
submitHandler: function(form) {
alert('submitted');
}
});
you must use the open callback of .dialog() and insert there the validator:
var dialogTest = $("#popup-form-test").dialog({
autoOpen: false,
modal: true,
open : function (event, ui) {
$('#form-test').validate({
debug: true,
rules : {
testText: {
required: true
}
},
submitHandler: function(form) {
alert('submitted');
}
});
},
close: function () {
console.log('closed');
}
});
i can't test without a valid example but it should work.
<script type="text/javascript">
var customDiv ="hello";
$(function () {
var $form = $("#authNotificationForm");
var startItems = $form.serializeArray();
startItems = convertSerializedArrayToHash(startItems);
$("#authNotificationSubmit").click(function (e) {
var currentItems = $form.serializeArray();
currentItems = convertSerializedArrayToHash(currentItems);
var itemsToSubmit = hashDiff(startItems, currentItems);
for (var item in itemsToSubmit) {
customDiv = "test";
}
});
$(".confirm").confirm({
text: "Are you sure you want update the following changes?" + customDiv,
confirm: function (button) {
// do something
},
cancel: function (button) {
// do something
},
confirmButton: "Yes I am",
cancelButton: "No",
post: true
});
</script>
All I am trying to do is on form load get the serializeArray of the form. Then after changing the fields again on submit click get a new serializedArray of form compare the 2 and get which fields were changed then on the confirmation box just show the field that were changed by the user. But the confirmation box is displaying hello instead of test.
It is my assumption that the confirmation box text is already loaded on document ready and it is never updated , so it always has the global variable value which is set on document ready.
(I am getting the updated values correctly so the serialization and the hashDiff functions are fine that not the issue the issue is only getting this values to the confirmation box.)
Thanks for the concern..
You're setting the text: option at load time. Changing customDiv later doesn't affect it because the concatenation was done earlier.
Instead of binding the confirmation dialog directly to the button, use $.confirm so you can pass arguments at the time of the call:
$(".confirm").click(function() {
$.confirm({
text: "Are you sure you want update the following changes?" + customDiv,
confirm: function (button) {
// do something
},
cancel: function (button) {
// do something
},
confirmButton: "Yes I am",
cancelButton: "No",
post: true
});
});
I have written a Jquery-Ui Dialog to popup as a confirmation on particular links. This however does not redirect to my Delete page correctly. However if I open the debugger in chrome to debug, then the code works as expected.
I have found the same question, however the solution does not seem to work for me. It is exactly the same scenario though. Question here JavaScript redirect not working and works only in Chrome if debugger is turned on
So I have my link
<div id="confirm-dialog">
<div class="dialog-inner">
<p id="confirm-dialog-message"></p>
</div>
</div>
Delete
And I have my javascript
$('.confirmLink').click(function (e) {
BodyScrolling(false);
var theHref = $(this).attr("href");
var theTitle = $(this).attr("title") == null ? "Confirm..." : $(this).attr("title");
var theText = $(this).attr("data-confirm-message") == null ? "Are you sure?" : $(this).attr("data-confirm-message");
$("#confirm-dialog-message").html(theText);
$("#confirm-dialog").parent().css({ position: "fixed" }).end().dialog("open");
$("#confirm-dialog").dialog({
title: theTitle,
close: function() {
BodyScrolling(true);
},
buttons: [
{
text: "Yes",
class: "mws-button red",
click: function () {
$("#confirm-dialog").dialog("close");
window.location.href = theHref;
return false;
}
},
{
text: "No",
class: "mws-button black",
click: function () {
$("#confirm-dialog").dialog("close");
}
}]
});
return false;
});
So when I click my Delete link, I am indeed presented with my confirm dialog with Yes and No buttons, css styled correctly, and has captured the link href and bound it to the Yes button. If I click "No", I am kicked back and nothing further happens - Correct!
If I click Yes, it should take send me on to the original href that it captured. I have thrown alert(theHref) on the Yes Button click just before the redirect and it does show me the correct address (/Customer/Delete/73865878346587), but the redirect does not happen.
When I open the chrome debugger to debug the javascript or see if any errors occurred, then everything works as expected and redirects me correctly!
In IE, it does not work either.
I have tried...
window.location.href = theHref
window.location = theHref
location.href = theHref
$(location).attr('href', theHref)
I have also tried adding return false; after my redirect. Nothing works.
The link I added above to the same question said to make sure that the Yes button is being rendered on the page as a ... which mine is.
Can anyone shed any light?
Instead of window.location.href = theHref;
have you tried window.location.replace(theHref);?
Back to basics, try: window.location = theHref;
Well I have found the answer. Javascript was a red herring!
I did try to remove the confirmLink jQuery class so that the link was just a standard link that went straight to my controller to perofm my delete. When I did this test, the link worked perfectly. Therefore I denoted the problem be with my javascript. However, it seems that this was not quite the case and had only worked again if the Debugger in Chrome had been or was open at the time aswell.
When I revisited the non confirm link option again, I found this not to work properly, therefore denoting the problem not with the javascript.
It appears that you cannot perform a Delete action from a HTML Link in MVC. This is obviously because of security risks involved as anyone could perform a Delete on an Id. I had thought of this in my implementation and had added code to check where the Request had come from and if it wasn't from my List page, then it threw back an error and wouldn't perform the Delete. It didn't matter what I named my controller either, eg Test, the link performing my HTTP GET request would never hit this. There must be some algorithm that determines what the action is doing and stops you from performing the action on a HttpGet request. For more information about Delete Actions, check out this post http://stephenwalther.com/archive/2009/01/21/asp-net-mvc-tip-46-ndash-donrsquot-use-delete-links-because
It seems that you can only perform this by a HTTP Post, which means either using a Ajax.ActionLink or by using a Form and a submit button. Then your Action must be specified for HttpPost.
If, like me, you wish to keep your Link as a HTML Link, then you can do the following which is what I did, code below. I kept my HTML Link, set it up to point to my HttpPost Delete Action. Added my confirmLink class for jquery to bind my dialog box to. I pick up the link href and set the Yes button in the jquery dialog to dynamically create a Form and set the method to post and the action to the links href. Then I can call submit on the new dynamically created form to perform my Post to my Delete action.
My Delete Link
Html.ActionLink("Delete", "Delete", "Caterer", new { id = caterer.Id }, new { #class = "mws-ic-16 ic-delete imageButton confirmLink", #data_confirm_title = "Delete " + caterer.Name, #data_confirm_message = "Are you sure you want to delete this caterer, " + caterer.Name + "?" })
My Javascript
function LoadConfirm() {
$('.confirmLink').click(function (e) {
e.preventDefault();
BodyScrolling(false);
var actionHref = $(this).attr("href");
var confirmTitle = $(this).attr("data-confirm-title");
confirmTitle = confirmTitle == null ? "Confirm..." : confirmTitle;
var confirmMessage = $(this).attr("data-confirm-message");
confirmMessage = confirmMessage == null ? "Are you sure?" : confirmMessage;
$("#confirm-dialog").dialog({
autoOpen: false,
modal: true,
width: 400,
closeOnEscape: true,
close: function () { BodyScrolling(true); },
title: confirmTitle,
resizable: false,
buttons: [
{
text: "Yes",
class: "mws-button red",
click: function () {
StartLoading();
$(this).dialog("close");
var form = document.createElement("form");
form.setAttribute("method", "post");
form.setAttribute("action", actionHref);
form.submit();
}
},
{
text: "No",
class: "mws-button black",
click: function () {
$("#confirm-dialog").dialog("close");
return false;
}
}
]
});
$("#confirm-dialog #confirm-dialog-message").html(confirmMessage);
$("#confirm-dialog").parent().css({ position: "fixed" });
$("#confirm-dialog").dialog("open");
});
}
My Action
[HttpPost]
[Authorize(Roles = "User")]
public ActionResult Delete(long id)
{
//Perform my delete
return RedirectToActionPermanent("List");
}
I would like to create a JavaScript function similar to confirm() that shows a dialog (a div with a question and 2 buttons) and returns true if the user clicks "Ok" or false otherwise.
Is it possible to do that using JavaScript/jQuery but without plugins (e.g. jQuery UI or Dialog)? Because I'm trying to reduce size and round trip times...
I tried to write this code, but I don't know how to make the function "wait" for the user click.
I would like to use my function in this way:
answer=myConfirm("Are you sure?")
In this way I could use the same function in several contexts, simply changing the question passed as a parameter. This is the same behavior of confirm()
Rather than waiting for the user's input and then returning from the function, it is more common in JavaScript to provide a callback function that will be called when the action you're waiting for is complete. For example:
myCustomConfirm("Are you sure?", function (confirmed) {
if (confirmed) {
// Whatever you need to do if they clicked confirm
} else {
// Whatever you need to do if they clicked cancel
}
});
This could be implemented along the lines of:
function myCustomConfirm(message, callback) {
var confirmButton, cancelButton;
// Create user interface, display message, etc.
confirmButton.onclick = function() { callback(true); };
cancelButton.onclick = function() { callback(false); };
}
If using jQuery, why not implement jQueryUI? And use the Dialog function as follows:
as a 2 part:
HTML
<div id="dialog-confirm" title="ALERT">
<p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>Are you sure?</p>
</div>
Script
$( "#dialog-confirm" ).dialog({
resizable: false,
modal: true,
buttons: {
"OK": function() {
$( this ).dialog( "close" );
},
Cancel: function() {
$( this ).dialog( "close" );
}
}
});
All in Script:
$(function() {
$("<div />").attr("id", "dialog-confirm").append(
$("<p />").text('Are you sure?').css("text-align", "center").prepend(
$("<span />").addClass("ui-icon ui-icon-alert").css({
float: 'left',
margin: '0 7px 20px 0'
})
)
).dialog({
resizable: false,
modal: true,
title: "ALERT",
buttons: {
"OK": function() {
answer=1;
$(this).dialog("close");
},
"Cancel": function() {
answer=0;
$(this).dialog("close");
}
}
});
});
jsFiddle
This really should be done with a callback. The closest thing to what you're after would be to use a publish and subscribe model with some custom events.
To do so:
When a user clicks the yes button, trigger a custom event called clickedYes. Do the same for "no"
$('#yesbtn').click(function(){
$(document).trigger('clickedYes');
});
$('#nobtn').click(function(){
$(document).trigger('clickedNo');
});
Now we need to "listen" or subscribe for those events and execute the appropriate action in context.
Lets create a hypothetical situation: Your user clicks delete and you want to confirm that choice.
First setup what you want to happen if they click yes:
$(document).unbind('clickedYes'); //Unbind any old actions
$(document).bind('clickedYes',function(){
//Code to delete the item
//Hide the popup
});
then what you want to happen if they click no:
$(document).unbind('clickedNo'); //Unbind any old actions
$(document).bind('clickedNo',function(){
//Hide the popup and don't delete
});
So we've setup actions that are listening for clickedYes or clickedNo. Now we just need to show the user the popup so that they have to click yes or no. When they do, they'll trigger the events above.
so your myConfirm() function will just do the following:
function myConfirm(msg){
//change the message to 'msg'
//Show the popup
}
So the order would be:
Bind triggers for the custom events to the yes and no buttons
Before prompting - unbind any old actions and attach your new ones
Present the user with a popup that'll cause them to trigger on of your actions.
This will allow you to call the function like this myConfirm('Are you sure'); It's not quite what you're after...but I don't think it's possible to do exactly what you want.