JQuery conditional preventDefault() firing when not called - javascript

I have the following script I've written.
<script>
$(document).ready(function(){
$('a').data('loop',true);
$('body').on('click', 'a', function(event){
console.log($(this).data('loop'));
if ($(this).data('loop') == 'true') {
console.log('hit');
event.preventDefault();
caller = $(this);
$(this).data('loop',false);
var linkref = $(this).attr('href');
var linkpos = $(this).offset();
var screenwidth = $(window).width();
var json_data = JSON.stringify({linkref: linkref, linkpos: linkpos, screenwidth: screenwidth});
$.ajax({
url: "content/submitcontenthandler?handler=core/_dashboard&method=tracking_ping",
method: "POST",
data: "json=" + json_data,
complete: function (jqXHR, status) {
console.log(status);
console.log(caller);
$(caller).click();
}
});
} else {
console.log(event.isDefaultPrevented());
console.log('miss');
$(this).data('loop',true);
}
});
});
</script>
It works, sends me the details I want etc etc. BUT!!!
When I click a link, It fires off the details to me via Ajax, then it's meant to "click" the event again, which it does! but the event does not fire it's normal action. So When clicking a link to another page, I would go to that other page... that's not happening.
If I comment out the line event.preventDefault(); Then the event fires as I would expect...
So to me it looks like the event.preventDefault is executing even though it's not meant to be during the second call...
Sorry if this is a bit complicated to understand. I don't quite understand what's happening myself.
Is it possibly a bug, or is there something that I've done that has caused this?
I didn't think I could, but I have successfully made a jsfiddle for this.
https://jsfiddle.net/atg5m6ym/2001/

