My jquery Animation doesn't work after ajax call - javascript

I'm trying to get my animation to work on after an ajax call has been made. It works fine when the user lands on the page. But if the user navigates back to the front page the animation will not run. I'm pretty new to Jquery, could you give me some hints?
I think it has something to do about .on but I'm not sure about the syntax if so. Any help would be greatly appreciated.
This is the code:
<script type="text/javascript">
(function() {
var quotes = $(".quoteName");
var quoteIndex = -1;
function showNextQuote() {
++quoteIndex;
quotes.eq(quoteIndex % quotes.length)
.fadeIn(3000)
.delay(12000)
.fadeOut(3000, showNextQuote);
}
showNextQuote();
})();
</script>

It seems that, when you make that AJAX call, you update (and by that I mean removing the current DOM nodes contained in the quotes object and creating new ones). If you do this, when you anitame the nodes in the quotes object, nothing will happen, becauser they no longer belong to the DOM you're seeing. jQuery objects don't have 'live updates', they don't change to reflect the changes in your DOM.
What you need is to make this call again after your AJAX request completes, to update the quotes object:
quotes = $('.quoteName');
Of course, your 'quotes' object is not global, so you might not be able to update it if your AJAX call is not inside the scope of the anonymous function where you're defining the code you've posted.

As far as I can see you have an Immediately Invoked Function Expression:
(function() {
})();
every variable and function declaration you put inside (like showNextQuote()) will not be accessible from other functions outside of it.
(function() {
function showNextQuote(arg) {
alert( arg );
}
showNextQuote('A');
})();
showNextQuote('B'); // ReferenceError: showNextQuote is not defined
One other thing is that your var quotes = $(".quoteName"); selector might get no results cause the DOM was not ready to be parsed by JS and for jQuery to catch your elements.
jQuery( function($) { // DOM is now ready and the $ alias secured.
var quotes = $(".quoteName");
var quoteIndex = -1;
function showNextQuote() {
++quoteIndex;
quotes.eq(quoteIndex % quotes.length).fadeIn(3000).delay(12000)
.fadeOut(3000, showNextQuote);
}
showNextQuote();
// other functions here
$('selector').on('some event', 'dynamicSelector', function(){
showNextQuote(); // will work
// other stuff here?...
});
});
Another hint would be that if you populate your DOM with new elements you might want to re-catch them to update the quotes.length

Related

function inside while loop

What Im trying to do is to get the content of a specific textarea tag in a specific clicks of a button, so I think a loop will solve this problem. The while loop on PHP does the role of making the name of textarea different and button's onclick trigger. But the loop in javascript wont work. Please anyone help what is the right one to complete my task?? Sorry for bad english...Thanks in advance
<html>
<head>
<script>
var i = 0;
while(i < 2000)
{
i++;
function feedbacks+i()
{
var feed = document.getElementsByName("feedback"+i)[0].value;
alert(feed);
}
}
</script>
</head>
<body>
<?php
while($i < 2000)
$i++;
echo "<textarea name='feedback$i' >you post</textarea>";
echo "<button onclick='feedbacks$i()' >send feedback</button>";
?>
</body>
</html>
I'm not sure if i get your question right, but why don't you write one single javascript function and pass the index as a parameter?
like:
function feedbacks(index) {
var feed = document.getElementsByName("feedback"+index)[0].value;
alert(feed);
}
and
onclick='feedbacks($i)'
Your code is incorrect, Since you have tagged your question with Jquery, I would like to suggest the following solution,
$(document).ready(function(){
$(document).on('click','button',function(){
alert($(this).prev('textarea').val())
});
});
You are creating those elements textarea and the button in runtime, So you have to use delegation inorder to register the click event for those buttons. Additionally you have to wrap your code inside .ready() function, Which means you have to manipulate the DOM only after it got ready.
Please see here for references,
.on (for delegation)
.ready()
.prev()
You have two major problems here.
Naming your function
When you name a function, you can't use variables, only a single identifier.
You could use a function expression and then assign the result somewhat that you can identify with a variable. e.g.
an_array_i_created_earlier[i] = function () {
// etc etc
}
Closures
You are trying to use i inside the function you are creating, but you are changing it outside that function before that function runs.
You can get around this by creating a new closure.
function createFunction(i) {
return function () {
// can use i sanely here because it was passed into a local variable belonging to `createFunction`
};
}
an_array_i_created_earlier[i] = createFunction(i);
This is all very messy though. You can forget about having to deal with i entirely, and throw out the horribly intrinsic event attributes while you are at it. Instead, navigate through the DOM to find the element:
addEventListener('click', function (evt) {
var textarea, t = evt.target;
if (t.classList.contains('feedback')) {
textarea = t.previousElementSibling;
alert(textarea.value);
}
});
Note that this uses some fairly recent additions to browser DOM. If you want compatibility with older browsers (in particular IE9 and earlier) then you will probably want to rewrite it to add some support for legacy approaches. A library like YUI or jQuery can help with that.
There's some error in your JavaScript code:
You tried to define a sequence of functions in a loop, and the function became local function to that loop. You cannot get access to these functions outside the loop. In order to make this work, you should define the function on window object, with the syntax window["feedbacks1"] = function () {}.
function feedbacks+i() is invalid syntax, use window['feedbacks' + i], as pointed in (1).
Functions defined in loop will share some local variable (closure). The variable in the function feedbacks#{i} will all share the same i. After the loop, i became 2001 and all the functions defined will try to get textarea with name feedbacks2001, which of course will not work. You will need the (function (i) { /* the code using i */ })(i); trick to make a local copy of the shared variable.
I made a demo on jsFiddle which correct the mistakes. I showed only 2 textareas. The following javascript should work for you 2000 textareas case.
for (var i = 0; i <= 2; ++i) {
window["feedbacks" + i] = (function (i) {
return function (e) {
var feed = document.getElementsByName("feedback"+i)[0].value;
alert(feed);
};
})(i);
}

