Is $(window).scrollTop() the correct statement? - javascript

I'm trying to build a function like this one:
var t =$('#top');
var q1=$('#fe1');
var q2=$('#fe2');
var q3=$('#fe3');
var q4=$('#fe4');
var q5=$('#fe5');
var win = $(window);
var doc=$(document);
var wins = win.scrollTop();
var docs = doc.scrollTop();
function next (){
if (wins == docs) {
q1.ScrollTo();
}
else if (wins == q1.scrollTop()) {
q2.ScrollTo();
}
else if (wins == q2.scrollTop()) {
q3.ScrollTo();
}
else if (wins == q3.scrollTop()) {
q4.ScrollTo();
}
else if (wins == q4.scrollTop()) {
q5.ScrollTo();
}
}
I want to go scrolling to the next section. To do so, the code checks in which section I am so it knows which section to scroll to. But I think $(window).scrollTop() is not what I am looking for.
I want a statement that returns the distance between the top of the page and the top of what I am displaying. Maybe i have to do a more complex operation. Do you know how can i get this?
Thanks.

This problem is quite simple to solve even without jQuery or similar in plain JavaScript. Here it is for your example:
var next = (function (sections) {
function getTop(node) {
return node ? node.offsetTop + getTop(node.offsetParent) : 0;
}
return function () {
var i, nodeTop, top = window.pageYOffset;
for (i = 0; i < sections.length; i += 1) {
nodeTop = getTop(document.getElementById(sections[i]));
if (nodeTop > top) {
window.scrollTo(window.pageXOffset, nodeTop);
return;
}
}
};
}(['top', 'fe1', 'fe2', 'fe3', 'fe4', 'fe5']));
The code is quite general, so you can pass any section ids you want (they just need to appear in the correct order).
We use two standard DOM properties/functions here window.pageYOffset and window.scrollTo() to get and set vertical offset of the window (window.pageXOffset is used to keep horizontal offset the same). To get the vertical offset of the section start I defined getTop function using simple recursion (jQuery uses similar code IMHO).
Resulting function next() is defined in a self-invoking closure to hide the implementation and helper function. To use it after this code is run, you simply call
next();
I tested this code, so I am quite confident it works :).

Related

Call function with params as another functions param

this has been bugging me, and I'd like to understand.
Let's say that I have a site, where some elements need to be switched at a certain window size. So I've created a function that I can call with any elements.
function switcher (one, two) {
if (win.width() < 900) {
one.insertAfter(two);
} else {
one.insertBefore(two);
}
}
var frst = div.find('.first');
var scnd = div.find('.second');
My question is: this is working:
win.on('resize', function () {
switcher(frst, scnd);
});
this is NOT working, and WHY?
win.on('resize', switcher(frst, scnd));
Thanks!

How to pass nested function parametrs to main function parametrs?

I have function, that makes animation on DOM elements using animate.css when user scrolling the page on certain coordinates. It works perfectly.
$(window).scroll(function() {
$('.dev-courses__item').each(function(){
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 591) {
function slideAnimate(name,method){
if (method === undefined || method == 'default') {
method = "slideInLeft";
}
$(name).addClass(method);
};
slideAnimate('.dev-courses__item-first');
slideAnimate('.dev-courses__item-second');
slideAnimate('.dev-courses__item-third');
slideAnimate('.services-list');
};
});
});
The goal is to make function, that could be used universally with diferent selectors etc. I tried this:
function elemAnimate(selector,position,name,method){
$(window).scroll(function() {
$(selector).each(function(){
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + position) {
function slideAnimate(name,method){
if (method === undefined || method == 'default') {
method = "slideInLeft";
}
$(name).addClass(method);
};
};
});
});
}
elemAnimate('.dev-courses__item', 591, '.dev-courses__item-first');
Somehow after function slideAnimate starts to work, nothing happens in console. So i figured out, that i can't pass parametrs from nested function in this way. How to do this correctly?
I think your answer is here:
JavaScript Nested Functions
All functions have access to the global scope.
In fact, in JavaScript, all functions have access to the scope "above" them.
JavaScript supports nested functions.
Nested functions have access to the scope "above" them.
https://www.w3schools.com/js/js_function_closures.asp
Your slideAnimate function is nested in an each function which is nested in the scroll function. Try un-nesting this function.
function elemAnimate(selector,position,name,method){
$(window).scroll(function() {
$(selector).each(function() {
if ($(this).offset().top < $(window).scrollTop() + position) {
slideAnimate(name,method);
}
});
});
}
function slideAnimate(name,method){
$(name).addClass(method === undefined || method === 'default' ? 'slideInLeft' : method);
}
Or, if you're only using it to add a class, just get rid of it all together...
function elemAnimate(selector,position,name,method){
$(window).scroll(function() {
$(selector).each(function() {
if ($(this).offset().top < $(window).scrollTop() + position) {
$(name).addClass(method === undefined || method === 'default' ? 'slideInLeft' : method);
}
});
});
}
Also, since you're already using jQuery, have you thought about using jQuery UI? It makes animating things pretty easy.
https://api.jqueryui.com/slide-effect/