You can try this and not worry about the "loop" anymore:
$(document).ready(function () {
$('body').on('click', 'a', function (event) {
event.preventDefault();
var caller = $(this);
var linkref = $(this).attr('href');
var linkpos = $(this).offset();
var screenwidth = $(window).width();
var json_data = JSON.stringify({linkref: linkref, linkpos: linkpos, screenwidth: screenwidth});
$.ajax({
url: "content/submitcontenthandler?handler=core/_dashboard&method=tracking_ping",
method: "POST",
data: "json=" + json_data,
complete: function (jqXHR, status) {
console.log(status);
console.log(caller);
window.location.href = linkref; // Redirect happens here
}
});
});
});
UPDATE
There's a few issues to note here:
1) Some links don't require a redirect (as noted, bootstrap model links that control showing/hiding or within document anchors
To correct this it really depends on the case. Usually bootstrap adds specific classes or data attributes to the links so you can do something like.
$('body').on('click', 'a:not(list of things to exclude)'..
Personally I'd instead define the links I wanted to track as :
<a href=<link> data-tracked='true'...
<script>
$('body').on("click","a[data-tracked='true']"...
Or if you want to track most links with a few exceptions you can:
<a href=<link> data-tracked='false'...
<script>
$('body').on("click","a:not([data-tracked='false'])"...
Or more generally:
<script>
$('body').on("click","a", function () {
if ($(this).attr("data-tracked") == "false" || <you can check more things here>){
return true; //Click passes through
}
//Rest of the tracking code here
});

The following if statement will return true whenever the data-loop attribute exists against an element, regardless of it's value:
if ($(this).data('loop')) {
It needs to be changed to check for the value:
if ($(this).data('loop') == 'true') {
When you assign anything to be the value of an element attribute it becomes a string and, as such, requires a string comparison.

Event.preventDefault() is not being executed second time.
Link redirection happens when the method is completed.
So in your case redirection will happen when complete method of ajax call is completed.
lets say, we have event1 and event2 object in the code. event1 is the object in the ajax call method and event2 is the event object in recursive call (second call) method.
so when link is clicked second time , we still have complete method to be executed. as soon as it returns to the complete method of ajax call, it finds the event1 is having preventDefault property true and it does not redirect.

Try this ;)
$(document).ready(function(){
$('body').on('click', 'a', function(event){
event.preventDefault();
var caller = $(this);
var linkref = $(this).attr('href');
var linkpos = $(this).offset();
var screenwidth = $(window).width();
var json_data = JSON.stringify({
linkref: linkref,
linkpos: linkpos,
screenwidth: screenwidth
});
$.ajax({
url: "content/submitcontenthandler?handler=core/_dashboard&method=tracking_ping",
method: "POST",
/* To temprary block browser; */
async: false,
data: "json=" + json_data,
complete: function(jqXHR, status){
/* add class **ignore** to a element you don't want to redirect anywhere(tabs, modals, dropdowns, etc); */
if(!caller.hasClass('ignore')){
/* Redirect happens here */
window.location.href = linkref;
}
}
});
});
});

Related

javascript/jquery doesn't work in ajax

I have php page "Home.php", that present user posts(using ajax).
This is how I get the posts:
<script type="text/javascript">
function loadmore()
{
var val = document.getElementById("result_no").value;
var userval = document.getElementById("user_id").value;
$.ajax({
type: 'post',
url: 'fetch.php',
data: {
getresult:val,
getuserid:userval
},
success: function (response) {
var content = document.getElementById("result_para");
content.innerHTML = content.innerHTML+response;
// We increase the value by 2 because we limit the results by 2
document.getElementById("result_no").value = Number(val)+10;
}
});
}
</script>
<div id="content">
<div id="result_para">
</div>
</div>
In every post, there is a like button(which also uses ajax). This is how I save the likes:
<script type="text/javascript">
function likethis(likepostid)
{
$.ajax({
type: 'post',
url: 'fetchlikes.php',
data: {
getpostid:likepostid
},
success: function (response) {
}
});
}
</script>
Before I used ajax to present posts, all worked well. But now when I press the like button, it DOES save the like, BUT the javascript/jquery doesn't work. I tried to make alert when I pressed the LIKE button, but it didn't work.
This is the index.js code(the javascript). It add +1 likes, when the user press the button:
$('.btn-counter_likecount').on('click', function(event, count) {
event.preventDefault();
//alert("hello");
var $this = $(this),
count = $this.attr('data-count'),
active = $this.hasClass('active'),
multiple = $this.hasClass('multiple-count_likecount');
$.fn.noop = $.noop;
$this.attr('data-count', ! active || multiple ? ++count : --count )[multiple ? 'noop' : 'toggleClass']('active');
});
EDIT fetchlikes.php:
<?php
mysql_connect('localhost','root','');
mysql_select_db('blabla');
$postid=$_POST['getpostid'];
mysql_query("UPDATE user_post SET likes_count=likes_count+1 WHERE post_id='$postid'");
?>
Because your posts are being loaded dynamically, the javascript where you bind the event is running before the posts are actually loaded, thus the buttons don't exist when you try to bind the event. You can use delegated events in jQuery to handle this.
Your previous code
$('.btn-counter_likecount').on('click', function(event, count) {
....
});
New Code
$('#result-para').on('click','.btn-counter_likecount',function(event, count) {
....
}
This way the event will actually be bound to a parent element that already exists when jQuery's ready() function runs. This way, the event handler checks for matching elements when the event is fired rather than when the event is bound.
For further reading, look into jQuery's delegated events

jquery unable to show and hide an element

I have div element as
<div class="preview-image hide"><img src="{{STATIC_URL}}ui-anim_basic_16x16.gif"></div>
The hide class belongs to Twitter Bootstrap 2.3.2, the preview-image basically adds some styling to the element and used as handle for JavaScript.
I have jQuery code as below where
$loading.show() and $loading.hide() are not working.
The surprising this is when I run $preview.parent().find('.preview-image').show() from console, its working!!
(function($) {
$(document).ready(function() {
var SET_TIME = 6000;
$('[data-preview]').click(function() {
var $this = $(this);
var $preview = $('#' + $this.data('presponse'));
var $loading = $preview.parent().find('.preview-image');
$loading.show();
$.ajax({
});
$loading.hide();
});
});
})(window.jQuery);
Because $.ajax() is an asynchronous call, the $loading.hide() is being called (as it appears to the user) immediately after the $loading.show(). In order to circumvent this, you should make the $loading.hide() call after your AJAX call is complete. One way to do this is:
var $loading = $preview.parent().find('.preview-image');
$loading.show();
$.ajax({
}).always(function() {
$loading.hide();
});
Is the issue that it's hiding straight away? I think the hide needs to be within a success function of the AJAX call rather than being after it.
Eg.
$.ajax({
success: function() {
$loading.hide();
}
});

Creating ajax pagination

I am trying to do an ajax pagination with the following code:
// AJAX pagination
$(".pages .prev").live('click', function(event) {
event.preventDefault()
var current_page = parseInt(getParameterByName('page'))-1;
$.get('/ajax/financial_page/', {'page': current_page}, function(response) {
$(".content table").replaceWith(response)
});
})
And in my view function:
def financial_page(request):
"""
Returns a single financials page, without extra HTML (used in AJAX calls).
"""
page = int(request.GET.get('page', 1))
if request.user.is_superuser:
fs = FinancialStatements.objects.order_by('-date', 'statement_id')
else:
up = request.user.get_profile()
providers = up.provider.all()
fs = FinancialStatements.objects.filter(provider__in=providers).order_by('-date', 'statement_id')
fs_objects, current_page_object, page_range = paginator(request, objects=fs, page=page, number_per_page=30)
data = { 'fs':fs_objects,
'page_range': page_range,
'current_page': current_page_object,
}
page = render_to_string('financial_section.html', data, RequestContext(request))
return HttpResponse(simplejson.dumps([page]))
However, there are two problems I'm running into. The first is that the response is not really HTML, and has a bunch of n\t\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\, etc. Also, I'm having trouble keeping track of the current page/changing the url as needed. How would I build a functional ajax pagination here?
Update: I figured out the first one, by doing response = $.parseJSON(response);. How would I keep track of which page I am on though?
To keep track of the page, you can increment/decrement a variable on click with your AJAX function. Try this:
var counter="0";
$(document.body).on('click', ".pages .prev, .pages .next", function(event) {
if($(this).hasClass('prev')
counter--;// <--decrement for clicking previous button
else if($(this).hasClass('next')
counter++; // <--increment for clicking next button
event.preventDefault()
$.get('/ajax/financial_page/', {'page': counter}, function(response) {
$(".content table").replaceWith(response)
});
})
I would also not use live method as it is deprecated as of jQuery 1.7. It has been replace by the on method. See the jQuery on() API here: http://api.jquery.com/on/
Check this tutorial about "Ajax Scroll Paging Using jQuery, PHP and MySQL", it may simplify your job:
http://www.bewebdeveloper.com/tutorial-about-ajax-scroll-paging-using-jquery-php-and-mysql
Here is the essential from:
var is_loading = false; // initialize is_loading by false to accept new loading
var limit = 4; // limit items per page
$(function() {
$(window).scroll(function() {
if($(window).scrollTop() + $(window).height() == $(document).height()) {
if (is_loading == false) { // stop loading many times for the same page
// set is_loading to true to refuse new loading
is_loading = true;
// display the waiting loader
$('#loader').show();
// execute an ajax query to load more statments
$.ajax({
url: 'load_more.php',
type: 'POST',
data: {last_id:last_id, limit:limit},
success:function(data){
// now we have the response, so hide the loader
$('#loader').hide();
// append: add the new statments to the existing data
$('#items').append(data);
// set is_loading to false to accept new loading
is_loading = false;
}
});
}
}
});
});
Try using the javascript String.replace() method:
// AJAX pagination
$(".pages .prev").live('click', function(event) {
event.preventDefault()
var current_page = parseInt(getParameterByName('page'))-1;
$.post('/ajax/financial_page/', {'page': current_page}, function(response) {
response = response.replace(/\n/g,'<br>').replace(/\t/,' ');
$(".content table").replaceWith(response)
});
})
jQuery.get(url, [data], [callback], [type])
type :xml, html, script, json, text, _default。
how about trying to define the last parameter as "html" ?

jquery click event

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.

Javascript Jquery doesn't work. $(this)

$(document).ready(function() {
$(".delete_user_button").click(function(){
var username_to_delete = $(this).attr('rel');
$.ajax({
type:"POST",
url:"/delete/",
data:{'username_to_delete':username_to_delete},
beforeSend:function() {
$(this).val("Removing...");
},
success:function(html){
$("div.delete_div[rel=" + username_to_delete + "]").remove();
}
});
return false;
});
});
Why doesn't $(this).val() work?
I'm trying to change the text of the button when the user clicks remove.
In your event handler (beforeSend), this refers to the XMLHttpRequest object used for the ajax call, not your original this of the click event handler. You should "capture" it in a variable first:
$(document).ready(function() {
$(".delete_user_button").click(function(){
var element = $(this);
var username_to_delete = element.attr('rel');
$.ajax({
type:"POST",
url:"/delete/",
data:{'username_to_delete':username_to_delete},
beforeSend:function() {
element.val("Removing...");
},
success:function(html){
$("div.delete_div[rel=" + username_to_delete + "]").remove();
}
});
return false;
});
});
This mechanism is called "closures". For an interesting explanation of this, check this link:
http://www.bennadel.com/blog/1482-A-Graphical-Explanation-Of-Javascript-Closures-In-A-jQuery-Context.htm
Without more knowledge about the context or analysing the script itself: Keep in mind that, in certain environments, it might be possible that $ itself does not work and needs to be replaced with jQuery - I've seen this in Liferay.
I guess this is not your problem here, but it might come in handy for others looking for this problem from another context.

Categories

Resources