Jquery hover effects stop working after ajax call - javascript

In my website there are some ajax calls that filter product results. There are some effects applied on these products, which stop working after ajax call completes.
At the bottom of the page's code, there's the following:
jQuery(function($) {
jQuery('.category-products-grid').on('mouseenter', '.item', function() {
...
...
...
}).on('mouseleave', '.item', function() {
...
...
...
});
});
I've seen lots of similar posts about this issue, but none of the solutions suggested worked for me.
UPDATE
Here is the ajax call code. i didn't posted before because I don't believe it provides helpful information. There are many functions called int it and the code is too big to post here. The function that matters here is replaceProductsBlock(), and so I'll post it here:
var request = new Ajax.Request(url,
{
method:'GET',
parameters:params,
onSuccess: function(transport){
....
replaceProductsBlock(response);
....
},
onFailure: function(){
....
}
});
replaceProductsBlock: function(response, need_scroll){
var content = response.product_list;
if (typeof(this.gan_static_navigation_url) != 'undefined' && this.gan_static_navigation_url){
if ($$('div.col-main').length > 0){
var col_main = $$('div.col-main')[0];
col_main.innerHTML += '<div class="category-view">' + content + '</div>';
}
return;
}
var replace_toolbar = false;
if($$('div.category-products').length > 0){
element = $$('div.category-products')[0];
if (element.select('div.toolbar').length == 0){
replace_toolbar = true;
}
}else if($$('div.col-main p.note-msg').length > 0){
element = $$('div.col-main p.note-msg')[0];
}else{
return;
}
if (content && content.toElement){
content = content.toElement();
}else if (!Object.isElement(content)) {
content = Object.toHTML(content);
var tempElement = document.createElement('div');
content.evalScripts.bind(content).defer();
content = content.stripScripts();
tempElement.innerHTML = content;
el = this.getElementsByClassName('category-products', tempElement);
if (el.length > 0){
content = el[0];
}else{
el = this.getElementsByClassName('note-msg', tempElement);
if (el.length > 0){
content = el[0];
if (this.gan_shop_by_area == 1){
var shop_by_content = Object.toHTML(response.navigation);
shop_by_content.evalScripts.bind(shop_by_content).defer();
shop_by_content = shop_by_content.stripScripts();
var tempElement = document.createElement('div');
tempElement.innerHTML = shop_by_content;
var shop_by = this.getElementsByClassName('block-layered-nav', tempElement);
if (shop_by.length > 0)
{
shop_by = shop_by[0];
shop_by.id = 'gan_tmp_shop_by';
new Insertion.Before(element, shop_by);
}
}
}else{
return;
}
}
}
element.parentNode.replaceChild(content, element);
if (replace_toolbar && $$('div.category-products').length > 0){
this.ganReplaceToolbal(response.product_list);
}
if (typeof(need_scroll) != 'undefined' && need_scroll){
if ($$('div.category-products').length > 0){
var category_products = $$('div.category-products')[0];
category_products.scrollTo();
}
}
},

After testing and failing again and again to solve this (used jquery live(), one(), livequery() and many many more..) I finally found a solution.
It's described in this article:
Re-binding jQuery Events on AJAX Callbacks
The code I used looks something like this:
function initBinding(){
jQuery('.category-products-grid > .item').hover(function() {
...
...
}, function() {
...
...
});
}
var request = new Ajax.Request(url,
{
...
...
onSuccess: function(transport){
initBinding();
}
});

Related

Can't get each to work after ajax page load changes contents

