Perform an action after trigger('click') finishes firing? - javascript

I manage a SharePoint site and have limited access to the underlying code; I can, however, manipulate things after the page loads via JavaScript. Have been using jQuery and SPServices.
I have a custom button I am adding to a form; it overrides the standard "save" button on the page, so I can perform some other ajax stuff prior to saving/closing. This works fine:
$('#the_save_button').hide();
$("#my_custom_save_button").click(function() {
// do some custom stuff first
$('#the_save_button').trigger('click'); //
window.close();
}
The item saves and the window.close() fires. Great! Now, though, I would rather not close the window but set the window.location.href ... however, when I do that, the page is getting redirected before the trigger('click') is finished firing and my item isn't saving:
$('#the_save_button').hide();
$("#my_custom_save_button").click(function() {
// do some custom stuff first
$('#the_save_button').trigger('click'); //
window.location.href = "/my/new/url.aspx";
}
I've tried using window.setTimout but the $('#the_save_button').trigger('click') has a built-in redirect itself ...
Any ideas on how I can work around this?

Yes, just have your click handler return a deferred object and use it to decide when to redirect.
$("#the_save_button").click(function(e){
e.preventDefault();
return $.ajax({...});
});
Now you can do this:
$("#my_custom_save_button").click(function() {
// do some custom stuff first
$('#the_save_button').triggerHandler('click').done(function(){
window.location.href = "/my/new/url.aspx";
});
});
Note: using triggerHandler instead of trigger in this case is important, triggerHandler allows you to use the returned jqXHR object.

Related

Warn user about unsaved changes to a form, when a form is being replaced during an AJAX call?

I'm new to Javascript and JQuery, and I'm implementing a warning to users that displays when they have made unsaved changes to a form's input/select/textarea elements if they navigate away from a page. I currently have the following which works fine when they leave a static form page:
/*
* Warn users when leaving a page with unsaved content, watches elements: (input, textarea, select) unless
* they are tagged with the "noWarning" class
*/
$(document).ready(function() {
$(document).on('change', 'input:not(.noWarning),textarea:not(.noWarning),select:not(.noWarning)', function () {
window.onbeforeunload = function(e) {
return 'You have unsaved changes';
};
});
});
The only page where it does not work, is in our main editing page. This page, unlike the others, has multiple tabs for editing different aspects of an item, which when clicked, trigger an AJAX call which replaces the content div with the appropriate form for editing the different aspect.
No warning dialog is displayed when a user clicks on a tab though, so any unsaved changes to the input are lost.
My intuition is that because the url is not changing, onBeforeUnload() is not executing. So I would have to check for any changes directly in the function which handles the AJAX call for replacing the form when a tab is clicked:
function clickedTabbedMenu() {
// This function replaces the content div with a new div and form
}
So my question is, how do I go about checking if any changes have been made to the elements in the current form before I replace the content div with another??? Can I directly call the "change" event listener for a true/false??? Or perhaps a different approach to handle this page's warning messages?
Any help is appreciated
Attach a change event handler to all the elements of the form. Have a variable outside the handler's scope dirty (or even a data on the form element) be set to false when a form is loaded, and true on every change event. Then, before replacing the form, check if dirty.
This would also be a good strategy for your non-AJAX pages as well - instead of setting the whole onBeforeUnload each time an element changes, just set onBeforeUnload once, and check if dirty inside it. This makes handling your AJAX and non-AJAX pages very similar.
EDIT: Untested because it's late and I need bed, but basically:
$(document).ready(function() {
var dirty = false;
$(document).on('change', 'input:not(.noWarning),textarea:not(.noWarning),select:not(.noWarning)', function () {
dirty = true;
});
function checkDirty() {
if (dirty) {
alert('You have unsaved changes');
return false;
}
return true;
}
// for non-AJAX pages
window.onbeforeunload = function(e) {
return checkDirty();
};
// for AJAX pages
$('.ajax_navigation_tab').on('click', function() {
if (!checkDirty()) {
// do the ajax thing
dirty = false;
}
});
});
I would try checking for and calling window.onbeforeunload() in your ajax script.
If it exists and returns a string, use it as an error message and halt the operation :)

JQuery "undo" an action by calling another function when back clicked

Is there a way to "undo" a function executed by jQuery when the back button is clicked? For example, my function that I want to execute is named doSomething:
function doSomething(button) {
...clicking the button does something...
}
And I have an undo function that undoes the above function, undoDoSomething:
function undoDoSomething(button) {
....undoes the doSomething function...
}
How do I call the function for the button and then if the back button is clicked right after I execute the function, I can call the undoDoSomething function to undo that function?
I know jQuery History goes back to a previous page saved in history but how do I use that to call a function?
the history api makes this easy: http://jsfiddle.net/Z9dRY/
html:
<button>Increase</button>click back button to decrease
<span id="counter">0</span>
js:
$("button").click(function(){
var count = +$("#counter").text() + 1;
history.pushState({count:count});
$(counter).text(count);
})
$(window).on("popstate",function(e){
if (e.originalEvent.state)
$(counter).text(e.originalEvent.state.count);
})
On each action, add to the history, and then each back button click will undo each change (of course, you have to develop the undo part. In this case, i just stored what the count should be changed to at that point and changed it.)
https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history
Take note of the browser support, this code will work in all modern browsers and IE10+. oldIE will need a workaround either using an iframe or a hash in the url.
Here's the same example with an added decrease button to show that it doesn't really change anything: http://jsfiddle.net/Z9dRY/1/ it even inherantly supports the forward button(redo).
Update: fixed losing initial state: http://jsfiddle.net/Z9dRY/2/
You could call your undo function on the window.unload event
window.onbeforeunload = function(e) {
undoDoSomething();
};
You can usue beforeunload that is executed when leaving the page
var called = false;
function doSomething(button) {
called = true;
}
$(window).on('beforeunload',function(e){
if(called){
//call your function here
undoDoSomething()
}
});

Can't refresh reCaptcha on JQuery Ajax return

I'm having a devil of a time trying to get Ajax to automatically refresh on a JQuery AJAX callback. I have a comment box with the messages being refreshed posted immediately upon validation of reCaptcha and it would be nice if the reCaptcha could refresh automatically in case someone wants to add another comment immediately afterward. Here's my return function:
$.post(url, formData, function(data) {
if (returnString.match(/^Error:/)) {
$("#interactionResults").html(data).show().fadeOut(6000);
}
else if (postNumber == 0) {
$('#newCommentDisplay').html(returnString).show();
$.post("http://www.google.com/recaptcha/api", "Recaptcha:reload()");
}
When I use:
$.post("http://www.google.com/recaptcha/api", "Recaptcha:reload()");
I get an error:
XMLHttpRequest cannot load http://www.google.com/recaptcha/api. Origin http://localhost:8888 is not allowed by Access-Control-Allow-Origin.
Fair enough, so I try to change that line with this one:
$('#recaptcha_reload_btn').trigger('click');
and still nothing is happening. Does anyone know what's going on?
in my html I have :
<div class="g-recaptcha" id='recaptcha' data-sitekey="xxxxxxxxxx"></div>
I use grecaptcha.reset();
example:
if (typeof $('#recaptcha') != "undefined") {
grecaptcha.reset();
}
Use
jQuery("#recaptcha_reload").click();
"#recaptcha_reload", the image itself, is the trigger. #recaptcha_reload_btn will NOT work, because the a-tag is NOT the trigger.
Recaptcha.reload();
( Recaptcha is already loaded )
if you are using new recaptcha 2.0 use this:
for code behind:
ScriptManager.RegisterStartupScript(this, this.GetType(), "CaptchaReload", "$.getScript(\"https://www.google.com/recaptcha/api.js\", function () {});", true);
for simple javascript
<script>$.getScript(\"https://www.google.com/recaptcha/api.js\", function () {});</script>
You have not bound a click handler to your element. From the jQuery docs:
.trigger( eventType [, extraParameters] )
Description: Execute all handlers and behaviors attached to the
matched elements for the given event type.
If you have not attached a handler to your element before calling trigger, there is no click handler to execute.
edit:
When you write $('#recaptcha_reload_btn').bind('click'); you actually set up a click handler, but one that does nothing. You have to tell that clickhandler what to do:
$('#recaptcha_reload_btn').bind('click',function() {
alert('you just clicked me');
};
If you do not set up a callback handler, the event is just registered but does not trigger any action. Combine this with the solution from this question Reload an iframe with jQuery and you should have your recaptcha doing what you want:
$('#recaptcha_reload_btn').bind('click',function() {
var iframe = document.getElementById('#recaptcha'); //use your own selector here!
iframe.src = iframe.src;
};
$( "#recaptcha_reload_btn" ).click();

anchor tag scrolls to top after onclick event return false doesn't work

I have a click event that will not return false after I have called my ajax function i was wondering how I can get around this. I have used e.preventDefault() which works so that the url doesn't add a hash but when I use return false after my ajax function it doens't work but If I do it the other way round it works but cancels out my ajax call.
Click me
$('a').click(function(e) {
getProducts(..., ...., ....) //my ajax function
e.preventDefault() // doesn't work
return false; doesn't work either
});
cancel the default action using preventDefault function.
$('a').click(function(e) {
getProducts(..., ...., ....) //my ajax function
e.preventDefault();
});
a few thoughts here. #1 e.preventDefault() only works if you pass in the event via function(e) {...} you aren't which would be a problem. #2 From what you've described the only thing I can suggest is that you've got a javascript error which leads to thought #3...If you want more help you're going to have to give us more to go on

Making an Ajax form from an Ajax request in jQuery

The client is making a request to the server.
I need to take part of that request, and make the form button work with Ajax.
This piece of code works perfectly for links:
var pagination_render = function() {
var pagination = $('.pagination a');
pagination.each(function() {
$(this).click(function(event) {
load_server(this.href, '.houseindex');
return false;
});
});
};
pagination_render();
I tried numerous things for making the Ajax button work, and this is one of the tries:
var contact_user = function () {
$('.expanded').find('#submit').each(function() {
$(this).unbind('click');
});
$('.expanded').each(function() {
$(this).find('#submit').click(function(event) {
form_submit($(this).parent(), '.contactuser .msg');
return false;
});
});
}
Whenever there is a successful Ajax call, it goes through all of the expanded items, and then binds a click event.
Now, sometimes this code works, and sometimes it doesn't.. When it doesn't work, it disables other events (toggle links) I have set up.
It seems as if I need to wait a few ms for it to load the component into the DOM.. Do I?
So I get that when you call contact_user you:
First unbind any previous binded click events from the submit button. I see one possible problem there and is that you are looking for an id of #submit. You should only have one id in a single page. Therefore you only need to use $('#submit').each(...) or if you have several submit buttons in the page either use a class if there are several submit buttons inside an .expanded item or just use $('.expanded :submit')
Adding a custom event when clicking the submit button. Same thing, you can simplify this by $('.expanded :submit') or if you truly only have one button with an id of submit (quite confusing). Go with $('#submit').
In conclusion:
var contact_user = function(){
$('.expanded :submit').unbind('click');
$('.expanded :submit').click(function(){
form_submit($(this).parent(), '.contactuser .msg');
return false;
});
};
the :submit selector will select all <input type="submit" />.

Categories