Function not working creating a variable and using jquery?

I have a function which changes the width of some images. This happens when I hover over a different div in a different function. For some reason the the called function only performs some lines of code and then it stops.
function hey()
{
alert(0);
var $imgContent = ('.imgContent');
$imgContent.css("width","10%");
alert(2);
}
var $content = $('.content');
$content.mouseenter(function() {
$content.removeClass('full').addClass('partial');
$(this).addClass('full').removeClass('partial');
$(this).find('.img1').css('display','none');
$(this).find('.img2').css('display','');
if($(this).hasClass('cont1')){
alert(1);
hey();
}
if($(this).hasClass('cont2')){
}
if($(this).hasClass('cont3')){
}
if($(this).hasClass('cont4')){
}
}).mouseleave(function(){
$(this).find('.img1').css('display','');
$(this).find('.img2').css('display','none');
$(this).removeClass('full').addClass('partial');
});
In the mouseenter() function when I check if $(this).hasClass('cont1') then I perform an alert, which works. After that I call on function hey(). This is where my problem arises. After calling function hey() i perform another alert(0) , which also works. But the lines of code after that do not get executed and the last alert(2) doesn't work either.
There is an error in your code.
Replace:
var $imgContent = ('.imgContent');
With
var $imgContent = $('.imgContent');
You have a mistake in your jquery object definition.
Per jQuery():
jQuery() — which can also be written as $() — searches through the DOM for any elements that match the provided selector and creates a new jQuery object that references these elements
so in your case you should have:
var $imgContent = $('.imgContent');
$imgContent.css("width","10%");
Also, it's important to note that in your .mouseenter() function you refer to:
$content.removeClass('full').addClass('partial');
$(this).addClass('full').removeClass('partial');
$content and $(this) both refer to the same object, so in essence these lines are pointless.

function scope in jQuery