on page load I run this function to hide long quoted posts into a clickable link to prevent huge comments on my site:
function hide_long_quotes()
{
$('.comments .comment_quote').each(function(i)
{
var actual_text = $(this).text();
var content = $(this).outerHTML();
if(actual_text.length > showChar)
{
var cite = $(this).find('cite span.username').first().text();
var cite_link = '';
if (cite.length > 0)
{
cite_link = 'from ' + cite;
}
var html = '<span class="morecontent">' + content + '</span>' + moretext + cite_link + '<br />';
$(this).replaceWith(html);
}
if (i+1 === quote_count) // this will be executed at the end of the loop
{
// deal with being linked to a comment, so we can put the window to the correct scroll position, since it will be different due to hidden quotes making the page smaller
if(window.location.hash)
{
var hash = window.location.hash.substring(1); //Puts hash in variable, and removes the # character
if (hash.indexOf("r") >= 0)
{
$('#'+hash)[0].scrollIntoView();
}
}
}
});
}
The problem is that when I reload ".comments" through ajax/load the above function no longer works:
function paginate_comments(page, article_id)
{
var url = "/includes/ajax/post_comment.php";
var current_url = window.location.href;
var host = window.location.host;
if(current_url.indexOf(host + '/admin.php?module=reviewqueue') != -1 || current_url.indexOf(host + '/admin.php?module=articles&view=Submitted') != -1 || current_url.indexOf(host + '/admin.php?module=articles&view=Submitted') != -1)
{
var area = 'admin';
}
else
{
var area = 'normal';
}
$('.comments').load(url, {'type':'reload', 'article_id': article_id, 'page': page, 'area': area}, function()
{
$(".lb-container").show();
$('.box.comments').get(0).scrollIntoView();
hide_long_quotes();
});
}
Not sure why it doesn't work, as the function is being called in the completed callback part of the load function?
What about giving the element collection to that function:
function hide_long_quotes(var comments = false)
{ /* for the case that you don't pass a collection to the function, maybe in the first call when the page is loaded */
comments = comments ? comments : $('.comments .comment_quote');
comments.each(function(i)
{
...
}
function paginate_comments(page, article_id)
{
...
$('.comments').load(
url,
{
'type':'reload',
'article_id': article_id,
'page': page,
'area': area
},
function()
{
$(".lb-container").show();
$('.box.comments').get(0).scrollIntoView();
hide_long_quotes($('.comments .comment_quote'));
}
);
}

detect when 2 calendar values changed

I am making a financial report where user choose 2 dates search_date1 and search_date2, and then a monthly report is generated.
I created first a daily report with only one calendar and when it is changed I apply some AJAX script to it and it works correctly:
var myApp = {};
myApp.search_date = "";
document.getElementById('search_date').onchange = function (e) {
if (this.value != myApp.search_date) {
var d = $("#search_date").val();
$.ajax({
...
});
}
}
Now I can't know how to detect if both calendars are changed to apply AJAX script according to their values.
EDIT
Is it correct to do the following:
var myApp = {};
myApp.search_date1 = "";
myApp.search_date2 = "";
document.getElementById('search_date1').onchange = function (e) {
if (this.value != myApp.search_date1) {
var d1 = $("#search_date1").val();
document.getElementById('search_date2').onchange = function (e) {
if (this.value != myApp.search_date2) {
var d2 = $("#search_date2").val();
$.ajax({
...
})
}
});
}
});
try this:
var temp = {
from: null,
to: null
}
document.getElementById('from').onchange = function(e){
temp.from = e.target.value;
goAjax();
}
document.getElementById('to').onchange = function(e){
temp.to = e.target.value;
goAjax();
}
function goAjax(){
if(temp.from && temp.to && new Date(temp.from) < new Date(temp.to)){
//do ajax call
console.log('valid')
}
}
<input type="date" id='from'/>
<br>
<input type="date" id='to'/>
I would have captured the change event for both elements :
$("#search_date1, #search_date2").on('change',function(){
var d1 = $("#search_date1").val();
var d2 = $("#search_date2").val();
$.ajax({...});
});
What you do in your edit may work, but it would be better (and easier) do something like this
var myApp = {};
myApp.original_search_date1 = $("#search_date1").val();
myApp.original_search_date2 = $("#search_date2").val();
myApp.search_date1 = $("#search_date1").val();
myApp.search_date2 = $("#search_date2").val();
document.getElementById('search_date1').onchange = function (e) {
if ($("#search_date1").val() != myApp.search_date1) {
myApp.search_date1 = $("#search_date1").val();
sendAjax();
}
});
document.getElementById('search_date2').onchange = function (e) {
if ($("#search_date2").val() != myApp.search_date2) {
myApp.search_date2 = $("#search_date2").val();
sendAjax();
}
});
function sendAjax() {
if (myApp.original_search_date1 !== myApp.search_date1 &&
myApp.original_search_date2 !== myApp.search_date2) {
$.ajax({
...
});
}
}
Cant you just set a variable to check if its been changed with true/false then run the script if both variables are true.
Something like,
var searchOneToggled = false,
searchTwoToggled = false;
$('#search_date_one').on('input', function() {
searchOneToggled = true;
runYourFunction();
});
$('#search_date_two').on('input', function() {
searchTwoToggled = true;
runYourFunction();
});
function runYourFunction() {
if(searchOneToggled === true && searchTwoToggled === true) {
alert('hello world');
}
}

