I have some jquery that looks like this,
$('.career_select .selectitems').click(function(){
var selectedCareer = $(this).attr('title');
$.ajax({
type: 'POST',
url: '/roadmap/step_two',
data: 'career_choice='+selectedCareer+"&ajax=true&submit_career=Next",
success: function(html){
$('.hfeed').append(html);
$('#grade_choice').SelectCustomizer();
}
});
});
My problem is that if the user keeps clicking then the .hfeed keeps getting data appended to it. How can I limit it so that it can only be clicked once?
Use the one function:
Attach a handler to an event for the elements. The handler is executed at most once per element
If you wanted the element to only be clicked once and then be re-enabled once the request finishes, you could:
A) Keep a state variable that updates if a request is currently in progress and exits at the top of the event if it is.
B) Use one, put your code inside a function, and rebind upon completion of request.
The second option would look like this:
function myClickEvent() {
var selectedCareer = $(this).attr('title');
var that = this;
$.ajax({
type: 'POST',
url: '/roadmap/step_two',
data: 'career_choice='+selectedCareer+"&ajax=true&submit_career=Next",
success: function(html){
$('.hfeed').append(html);
$('#grade_choice').SelectCustomizer();
},
complete: function() {
$(that).one('click', myClickEvent);
}
});
}
$('.career_select .selectitems').one('click', myClickEvent);
You can either use a global variable like
var added = false;
$('.career_select .selectitems').click(function(){
if(!added) {
// previous code here
added = true;
}
});
or use .one("click", function () { ... }) instead of the previous click function to execute the handler at most once per element. See http://api.jquery.com/one/ for more details.
Related
So, I have a jQuery AJAX call that gets data from the server (some text, some links).
Inside AJAX success callback function I got a .on that is bind to <a> that load for me next page and get me the text of the clicked link (let's say stackoverflow.com).
The problem starts here because in the newly loaded page I got anchors...
After every click on anchor links I got new .text() value.
$.ajax({
url: url,
type: type,
dataType: dataType,
success: function(data){
$('.container').append(data);
$('.container').on('click', 'a', function(e){
e.preventDefault();
var clickLinkName = $(this).text();
console.log(clickLinkName);
$('.container').load($(this).attr('href'));
});
}
});
I would like to know how to lock clickLinkName variable. OR any other way to save only first hit.
I think this would do the trick:
$.ajax({
url: url,
type: type,
dataType: dataType,
success: function(data) {
$(".container").append(data);
var clickLinkName; // Declared here.
$(".container").on("click", "a", function(e) {
e.preventDefault();
// If not initialized, initialize.
if(!clickLinkName) {
clickLinkName = $(this).text();
}
console.log(clickLinkName);
$(".container").load($(this).attr("href"));
});
}
});
That would save only the first value in the variable clickLinkName. This answers your question, but I'm sure there are better ways of doing this.
I know about event.preventDefault() and event.stopImmediatePropagation(). But it doesn't work for me. In my case I have such ajax call:
$('#templateConfirmDialog').on('show.bs.modal', function (event) {
$(this).find('.modal-yes').click(function(){
var form = form2js('search_form', '.', true, function (node) {}, false);
var requestData = JSON.stringify(form, replacer);
var $formErrors = $('.search_form').find('.alert-danger');
event.preventDefault();
event.stopImmediatePropagation();
$.ajax({
type: 'POST',
contentType : "application/json",
url: '/fraud/template/testCreate',
data: requestData,
dataType: 'json',
success: function (data) {
$formErrors.text('');
//if no errors just reload
if (data === undefined || data.length === 0) {
location.reload();
}
else {
//else bind error messages
data.forEach(function(error) {
$('#new-' + error.field + '-error').text(error.defaultMessage);
})
}
}
});
});
My problem is that the ajax call is prevented as much times as I made attempts to input data. If I entered invalid data once - ajax is called twice. If twice - 3 times. What may be a reason of such behavior?
Every time this event happens:
$('#templateConfirmDialog').on('show.bs.modal', function (event) {
You bind a new click event handler:
$(this).find('.modal-yes').click(function(){
So if you show.bs.modal twice, then you have two click event handlers both submitting the AJAX request. Instead, just bind the click event handler once to the target clickable element, instead of binding it every time the modal is displayed.
Replace this:
$('#templateConfirmDialog').on('show.bs.modal', function (event) {
$(this).find('.modal-yes').click(function(){
//...
});
});
With this:
$('#templateConfirmDialog').find('.modal-yes').click(function(){
//...
});
Or, if that element is dynamically added to the DOM, this:
$(document).on('click', '#templateConfirmDialog .modal-yes', function(){
//...
});
That way there's just a single click event handler created when the page loads, rather than adding a new handler every time you display the modal.
So I'm just getting started with event delegation and I'm still fairly confused by it but here goes:
I have a button which adds a rating in ajax, once clicked again I'd like it to remove the rating, here's the code with annotations (and some parts removed to make it look more clear).
$(document).on("click", '.add_rating', function() {
l.start();
var input = $(this).prev().children('.my_rating');
var score = input.val();
var what_do = input.attr('action_type');
var cur_average = $('.current_average').val();
var data = {};
data.score = score;
data.media_id = <?php echo $title_data->media_id; ?>;
data.what_do = what_do;
$.ajax({
dataType: "json",
type: 'post',
url: 'jquery/actions/add_remove_rating',
data: data,
success: function(data) {
if (data.comm === 'success') {
//do some other stuff there, irrelevant
$('.ladda-button').removeClass('btn-primary');
$('.ladda-button').removeClass('btn-sm');
$('.ladda-button').addClass('btn-danger btn-xs');
$('.ladda-label').html('Remove');
$('.ladda-button').addClass('remove_rating'); <-- add the remove rating class I want to call if the button is clicked again
input.attr('action_type', 'remove_rating');
l.stop();
}
}
});
$('.remove_rating').on('click', function() { <-- this doesn't work, why?
alert('remove was clicked');
});
});
I can't seem to trigger this:
$('.remove_rating').on('click', function() { <-- this doesn't work, why?
alert('remove was clicked');
});
Any help appreciated!
Edit: on a side note, I don't actually need this to work as php figures out if we're removing or adding a score based on the action_type attribute. I just wanted to find out why it's not triggering.
change your code to:
$(document).on("click", '.add_rating', function() {
l.start();
var input = $(this).prev().children('.my_rating');
var score = input.val();
var what_do = input.attr('action_type');
var cur_average = $('.current_average').val();
var data = {};
data.score = score;
data.media_id = <?php echo $title_data->media_id; ?>;
data.what_do = what_do;
$.ajax({
dataType: "json",
type: 'post',
url: 'jquery/actions/add_remove_rating',
data: data,
success: function(data) {
if (data.comm === 'success') {
//do some other stuff there, irrelevant
$('.ladda-button').removeClass('btn-primary');
$('.ladda-button').removeClass('btn-sm');
$('.ladda-button').addClass('btn-danger btn-xs');
$('.ladda-label').html('Remove');
$('.ladda-button').addClass('remove_rating'); <-- add the remove rating class I want to call if the button is clicked again
input.attr('action_type', 'remove_rating');
l.stop();
$('.remove_rating').on('click', function() { <-- this doesn't work, why?
alert('remove was clicked');
});
}
}
});
});
EXPLANATION:
first have a look here: Understanding Event Delegation.
event delegation is used when you need to create event handlers for elements that do not exist yet. you add a .remove_rating class to elements dynamically, however you are trying to attach a handler to elements with the above mentioned class before you even attach it.
you are attaching the class when the asynchronous ajax call returns, in the success function, however your event handler block is being processed right after you send the ajax, and not after the ajax returns (ajax is async rememeber?). therefore, you need to wait until the ajax returns and the elements are created, and only then attach the handler to them.
alternatively, using event delegation, you can attach the handler to the document, like you did in the following line:
$(document).on("click", '.add_rating', function() {
it means, that you attach the handler to the document, and whenever any element ON the document is clicked, if that element has the class '.add_rating' then execute the handler.
therefore, you may attach another handler to the document to monitor for clicks on elements with the .remove_rating class as follows:
$(document).on("click", '.remove_rating', function() {
this is called event delegation, because you delegate the event to a parent element.
Because class was added after click event initialised. You need to use live event handlers, like this:
$( document ).on('click', '.remove_rating', function() {
In this case .remove_rating click handler will work on dynamically created elements and on class name changes.
I have this link:
$('.popup-window').click(function (e) {
e.preventDefault();
$.ajax({
...
})
});
which is a .NET LinkButton (a link that call a javascript, not a real href). I want to prevent Default if ajax return some (let say, false). Else, if true, continue with that link handler.
How can I do it?
P.S. I need that e.preventDefault(); at the beginning, else .NET handler will act immediatly.
You can use the __doPostBack() js function to trigger the postback in your AJAX callback.
The only thing is that you need to pass in the id of the control causing the postback, e.g.
__doPostBack('btnPopup', null);
you can see more on this function in this question: How to use __doPostBack()
I think I understand what you're looking for.
Here's my idea on it: use a data attribute on the DOM element to decide weither default event should be prevented or not. Initially, the event is prevented but the ajax has the power to "unlock?" it, then fire it again. It's a little bit of custom work but it may do the trick:
var $popupWindow=$('popup-window');
// initially "tell" the LinkButton to prevent default
$popupWindow.data('prevent-default', 1);
// the click event (initially prevents default)
$popupWindow.click(function(e){
var $this=$(this);
if ($this.data('prevent-default')==0) { // if "unlocked"
// "lock" it again (default isn't prevented)
$this.data('prevent-default', 1);
} else { // if "locked"
// default is prevented
e.preventDefault();
// test if it should be unlocked
$.ajax({
// ...
}).done(function(data){
if (data.length>0 && data.response==false) {
// set the attribute so it shouldn't prevent default
$this.data('prevent-default', 0);
// trigger this click (should let the event fire completely)
$this.trigger('click');
}
});
}
});
UPDATE:
An alternative could be to add a Page Method.
(See: Using jQuery to directly call ASP.NET AJAX page methods)
This would reduce the mechanics to somethink like this:
$('popup-window').click(function(e){
e.preventDefault();
$.ajax({
// ...
}).done(function(data){
if (data.length>0 && data.response==false) {
$.ajax({
type: "POST",
url: "YourPage.aspx/YourMethod",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
// Replace the div's content with the page method's return.
$("#Result").text(msg.d);
}
});
}
});
});
$('.popup-window').click(function (e) {
data = '?sample=1' //serialized data here
callback = function(json){
if(json.returnVar!=true){ //check if returnVar is not true
e.preventDefault(); //prevent redirect if not true
}
};
$.ajax({
type: 'POST',
url: "../ajaxcall.php", //the url to call for ajax here
data: data,
success: callback,
dataType: 'json'
});
});
Try this, let me know if you can't understand the code
Doing following in jQuery:
$('#signupbox1').on('click', '#signup1', function() {
var str = $('#signupform').serialize();
// make it look like a waiting button
$('#signup1').addClass("btn_wait");
var btn_val = $('#signup1').val();
$('#signup1').val('');
$.ajax({
type: "POST",
url: "signup_step1.php",
data: str,
success: function(msg) {
//doing stuff here
$('#signup1').removeClass("btn_wait");
$('#signup1').val(btn_val);
}
});
});
How could you disable the click event as well till you receive an answer from the ajax call? So, when you click on the button it not only "transforms" to a waiting button because of the added class, but also the click event will be "paused"... is this possible?
Thank you very much in advance!
$('#signupbox1').on('click', '#signup1', function() {
var str = $('#signupform').serialize();
// make it look like a waiting button
var btn_val = $('#signup1').val();
$('#signup1').addClass("btn_wait").val('').unbind('click');
$.ajax({
type: "POST",
url: "signup_step1.php",
data: str,
success: function(msg) {
$('#signup1').removeClass("btn_wait").val(btn_val);
},
complete: function() {
$('#signup1').bind('click'); // will fire either on success or error
}
});
});
You can add a flag to denote "currently loading". You can use anything like a variable, property or attribute. In this example, I use jQuery .data()
Also, it's advisable that you use submit event instead of adding a click handler to the submit button when you submit a form.
$('#signupform').on('submit', function() {
var form = $(this),
loading = form.data('loading'), //check loading status
str, button, val;
//if not loading
if(!loading){
//set loading to true
form.data('loading',true);
str = form.serialize();
button = $('#signup1', form);
val = button.val();
// make it look like a waiting button
button
.addClass("btn_wait");
.val('');
$.ajax({
type: "POST",
url: "signup_step1.php",
data: str,
success: function(msg) {
//remove loading state
form.data('loading',false);
//return button to normal
button
.removeClass("btn_wait");
.val(val);
}
});
}
});