I have this code in <script> tags at the top of my HTML file.
$(document).ready(function()
{
$('#scrollbar1').tinyscrollbar();
$('a.jqtree_common').click(updateScrollbar());
});
$(function updateScrollbar()
{
var oScrollbar = $('#scrollbar1');
oScrollbar.tinyscrollbar();
oScrollbar.tinyscrollbar_update();
$('a.jqtree_common').click(updateScrollbar());
});
But for some reason when I run this, it says updateScrollbar() is undefined within (document).ready. When I try to define updateScrollBar() inside of (document).ready then updateScrollBar() gets caught in some kind of endless loop.
My question is twofold:
What can I do to make updateScrollBar() defined within the scope of (document).ready?
Is there a better way to assign this function to the 'a.jqtree_common' elements? They are created dynamically at runtime, and modified as the webpage is used. I want the function to run every time one of them is clicked.
I'm using tiny scrollbar and jqtree
EDIT: I want the $('a.jqtree_common').click(updateScrollbar); assignment to be made every time the scrollbar is updated, since I believe clicking on a 'a.jqtree_common' element creates more 'a.jqtree_common' elements.
Pass the function reference as the callback, instead of the result of the function in Click event. () will invoke the function and set the result as a call back which inturn calls updatescrollbar inside it again and goes in an infinite loop.
$(document).ready(function()
{
$('#scrollbar1').tinyscrollbar();
$('a.jqtree_common').click(updateScrollbar);
});
function updateScrollbar()
{
var oScrollbar = $('#scrollbar1');
oScrollbar.tinyscrollbar();
oScrollbar.tinyscrollbar_update();
//$('a.jqtree_common').click(updateScrollbar);
}
Okay, I know there are a lot of hats in the ring at this point, but here's my entry just the same...
//IMMEDIATELY-INVOKED FUNCTION EXPRESSION (IIFE)
// Used for privacy/variable scoping
(function(){
//bind init function to dom-ready event
$(init); //same as $(document).ready(init);
//initialize event bindings for page
function init() {
//initialize scrollbar
$('#scrollbar1').tinyscrollbar();
//click binding for tree
$('a.jqtree_common').click(updateScrollbar);
//assuming you want to run the updateScrollbar on page load
//in addition to clicks
updateScrollbar();
}
//handles scrollbar updates
function updateScrollbar() {
//assuming the tinyscrollbar() initialization only needs
//to happen once, inside the initialization event.
$('#scrollbar1').tinyscrollbar_update();
}
}());
The structure above is pretty much how I work through things... I do my variables first, then event bindings at the top, and have my function declarations below. This works because of function hoisting (in compilation of the JS, function declarations are moved to the top), this doesn't work with function assignments (ex: var x = function(){...}), then I wrap the whole thing inside an IIFE. I find that this structure provides easier readability and comprehension. I don't like putting my bindings at the bottom, as I find you have to go over a lot to get to what you are looking for.
Try this code:
$(document).ready(function() {
var updateScrollbar = function () {
var oScrollbar = $('#scrollbar1');
oScrollbar.tinyscrollbar();
oScrollbar.tinyscrollbar_update();
};
$('#scrollbar1').tinyscrollbar();
$('a.jqtree_common').click(updateScrollbar).click();
});
To bind elements loaded later we must use this .on( function
$(document).ready(function(){
$('#scrollbar1').tinyscrollbar();
$(document).on("click","a.jqtree_common", updateScrollbar);
});
function updateScrollbar(){
var oScrollbar = $('#scrollbar1');
oScrollbar.tinyscrollbar();
oScrollbar.tinyscrollbar_update();
}
and if you want the scope limitation then declare function within the block
$(document).ready(function(){
$('#scrollbar1').tinyscrollbar();
$(document).on("click","a.jqtree_common", updateScrollbar);
function updateScrollbar(){
var oScrollbar = $('#scrollbar1');
oScrollbar.tinyscrollbar();
oScrollbar.tinyscrollbar_update();
}
});
This is what ultimately worked for me:
$(document).ready(function()
{
$('#scrollbar1').tinyscrollbar();
$('a.jqtree_common').click(updateScrollbar);
function updateScrollbar()
{
var oScrollbar = $('#scrollbar1');
oScrollbar.tinyscrollbar();
oScrollbar.tinyscrollbar_update();
$('a.jqtree_common').click(updateScrollbar);
}
});

Anonymous function on page load

I'm trying to get better with JavaScript and learn how to utilize my code in functions and keep everything clean. I'm trying to run a function on page-load...
var setColors = function(){
this.init = function(){
$.getJSON('js/colors.json', function(colors) {
$.each(colors, function(i, colors) {
$('<li>', {
text: colors['color'],
'name' : colors['color'],
'data-hex' : colors['hex'],
'data-var' : colors['var']
}).appendTo('#picker');
})
});
}
}
(This is not a color-picker, just a list of colors)
I want setColors() to be executed as soon as the page starts. I read that an anonymous function runs automatically, but this one isn't, I also tried...
$(function(){
setColors();
});
Below the setColors() function and that isn't working ether (The page is just blank). What am I doing wrong and how do I get my function to run on page load? I'm trying to learn so an explanation would be great.
Anonymous functions are not run immediately, you're thinking of Immediately Invoked Function Expressions which happen to often use an anonymous function.
To fix your code:
a) get rid of the this.init function wrapper within the "object" - you're not using it and this.foo only makes sense if you're using new to instantiate an object:
function setColors() {
return $.getJSON(...);
}
Note that returning the $.getJSON() result allows you to register additional deferred object handlers, register error handlers, etc.
b) call the above function in a document.ready handler (which you must do, since the AJAX callback modifies the DOM).
$(setColors);
NB: the latter is a legal way of calling this handler - jQuery will automatically register any function that you pass this way as a document.ready handler. It's similar to writing:
$(function() { setColors() })
but without the extra (useless) function wrapper.
To have that run once the DOM is initialized, you can put it in a ready listener (jQuery):
$(document).on('ready', function() {
setColors();
});
If you want the function to run automatically as soon as it is encountered in the js, after the } that ends the function, add ();
Something like:
function setColors() {
// Code
}();
setColors doesn't return the next function, or call it at the end. YOu could change it to look like:
var setColors = function(){
this.init = function(){
$.getJSON('js/colors.json', function(colors) {
$.each(colors, function(i, colors) {
$('<li>', {
text: colors['color'],
'name' : colors['color'],
'data-hex' : colors['hex'],
'data-var' : colors['var']
}).appendTo('#picker');
})
});
}
init(); // <--- change
}
Which would do the trick for you. You don't even need to "return it" either since the init function itself doesn't return anything, so you could just call it.