Adding click listeners onto code generated in a Javascript object

I am creating a Javascript/jQuery slider class which builds a slideshow on a page when invoked.
Here is my Cycler object code:
//Cycle
var Cycler = function(options) {
this.cycleElement = options.cycleElement;
this.speed = options.speed || 5000;
this.effect = options.effect || "linear";
this.currentItem = null;
this.children = this.addItemsToCycler();
this.buttons = null;
if(options.buttonsEl.length != "") {
this.buttons = this.generateButtons();
}
}
Cycler.prototype.addItemsToCycler = function() {
var children = [];
jQuery(this.cycleElement + " > div.cycle-object").each(function(item, value) {
children.push(value);
});
return children;
}
Cycler.prototype.generateButtons = function() {
var buttons = "<ul>";
var counter = 0;
this.children.forEach(function(item) {
buttons += "<li><a href='#' data-rel='" + counter + "'></a></li>";
counter++;
});
buttons += "</ul>";
jQuery("#cycle-buttons").html(buttons);
}
Cycler.prototype.showItem = function() {
jQuery(this.children).fadeOut("slow");
jQuery(this.children[this.currentItem]).fadeIn("slow");
}
Cycler.prototype.start = function() {
if(this.currentItem == null || this.children.length <= this.currentItem) {
this.currentItem = 0;
}
this.showItem();
var self = this;
interval = window.setInterval(function() {
self.next();
}, this.speed);
}
Cycler.prototype.next = function() {
if(this.currentItem >= (this.children.length - 1)) {
this.currentItem = 0;
} else {
this.currentItem++;
}
this.showItem();
}
Cycler.prototype.prev = function() {
if(this.currentItem <= 0) {
this.currentItem = this.children.length - 1;
} else {
this.currentItem--;
}
this.showItem();
}
Cycler.prototype.pause = function() {
if(this.interval == null) {
console.log("Cycler is already paused");
} else {
window.clearInterval(this.interval);
this.interval = null;
}
}
Cycler.prototype.gotoItem = function(gotoItem) {
this.currentItem = gotoItem;
this.showItem();
}
The markup:
<div id="cycle-wrap">
<div id="background-cycle">
<div data-rel="0" class="cycle-object"></div>
<div data-rel="1" class="cycle-object"></div>
<div data-rel="2" class="cycle-object"></div>
</div>
<div class="inner">
<div id="cycle-buttons">
</div>
</div>
</div>
And my client code which creates an instance of the class:
//Cycler
var cycler = new Cycler({
cycleElement : "#background-cycle",
speed : 5000,
effect : "linear",
buttonsEl : "#cycle-buttons"
});
cycler.start();
Now, if a user supplies an element in the 'buttonsEl' variable which is passed to the class, I want the class to generate a list of li elements which when clicked will take the user to that slide. I have done this via the 'generateButtons' function I have already created the prototype function for this called 'goToItem' as you can see above. I am linking the li elements and the corresponding html using a 'data'rel' attribute.
What I would like to do is add click listeners onto each list element (that is generated in the 'generateButtons' function) which will pass the data-rel attribute through to my 'goToItem' function. Does anyone know of the best way this would be incorporated into my code, keeping it nice and OOP.
Thanks
In your Cycler constructor we could pass the buttonsEl to the generateButtons. Then this method will be able to insert the buttons in the desired element.
// Not sure if you want this comparison. If works by coercion but it's tricky. And it
// will fail if your client doesn't pass a buttonsEl option.
// I would prefer something like this:
// if(options.buttonsEl && options.buttonsEl.length > 0) {
if(options.buttonsEl.length != "") {
this.buttons = this.generateButtons(options.buttonsEl);
}
The generateButtons could be something like this:
Cycler.prototype.generateButtons = function(buttonsEl) {
var $buttons = jQuery("<ul></ul>");
this.children.forEach(function(item, counter) {
$buttons.append("<li><a href='#' data-rel='" + counter + "'></a></li>");
});
// Capture cycler this to be able to invoke the gotoItem method
// within the event handler
var that = this;
$buttons.on('click', 'li', function () {
that.gotoItem($(this).find('a').data('rel'));
});
jQuery(buttonsEl).html($buttons);
return $buttons;
}