Errors with greensock tween activated by mouse in pixi.js

I'm trying to scroll a greensock tween in pixi. I'm getting errors trying to hook the code that gets the mouse/arrow input (trackpad.value) with my tween.
Here's my working greensock test tween, to make sure I have greensock working in pixi: (have to tween the position element in pixi):
var t1 = new TimelineMax({onUpdate:animate, onUpdateScope:stage});
t1.to(bg.position, 3, {y:100});
Here's my code where I'm trying to hook trackpad.value into the greensock code (I'm getting the following error: Uncaught TypeError: bg.position is not a function):
trackpad = new Trackpad(document);
var t1 = new TimelineMax({paused:true, onUpdate:animate, onUpdateScope:stage});
t1.progress(bg.position( Math.abs( trackpad.value ) / 3240));
I then tried the following - it didn't work (but I didn't get an error):
var moveIt = trackpad.value / 3240;
t1.progress(bg.position, moveIt, {});
Here's the code where the trackpad value is defined:
/*
* param: the html element that will be scrolled
*/
Trackpad = function(target)
{
this.target = target;
this.value = 0;
this.easingValue = 00;
this.dragOffset = 0;
this.dragging;
this.speed= 0;
this.prevPosition = 0;
$(this.target).mousedown($.proxy(this.onMouseDown, this));
this.target.onmousewheel = $.proxy(this.onMouseWheel, this);
// not forgetting touchs!
this.target.ontouchstart = $.proxy(this.onTouchStart, this);
// stop dragging!
$(document).keydown( $.proxy(this.onArrow, this))//function(e){
//this.target.ondragstart = function(){return false;}
}
// set constructor
Trackpad.constructor = Trackpad;
// create the functions
Trackpad.prototype.unlock = function()
{
this.locked = false;
this.speed = 0;
this.easingValue = this.value;
}
Trackpad.prototype.lock = function()
{
this.locked = true;
}
Trackpad.prototype.update = function()
{
if(this.easingValue > 0)this.easingValue = 0;
if(this.easingValue < -10700)this.easingValue = -10700;
this.value = this.easingValue;
if(this.dragging)
{
var newSpeed = this.easingValue - this.prevPosition;
newSpeed *= 0.7;
this.speed += (newSpeed - this.speed) *0.5;//+= (newSpeed - this.speed) * 0.5;
this.prevPosition = this.easingValue;
}
else
{
this.speed *= 0.9;
this.easingValue += this.speed;
if(Math.abs(this.speed) < 1)this.speed = 0;
}
}
Trackpad.prototype.onArrow = function(event)
{
if (event.keyCode == 38) {
// UP
this.speed = 4;
return false;
}
else if (event.keyCode == 40) {
// UP
this.speed -= 4
return false;
}
}
Trackpad.prototype.onMouseWheel = function(event)
{
event.preventDefault();
this.speed = event.wheelDelta * 0.1;
}
Trackpad.prototype.startDrag = function(newPosition)
{
if(this.locked)return;
this.dragging = true;
this.dragOffset = newPosition - this.value;
}
Trackpad.prototype.endDrag = function(newPosition)
{
if(this.locked)return;
this.dragging = false;
}
Trackpad.prototype.updateDrag = function(newPosition)
{
if(this.locked)return;
this.easingValue = (newPosition - this.dragOffset);
}
/*
* MOUSE
*/
Trackpad.prototype.onMouseDown = function(event)
{
if(event)event.preventDefault();
event.returnValue = false;
$(document).mousemove($.proxy(this.onMouseMove, this));
$(document).mouseup($.proxy(this.onMouseUp, this));
this.startDrag(event.pageY);
}
Trackpad.prototype.onMouseMove = function(event)
{
if(event)event.preventDefault();
this.updateDrag(event.pageY);
}
Trackpad.prototype.onMouseUp = function(event)
{
//$(this.target).mousemove(null);
$(document).unbind('mousemove');
$(document).unbind('mouseup');
//this.target.onmousemove = null;
this.endDrag();// = false;
}
/*
* TOUCH!
*/
Trackpad.prototype.onTouchStart = function(event)
{
//event.preventDefault();
this.target.ontouchmove = $.proxy(this.onTouchMove, this);
this.target.ontouchend = $.proxy(this.onTouchEnd, this);
this.startDrag(event.touches[0].clientY);
}
Trackpad.prototype.onTouchMove = function(event)
{
event.preventDefault();
this.updateDrag(event.touches[0].clientY);
}
Trackpad.prototype.onTouchEnd = function(event)
{
this.target.ontouchmove = null;
this.target.ontouchend = null;
this.endDrag();
}
** edit
tl = new TimelineLite( { paused: true } );
// respond to scroll event - in this case using jquery
$(window).scroll();
//apply whatever math makes the most sense to progress the timeline progress from 0 to 1 within those parameters. Something like,
$(window).scroll( function() {
var st = $(this).scrollTop();
if ( st < someArbitraryValue ) { // someArbitraryValue, where to start
// Here, "someOtherArbitaryValue" would be the
// "height" of the scroll to react to
tl.progress( Math.abs( st ) / someOtherArbitaryValue );
}
});
Is this the kind of effect you were after?
JavaScript:
window.requestAnimFrame=(function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(callback){window.setTimeout(callback,1000/60);};})(); //http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
var stageWidth=$(window).innerWidth();
var stageHeight=$(window).innerHeight();
var renderer=PIXI.autoDetectRenderer(stageWidth,stageHeight);
var bg,cat,moon,blue,trackpad,texture1,texture2,texture3;
document.body.appendChild(renderer.view);
texture1=PIXI.Texture.fromImage('https://dl.dropboxusercontent.com/u/45891870/Experiments/StackOverflow/1.5/cat.jpg');
texture2=PIXI.Texture.fromImage('https://dl.dropboxusercontent.com/u/45891870/Experiments/StackOverflow/1.5/moon.jpg');
texture3=PIXI.Texture.fromImage('https://dl.dropboxusercontent.com/u/45891870/Experiments/StackOverflow/1.5/blue.jpg');
bg=new PIXI.Container();
cat=new PIXI.Sprite(texture1);
moon=new PIXI.Sprite(texture2);
blue=new PIXI.Sprite(texture3);
cat.anchor.x=cat.anchor.y=moon.anchor.x=moon.anchor.y=blue.anchor.x=blue.anchor.y=0;
cat.position.x=cat.position.y=moon.position.x=blue.position.x=bg.position.x=bg.position.y=0;
cat.width=moon.width=blue.width=stageWidth;
moon.position.y=1080;
blue.position.y=2160;
bg.addChild(cat);
bg.addChild(blue);
bg.addChild(moon);
bg.vy=bg.vx=0;//what are those?
trackpad=new Trackpad(document);
requestAnimFrame(animate);
function animate(){
requestAnimFrame(animate);
bg.position.y=trackpad.value;
trackpad.update();
renderer.render(bg);
}
Let me know if this is exactly the thing you were looking for & I'll then break it down for you in terms of what has changed in comparison to your code.
Notes:
First & foremost, I have used the latest version (v3.0.6) of Pixi.JS in my example above. This v3 update brought a few major changes. Couple of them prominent to your problem are:
No need for Stage object anymore for rendering purposes. Any Container type object can be used directly to be rendered on canvas.
Shortening of the name DisplayObjectContainer to simply Container. This is probably the reason why you are getting the error when trying to implement my code in your environment that you mentioned in comments because I presume you are using one of the old verions.
Read all about this update here, here & here.
I always prefer to use the latest & greatest of GSAP (v1.17.0‏). Even the dot releases of this framework brings major updates which is why I like to keep it up to date. Read an important note on this update here. Having said that, the current implementation doesn't really use TweenMax at all.
TweenMax bundles EasePack, CSSPlugin & a few other things. No need to load them in separately. Update your HTML accordingly. Use this handy GSAP CheatSheet by Peter Tichy to get such information and more about this tool.
Changes in Trackpad.js:
Inside the update method, there was a maximum scroll limit defined the page can scroll up to. That value previously was -10700. I changed it to -2160. You may want to set it to -3240 I think, based on what I have been able to understand so far as to what you are trying to achieve.
Formatting changes.
Changes in main.js (whatever name you gave to your main script file):
Added a requestAnimationFrame polyfill thanks to Paul Irish.
Removed the var stage= new PIXI.Stage(0xff00ff); line. Read #1 above for details.
Renamed DisplayObjectContainer to Container which was assigned to bg. Read #1 above for details.
Added bg.position.y=trackpad.value; in the animate loop. You were missing this. You will need to use trackpad.value in order to position your bg.
Added trackpad.update(); in the same animate loop. This is the big one and IMHO, this is the one you were failing to understand the purpose of. In summary, Trackpad.js needs to update its value on a timely basis & the only loop you have got running is the animate loop thanks to requestAnimFrame. Hence, the update(); method is called.
Rendering bg instead of stage. Read #1 above for details.
Formatting changes.
Let me know if anything is unclear.
T
I thought of editing the old answer but decided against it because I think it answers your original question.
Take a look at this Codepen demo for a new approach to the same problem. I am really hoping to listen to community on the approach I have taken here in terms of listening to events and using them to adjust a GSAP timeline.
There are 4 JS files used in my example: app.js, constants.js, timeline.js & listeners.js. Links to which can be found in the settings gear icon of the JavaScript editor of the demo. All of these files are heavily annotated with links to solutions I found over the internet to specific problems.
Among these files, code of app.js is as follows:
JavaScript:
function Application(){}
Application.prototype.init=function(){
this.constants=Constants.getInstance();
this.BASE_URL=this.constants.BASE_URL;
this.IMAGE_JS_URL=this.constants.IMAGE_JS_URL;
this.IMAGE_PIXI_URL=this.constants.IMAGE_PIXI_URL;
this.IMAGE_GSAP_URL=this.constants.IMAGE_GSAP_URL;
this.createPolyfillForBind();
this.setupRenderer();
this.loadImages();
};
Application.prototype.setupRenderer=function(){
this.stageWidth=window.innerWidth;
this.stageHeight=window.innerHeight;
//this.renderer=PIXI.autoDetectRenderer(this.stageWidth,this.stageHeight);
this.renderer=new PIXI.CanvasRenderer(this.stageWidth,this.stageHeight);
document.body.appendChild(this.renderer.view);
};
Application.prototype.loadImages=function(){
var self=this;
this.loader=new PIXI.loaders.Loader(this.BASE_URL,1,{crossOrigin:''}); // PIXI Loader class [http://pixijs.github.io/docs/PIXI.loaders.Loader.html]
this.loader.add(this.IMAGE_JS_URL); // Loader extends ResourceLoader [http://adireddy.github.io/docs/haxe-pixi/v3/types/pixi/plugins/resourceloader/ResourceLoader.html]
this.loader.add(this.IMAGE_PIXI_URL);
this.loader.add(this.IMAGE_GSAP_URL);
//this.loader.once('complete',function(){self.onImagesLoaded.apply(self);}); // Vanilla JS alternative to jQuery's proxy() method [http://stackoverflow.com/a/4986536]
this.loader.once('complete',this.onImagesLoaded.bind(this)); // bind() polyfill [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Polyfill]
this.loader.load();
};
Application.prototype.onImagesLoaded=function(){
this.setupSprites();
this.initTimeline();
this.initListeners();
this.startTicker();
};
Application.prototype.setupSprites=function(){
this.containerBg=new PIXI.Container();
this.spriteJS=new PIXI.Sprite(PIXI.utils.TextureCache[this.BASE_URL+this.IMAGE_JS_URL]); // TextureCache in action [http://www.html5gamedevs.com/topic/7674-load-textures-synchronously/?p=45836]
this.spritePIXI=new PIXI.Sprite(PIXI.utils.TextureCache[this.BASE_URL+this.IMAGE_PIXI_URL]); // PIXI.TextureCache became PIXI.utils.TextureCache in v3 [http://www.html5gamedevs.com/topic/14144-v3-utilstexturecache-utils-is-not-defined/?p=80524]
this.spriteGSAP=new PIXI.Sprite(PIXI.utils.TextureCache[this.BASE_URL+this.IMAGE_GSAP_URL]);
this.containerBg.addChild(this.spriteJS);
this.containerBg.addChild(this.spritePIXI);
this.containerBg.addChild(this.spriteGSAP);
this.spriteJS.anchor.x=this.spriteJS.anchor.y=this.spritePIXI.anchor.x=this.spritePIXI.anchor.y=this.spriteGSAP.anchor.x=this.spriteGSAP.anchor.y=0;
this.spriteJS.position.x=this.spriteJS.position.y=this.spritePIXI.position.x=this.spriteGSAP.position.x=this.containerBg.position.x=this.containerBg.position.y=0;
this.scaleImage(this.spriteJS);
this.scaleImage(this.spritePIXI);
this.scaleImage(this.spriteGSAP);
this.spritePIXI.alpha=this.spriteGSAP.alpha=0;
this.spriteJS.position.y=this.constants.GUTTER;
this.spritePIXI.position.y=this.spriteJS.height*2+this.constants.GUTTER;
this.spriteGSAP.position.y=this.spriteJS.height+this.spritePIXI.height*2+this.constants.GUTTER;
};
Application.prototype.scaleImage=function(sprite){
//var scale=Math.min(this.stageWidth/sprite.width,this.stageHeight/sprite.height); // resize with aspect ratio [http://community.createjs.com/discussions/createjs/547-resizing-canvas-and-its-content-proportionally-cross-platform#comment_27266530] and [https://opensourcehacker.com/2011/12/01/calculate-aspect-ratio-conserving-resize-for-images-in-javascript/]
var scale=this.stageWidth/sprite.width;
sprite.scale.x=sprite.scale.y=scale;
};
Application.prototype.initTimeline=function(){
this.timeline=new Timeline();
this.timeline.init(this.containerBg,this.spriteJS,this.spritePIXI,this.spriteGSAP,this.stageWidth,this.stageHeight);
};
Application.prototype.initListeners=function(){
var self=this;
//this.listeners=new Listeners();
//this.constants.setListenersObject(this.listeners);
//this.listeners.init();
this.listeners=Listeners.getInstance();
this.listeners.addListeners();
document.addEventListener(this.constants.SCROLLED,this.onScroll.bind(this),false);
document.addEventListener(this.constants.STARTED_DRAG,this.onStartDrag.bind(this),false);
document.addEventListener(this.constants.DRAGGED,this.onDrag.bind(this),false);
document.addEventListener(this.constants.END_DRAG,this.onEndDrag.bind(this),false);
};
Application.prototype.onScroll=function(e){ this.timeline.onScroll(e); };
Application.prototype.onStartDrag=function(e){ this.timeline.onStartDrag(e); };
Application.prototype.onDrag=function(e){ this.timeline.onDrag(e); };
Application.prototype.onEndDrag=function(e){ this.timeline.onEndDrag(e); };
Application.prototype.startTicker=function(){
var self=this;
//TweenLite.ticker.addEventListener('tick',function(){self.render.apply(self);},false); // Vanilla JS alternative to jQuery's proxy() method [http://stackoverflow.com/a/4986536]
TweenLite.ticker.addEventListener('tick',this.render.bind(this),false);
};
Application.prototype.render=function(){this.renderer.render(this.containerBg);};
Application.prototype.createPolyfillForBind=function(){ // [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Polyfill]
if(!Function.prototype.bind){
Function.prototype.bind=function(oThis){
if(typeof this!=='function'){
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs=Array.prototype.slice.call(arguments,1),
fToBind=this,
fNOP=function(){},
fBound=function(){
return fToBind.apply(this instanceof fNOP
?this
:oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype=this.prototype;
fBound.prototype=new fNOP();
return fBound;
};
}
};
//
var app=new Application();
app.init();
P.S. I have also heavily experimented with design patterns in this same example, mainly Prototype and Singleton patterns. I am also looking forward to comments on them as well from the community.
T

jQuery Not Defined within a function

Alright, here's a puzzler. I've got a jQuery function to display a PHP generated list of announcements for a website via .fadeIn/.fadeOut; the very first thing loaded on the page is jQuery 1.11.xx from a CDN. I'm running Bootstrap, fullCalendar, SmartMenus, etc., and jQuery is most definitely loading.
Except within the setInterval() to update the announcement. This is rough-code, some functionality isn't present, but to my mind it should be doing an animation.
var announcementArray = [];
var announcementSource = "../announcements.php";
var totalAnnc;
$.getJSON(announcementSource, function(data) {
announcementArray = data.concat();
totalAnnc = announcementArray.length;
});
var count = 0;
var fadeAnnc = function() {
$('#announcementArea').text(announcementArray[count].announceText);
$('#announcementArea').fadeIn('slow',function() {
$('#announcementArea').css('display','block');
}).delay(2000).fadeOut('slow',function() {
count = (count + 1) % totalAnnc;
});
};
setInterval(function() {
fadeAnnc();
}, 3000);
Instead, when I run the page, I get a "function not defined" error for any jQuery function that's called within the setInterval(). If I call using document.getElementById('announcementArea').innerHTML = etc., it works, but doing the fade in/out via DOM manipulation seems to be more work than is needed when jQuery is available and working everywhere else on the page.
I've tried a few scope adjustments and have been working on what should be simple code for the last 5 hours. So, where's my glaring error? ;)
Not sure what kind of scope issue you are having (looks like it's the result of unposted code, as everything in your question looks OK), but if you want a fairly foolproof way of passing along the jQuery object, you could always pass it as a parameter:
var fadeAnnc = function($) {
$('#announcementArea').text(announcementArray[count].announceText);
$('#announcementArea').fadeIn('slow',function() {
$('#announcementArea').css('display','block');
}).delay(2000).fadeOut('slow',function() {
count = (count + 1) % totalAnnc;
});
};
setInterval(function() {
fadeAnnc($);
}, 3000);
Based on your updated answer, here's another possible solution:
(function($){
var announcementArray = [];
var announcementSource = "../announcements.php";
var announcementSpace = "#announcementArea";
$.getJSON(announcementSource, function(data) {
announcementArray = data.concat();
if (announcementArray.length === 0) {
$('#anncRow').css('display','none');
}
});
var count = 0;
var masterCount = 0;
var totalAnnc = announcementArray.length;
var timer;
var fadeAnnc = function() {
if (announcementArray.length > 0) {
$(announcementSpace).html(announcementArray[count].announceText);
$(announcementSpace).fadeIn(750, function() {
$(announcementSpace).css('display','block');
}).delay(4500).fadeOut(750, function() {
$(announcementSpace).css('display','hidden');
});
}
count += 1;
if ((count % announcementArray.length) == 0) {count = 0}
};
setInterval(fadeAnnc, 6000);
}(jQuery));
$ is defined as a function parameter and thus overrides the globally scoped $ within the function body, protecting it's definition for your code. This is actually exactly what jQuery recommends when creating an extension.
My previous answer - scratch that:
The issue was more interesting - somewhere between the SmartMenu plugin and the LibraryThing book display widget there is a jQuery conflict created. This explains why - depending on the load order - different parts would break, but always the setInterval(), which always loaded after SmartMenu and LibraryThing.
So, my somewhat messy solution is to release the $ at the beginning of the script and reclaim it at the end so on other pages jQuery has access to it, like so:
jq = jQuery.noConflict();
var announcementArray = [];
var announcementSource = "../announcements.php";
var announcementSpace = "#announcementArea";
jq.getJSON(announcementSource, function(data) {
announcementArray = data.concat();
if (announcementArray.length === 0) {
jq('#anncRow').css('display','none');
}
});
var count = 0;
var masterCount = 0;
var totalAnnc = announcementArray.length;
var timer;
var fadeAnnc = function() {
if (announcementArray.length > 0) {
jq(announcementSpace).html(announcementArray[count].announceText);
jq(announcementSpace).fadeIn(750, function() {
jq(announcementSpace).css('display','block');
}).delay(4500).fadeOut(750, function() {
jq(announcementSpace).css('display','hidden');
});
}
count += 1;
if ((count % announcementArray.length) == 0) {count = 0}
};
setInterval(fadeAnnc, 6000);
$ = jQuery.noConflict();
Use closures (which is considered good practice anyways):
(function($) {
var your_function = function() {
$(...);
};
setTimeout(function() {
your_function();
});
}(jQuery));
Using closures creates a sort of 'sandbox' for your code, so you don't have to worry about overwriting any variables declared in a parent scope (such as the dollar-sign $ used by jQuery).

JavaScript if Statement

I'm creating an if statement that fires different functions. Is there a better way I can accomplish this functionality?
$("#slide01-bttn").click(function() {
if ($("#slide-1").is('#featured_ul li:nth-child(1)'))
{
alert("First Child");
moveSlideFirstChild();
}
if ($("#slide-1").is('#featured_ul li:nth-child(2)'))
{
alert("Second Child");
moveSlideSecondChild();
}
if ($("#slide-1").is('#featured_ul li:nth-child(3)'))
{
alert("Third Child");
moveSlideThirdChild();
}
if ($("#slide-1").is('#featured_ul li:nth-child(4)'))
{
alert("Fourth Child");
moveSlideFourthChild();
}
});
You could of course simplify your code to this
var pos = $("#slide-1").prevAll().length;
switch (pos)
{
case 0:
...
break;
case 1:
...
break;
...
default:
...
break;
}
But it seems that you should optimize your methods that move child elements to have just one function instead of N so you could do a simple call:
var elem = $("#slide-1");
// pass position AND element because you'll likely use it inside
moveSlideChild(elem.prevAll().length, elem);
You could of course just pass in the element and get position inside. And save some element selections because you're doing many many jQuery element selector calls. This would make your code significantly faster and optimised.
$("#slide01-bttn").click(function() {
var slide = $("#slide-1");
var index = $('#featured_ul li').index(slide);
var position = ["First", "Second", "Third", "Fourth"][index];
if (position) {
alert(position+" Child");
// assuming they are global functions:
window["moveSlide"+position+"Child"]();
}
});
If your functions are local variables, you still could do
var fn = [moveSlideFirstChild, moveSlideSecondChild, moveSlideThirdChild, moveSlideFourthChild][index];
if (fn) fn();
But I would really recommend to paramatize your moveSlide function, so that you only need one that takes the element to move as an argument:
moveSlide(slide);
I think the best thing that you could do would be to paramatize your moveSlide functions
function moveSlide(childNumber) {
//Grab the child element you are looking for
//Move it code
}
Really you should be able to do something with the ids on the li to simplify it even more. I'm not sure how the HTML is layed out. if you could provide a fiddle we could probably make more progress.
You could use a switch to get the job done:
$("#slide01-bttn").click(function() {
var pos = $("#slide-1").prevAll().length;
switch(pos)
{
case 0:
case 1:
moveSlide(pos);
break;
default:
//code to be executed if pos is different from case 0 and 1
}
}
function moveSlide(childNumber) {
//Grab the child element you are looking for
//Move it code
}
If moveSlideNChild() all do similar things, it would be best to apply some abstraction to reduce the amount of code. You can then call
var $list = $('#featured_ul li'); // set here for cacheing
var $slide = $("#slide-1"); // set here for cacheing
$("#slide01-bttn").click(function() {
var position = $list.index($slide);
if( position >= 1 && position <= 4) { // only want 1 through 4
alert('Child ' + position);
moveSlideChild(position);
}
}

Categories