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).
Related
many people said that looping function inside each() is bad practices.
it will cause terrible perfomance...
just like version one...
Version one :
$(".next").each(function() {
var el = $(this),
setNo = 0,
onNo = function() {
setNo = 1;
};
onNo(); // setNo will become 1
)};
so, i have to move function outside each(). then i'm confused on replacing local variable at each()
Version two :
var onNo = function() {
var setNo = 1;
return setNo; // replace it
};
$(".next").each(function() {
var el = $(this),
setNo = 0;
onNo(); // it's not replacing setNo local variable. how to fix this?
)};
how to fix this?
do you guys have more efficient design pattern, i'm really confused at javascript design pattern.
thanks...
Are you looking for something like this?
function onNo ($el) {
// do some calculation with $el
var setNo = 1;
return setNo;
}
$(".next").each(function() {
var $el = $(this)
var setNo = 0
setNo = onNo($el)
)}
I agree with Juhana's comment that the performance issues are not significant enough to worry about. However, to answer your question:
You can't set a local variable in another function like that. However, you can pass variables to that function.
var onNo = function(setNo) {
return setNo; // returns 0
};
$(".next").each(function() {
var el = $(this),
setNo = 0;
onNo(setNo);
)};
I have a table in a separate HTML file that I am loading with jQuery. I am then defining the variable "aa". I am attempting to use this variable in my JavaScript Function "report(period)". I tried creating a global variable but that didn't help. I am not entire sure I was doing it correctly. I am fairly new to JavaScript and know even less of jQuery. I've gone through other similar posts but it’s very difficult to understand exactly what's happening. Any help would greatly be appreciated.
jQuery
jQuery(function($) {
aa = document.getElementById('part1Table').rows[0].cells[2].innerHTML;
});
Javascript
function report(period) {
x = document.getElementById("tblabiNew").rows[2].cells[1].innerHTML; /*----- for testing use a number instead (example: x = "205-000040-634") ------*/
/*---------------------------------------------------------------------------------------------- Start - Object Removal Control ------------------------------------------------------------------------------------*/
if (x==aa) {
var i = 1; do {
+ i; i++;
var e = document.getElementById (i);
e.style.display = 'none'
} while (i < 15)
/*polebrea21*/
var polebrea = 21;
do {
+ polebrea;
polebrea++;
var e = document.getElementById (polebrea);
e.style.display = 'none'
} while (polebrea < 28)
/*polebrea31*/
var polebrea = 31;
do {
+ polebrea;
polebrea++;
var e = document.getElementById (polebrea);
e.style.display = 'none'
} while (polebrea < 38)
/*regulatory51*/
var regulatory = 51;
do {
+ regulatory;
regulatory++;
var e = document.getElementById (regulatory);
e.style.display = 'none'
} while (regulatory < 64)
/*regulatory51*/
/*regulatory81*/
var regulatory = 81;
do {
+ regulatory;
regulatory++;
var e = document.getElementById (regulatory);
e.style.display = 'none'
} while (regulatory < 94)
};
};
If you want "global" variable you should declare it outside of all functions body. So this should be.
var aa;
jQuery(function($) {
aa = //do something with aa
});
but anything you use without declaring is by default global (mind it work that way only in browsers).
If you want create local variable, add var keyword before it name, like this:
function report(period) {
var x = //...
}
I believe your aa variable is not declared because report function is called before page is ready.
Everything in function given to jQuery() run after DOM is ready, so if I write:
jQuery(function($) { console.log(1); });
console.log(2);
I get "2, 1" and not "1, 2".
You should really learn JavaScript and jQuery if you want to use it. Your report code seems like it can be replaced with one line with jQuery.
If I understand your scenario correctly you are not able to obtain the relevant node because the HTML fetched via ajax has not been injected into the DOM and hence can't be fetched using document.getElementById.
Could you provide the code which fetches the remove HTML and then what is done with it ? That may be helpful to understand the situation.
Anyway, this is something you may want to try:
$.ajax({
method: "GET",
url: "some/remote/url",
success: function(htmlContent) {
aa = $(htmlContent).find('#part1Table')[0].rows[0].cells[2].innerHTML;
// Do some processing
}
})
Last week a made a function for ellipsing the text inside some selector.
I was calling the function like this:
ellipsiText('.class',50) passing the selector and the max length of the text that i wanted to. This works fine, but im trying to make it a plugin, to call like this: $('.class').ellipsiText(50).
So, i was reading the tutorial in jquery website, and i understood how to do it. But i think i'm having an issue with the "this" seletor. Here is my original function:
function ellipsiText(selector,maxLength){
var array = $(selector).map(function(){
return $(this).text();
}).get();
var i;
var teste = [];
for (i=0;i<array.length;i++){
if (array[i].length > maxLength){
teste.push(array[i].substr(0,maxLength) + "...");
} else {
teste.push(array[i]);
}
}
for (var i=0;i<teste.length;i++){
$(selector).each(function(i){
$(this).text(teste[i]);
});
}
}
and here is my tentative of making a jquery plugin:
(function ($) {
$.fn.ellipsiText = function(length){
var array = $(this).map(function(){
return $(this).text();
}).get();
var i;
var teste = [];
for (i = 0; i < array.length; i++){
if (array[i] > length){
teste.push(array[i].substr(0,length) + "...");
} else {
teste.push(array[i]);
}
}
$(this).each(function(i){
$(this).text(teste[i]);
});
};
}(jQuery));
What am i doing wrong?
Well first thing is not a problem, but instead of $(this) in the first function scope, you can use this.map/this.each.
The problem is, in the second code you do
if (array[i] > length)
instead of
if (array[i].length > length)
Nothing to do with the jQuery plugin!
http://jsfiddle.net/UY88r/
This is untested, but the basic structure is something like this. Also you have so much looping in your code when one loop is needed.
$.fn.ellipsiText= function(options) {
var settings = $.extend({ //nice way to give to give defaults
length : 50,
ellipsi : "..."
}, options );
return this.each(function() { //the return is needed for chaining
var elem = $(this);
var txt = elem.text();
if (txt.length>settings.length) {
elem.text(txt.substr(0,settings.length) + settings.ellipsi );
}
});
};
and call it
$( "div.defaults" ).ellipsiText();
$( "div.foo" ).ellipsiText({
length : 10
});
$( "div.more" ).ellipsiText({
length : 10,
ellipsi : "<more>"
});
You already have a working function, just use it.
$.ellipsiText = ellipsiText;
$.fn.ellipsiText = function (count) {
ellipsiText(this, count);
}
now you can use it like any of the following:
ellipsiText('.class',50);
$.ellipsiText('.class',50);
$('.class').ellipsiText(50);
There's no sense in rewriting the function you already have working when you can just use it.
The variable my_sound is declared in the first, outer function. So, I should be able to use it in the nested function. However the mouseout event produces no result. What am I doing wrong? Thanks for any help.
$(document).ready(function () {
var starting_pics = ["CN.gif", "EN.gif", "GN.gif"];
var starting_sounds = ["CN.mp3", "EN.mp3", "GN.mp3"];
var i = 0;
for (i = 0; i < starting_pics.length; i++) {
$("<img/>").attr("src", "images/" + starting_pics[i]).appendTo("#main").addClass("pics");
}
$("#main").on("click", ".pics", function () {
var i = $(this).index();
var my_sound =($("<audio/>").attr("src", "audio/" + starting_sounds[i])).load().get(0).play();
$("#main").on("mouseout", ".pics", function () {
$("my_sound").animate({ volume: 0 }, 1000);
});
});
});
The problem is probably that .play() doesn't return a jQuery object (or anything, for that matter, hence undefined).
Additionally, as the other comments have said, you don't want $('my_sound').whatever but rather just my_sound.whatever if it were a jQuery object, which it is not. So maybe you could try
var $my_sound = $("<audio />").attr("suchandsuch","etc");
$my_sound.load().get(0).play();
$my_sound.whatever();
I'm trying to develop a jQuery plugin. Here's the code snippet I've written so far:
var MYNAMESPACE = MYNAMESPACE || {};
MYNAMESPACE.MyPlugin = function (inputElement, options) {
var element = $(inputElement),
oldValue = element.val(),
container = null,
init = function () {
container = $('<div class="container"></div>').hide().insertAfter(element);
//the suggest method is called from within the anonymous function
//called by getJSON...
},
suggest = function (resp) {
for (var i = 0; i < len; i++) {
var item = $('<div/>')
.html('whatever')
.mouseover(function (index) {
return function () {
activateItem(index);
};
} (i));
container.append(item);
}
},
activateItem = function (index) {
//container doesn't include those appended items.
//why???
};
init();
};
(function ($) {
$.fn.myplugin = function (options) {
return new MYNAMESPACE.MyPlugin(this.get(0), options);
};
} (jQuery));
Within the activateItem function, the container doesn't have any children!!! Why is that?
Any help would be highly appreciated,
container is already a defined jQuery object, but you are redefining to 'xxxx'. I'm guessing you want to insert the value? Try using container.html('xxxx')?
Also, it appears your mouseover function is returning a function where the index will be undefined (I haven't test it), but try this instead:
.mouseover(function () {
container.html('xxxx');
activateItem(i);
});
Update: Ok, now that I have time to look at the code, it appears len is not defined inside the suggest function. I made a rudimentary demo to test it all and it seems to work as expected.