Conflict between two js scripts, I can't understand why?

I am trying to implement a tracking script that standalone and on other sites works just as intended (or atleast to what I can see from watching the sites and analytics).
The code looks like this
{
jQuery(document).ready(function($) {
var filetypes = /\.(zip|exe|dmg|pdf|doc.*|xls.*|ppt.*|mp3|txt|rar|wma|mov|avi|wmv|flv|wav)$/i;
var baseHref = '';
if (jQuery('base').attr('href') != undefined) baseHref = jQuery('base').attr('href');
jQuery('a').on('click', function(event) {
var el = jQuery(this);
var track = true;
var href = (typeof(el.attr('href')) != 'undefined' ) ? el.attr('href') :"";
var isThisDomain = href.match(document.domain.split('.').reverse()[1] + '.' + document.domain.split('.').reverse()[0]);
if (!href.match(/^javascript:/i)) {
var elEv = []; elEv.value=0, elEv.non_i=false;
if (href.match(/^mailto\:/i)) {
elEv.category = "Email";
elEv.action = "Klick";
elEv.label = href.replace(/^mailto\:/i, '');
elEv.loc = href;
}
else if (href.match(filetypes)) {
var extension = (/[.]/.exec(href)) ? /[^.]+$/.exec(href) : undefined;
elEv.category = "Nerladdning";
elEv.action = "Fil-" + extension[0];
elEv.label = href.replace(/ /g,"-");
elEv.loc = baseHref + href;
}
else if (href.match(/^https?\:/i) && !isThisDomain) {
elEv.category = "Ex.Länk";
elEv.action = "Klick";
elEv.label = href.replace(/^https?\:\/\//i, '');
elEv.non_i = true;
elEv.loc = href;
}
else track = false;
if (track) {
_gaq.push(['_trackEvent', elEv.category.toLowerCase(), elEv.action.toLowerCase(), elEv.label.toLowerCase(), elEv.value, elEv.non_i]);
if ( el.attr('target') == undefined || el.attr('target').toLowerCase() != '_blank') {
setTimeout(function() { location.href = elEv.loc; }, 400);
return false;
}
}
}
});
});
}
This is the jquery version that is loaded before
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js"></script>
Now onto the problem, if I place "my" script above the ones I will post below then my script works. But if I do it as I want, placing my script last on the page it does not work, or anywhere aslong as it is below the other one will end up with mine not working
<script type="text/javascript"> jQuery(document).ready(function ($) { runJS(); }); </script>
The runJS leads to another .js file that is functions.js, of what I can understand runJS is this (I replaced the name of the site with site below).
function runJS() {
if((fontLoaded('DistrictThin') && fontLoaded('NationalLight')) || timer > 30) {
site.init();
$(".search_result").find('img').load(function () {
$(".search_result.primary").equalHeights();
//$(".search_result:not(.primary)").equalHeights();
});
if ($('#site_search_form').length > 0) {
populateForm();
}
}
else {
setTimeout('runJS()', 100);
timer += 1;
}
}
Any help would be much appreciated!
if you using different version of jquery in single page you must use this
var jq = jQuery.noConflict (); // jq having the value of $.
// In your entire script use jq instead of $.

Javascript file "FASW transitions" duplicating my header info. How to fix

Ok! I'm working on a wordpress site, and everything this javascript add on is supposed to do, it does...But, when I inspect element via safari develop, I notice that it's loading all of my headers scripts,meta,styles etc. into the body as well as the head. I can't figure out why. Here's what the script looks like:
function ft(params) {
var ol= document.addEventListener?"DOMContentLoaded":"load"; //on load event
var navB = params.navB || "reverse slide"; //backbrowser button effect, default empty
var but = params.but || false; //Allow transitions on input type button
var cBa = params.cBa || function() {};
function aDL(url, t, o) { //Ajax Div Load
if (window.XMLHttpRequest) {
r = new XMLHttpRequest();
} else if (window.ActiveXObject) {
r = new ActiveXObject("Microsoft.XMLHTTP");
}
if (r != undefined) {
r.onreadystatechange = function() {Ol(r, t, o);};
r.open("GET", url, true);
r.send("");
}
}
function Ol(r, t, o) { //On load div
if (r.readyState == 4) {
if (r.status == 200 || r.status == 0) {
t.innerHTML = r.responseText;
o();
} else {
t.innerHTML="Error:\n"+ r.status + "\n" +r.statusText;
}
}
}
function DE() //Div Effect
{
var dochtml = document.body.innerHTML;
document.body.innerHTML = "";
var d1 = document.createElement("div");
d1.id = "d1";
d1.style.zIndex = 2;
d1.style.position = "absolute";
d1.style.width = "100%";
d1.style.height = "100%";
d1.style.left = "0px";
d1.style.top = "0px";
document.body.appendChild(d1);
d1.innerHTML = dochtml;
var d2 = document.createElement("div");
d2.id = "d2";
d2.style.zIndex = 1;
d2.style.position = "absolute";
d2.style.width = "100%";
d2.style.height = "100%";
d2.style.left = "0px";
d2.style.top = "0px";
document.body.appendChild(d2);
return {d1: d1, d2: d2 };
}
function timeOuts(e, d1,d2)
{
setTimeout(function() { d1.className = e + " out"; }, 1);
setTimeout(function() { d2.className = e + " in"; }, 1);
setTimeout(function() {
document.body.innerHTML = d2.innerHTML;
cBa();
}, 706);
}
function slideTo(href, effect, pushstate)
{
var d = DE();
var d1 = d.d1;
var d2 = d.d2;
aDL(href, d2,
function() {
if (pushstate && window.history.pushState) window.history.pushState("", "", href);
timeOuts(effect,d1,d2);
}
);
}
function dC(e){ //Detect click event
var o;
var o=e.srcElement || e.target;
var tn = o.tagName.toLowerCase();
if (!but || tn!="input" || o.getAttribute("type")!="button") //if it is not a button
{
//try to find an anchor parent
while (tn!=="a" && tn!=="body")
{
o = o.parentNode;
tn = o.tagName.toLowerCase();
}
if (tn==="body") return;
}
var t = o.getAttribute("data-ftrans");
if (t)
{
e.preventDefault();
var hr = o.getAttribute("href") || o.getAttribute("data-href");
if (hr) slideTo(hr, t, true);
}
}
function aE(ev, el, f) { //Add event
if (el.addEventListener) // W3C DOM
el.addEventListener(ev,f,false);
else if (el.attachEvent) { // IE DOM
var r = el.attachEvent("on"+ev, f);
return r;
}
}
aE("click", window, dC);
aE(ol, document, //On load
function(ev)
{
aE("popstate", window, function(e) { //function to reload when back button is clicked
slideTo(location.pathname, navB, false);
});
}
);
}
here is the link to the site: http://www.fasw.ws/faswwp/non-jquery-page-transitions-lightweight/
I assume that thats not supposed to happen. So im trying to figure out how to keep it clean, and keep the head files loaded in the head, and only load the page content. I cannot figure this one out, some help from the pros is needed :)
FASW comes with two functions that serves as "hooks" both before and after initializing the component. you can do it like this:
(function inittrans()
{
initComponents();
var params = { /*put your options here*/ };
new ft(params);
})();
function onTransitionFinished()
{
initComponents();
}
function initComponents() {
// here is where you put your "other" javascript codes
}
Notice how your javascript codes are executed after loading your initial page and once again after the transition happened. Anyway, this is how I got the work around on it 'coz javascript codes just won't work as they are loaded by FASW via Ajax on-the-fly.

Categories

Resources