Javascript scope help

I am relatively new to javascript so please be patient if what i am asking is completely stupid!
I am trying to make a simple module. Inside the module i want to have a config object that holds settings for the module. I am also using jquery. The jquery selectors work only when in a function directly in the main object/module.
I understand that javascript has functional scope so I am suprised that I cannot use the jquery selectors anywhere inside the module.
EDIT:
I want to be able to directly set all of my configs inside the configs object using jquery selectors. This way i keep all the messy stuff inside one place and can then access configs.whatever throughout the rest of the module. At the moment jquery selectors do not work inside the configs module.
var OB = function() {
var configs = {
'mode' : 'test',
'numOfSelects' : $('.mySelect').find('select').length, // This doesnt work
}
var getMode = function() {
return configs.mode;
}
function init() {
alert(configs.numOfSelects); // This alerts 0 until the following line
alert($('.mySelect').find('select').length); // This correctly alerts 2
};
var handlers = {
successHandler : function() {
alert("Success");
},
errorHandler : function() {
alert("error");
}
}
return {
init : init,
getMode : getMode
}
}( );
$(document).ready(function(){
OB.init();
});
It isn't that jQuery isn't in scope — that's that the code isn't executing when you think it is. The variable config is defined when that anonymous function (var OB = function() {}()) is executed. The DOM isn't ready yet, so that DOM traversal doesn't find anything. When you do the DOM traversal in init(), that isn't executed until it's explicitly called inside the $(document).ready() handler, at which point that DOM is set up. That's the difference you're seeing.
OB() needs to be called after the DOM has completely loaded. Hence the answer by Marcelo, which calls OB() in the ready() method.
EDIT: It's funny that my original answer below was incorrect because I didn't notice two little parentheses at the end of the definition of OB, and it turns out that these are the culprit. You define and then immediately invoke OB, which is before the DOM has been fully loaded. Remove those parentheses and make the change I suggest below.
Calling OB() returns an object with init and getMode, but you haven't called OB(), you've only referred to OB. Try this instead:
$(document).ready(function(){
OB().init();
});
Also, I assume you want to later refer to getMode. In particular, you will to get the copy of getMode that has access to the same local scope that your init() call had access to. To achieve this, you will need to store the result of calling OB() for later use:
var ob;
$(document).ready(function(){
ob = OB();
ob.init();
});
function some_other_function() {
... ob.getMode() ...;
}

Categories

Resources