iScroll, how do I call my scroller? - javascript

The iScroll documentation shows a typical iScroll setup like the one below.
var myScroll;
function loaded() {
setTimeout(function () {
myScroll = new iScroll('wrapper');
}, 100);
}
window.addEventListener('load', loaded, false);
My question is how do I call the scroller? If I use:
var currentItem = 5;
myScroll.scrollToElement('.nav > li:nth-child('+currentItem+')', 300);
I get an error.
Uncaught TypeError: Cannot call method 'scrollToElement' of undefined

I suppose you need to use the variable name you assigned the iScroll to:
myScroll.scrollToElement ...
and not
scroller.scrollTo ...
Update:
According to your latter tests, it obviously was a timing error. You proably called myScroll.scrollToElement before the timeout function was executed.

It looks like you are adding extra quotation marks within the first parameter.
Remove the quotation marks, and try changing your code to the following
myScroll.scrollToElement('.nav > li:nth-child(5)', 300);
If you are looking to make the query dynamic, replace the number with a variable and adding plus signs to concatenate the string.
var incNumber = 5;
myScroll.scrollToElement('.nav > li:nth-child('+ incNumber +')', 300);
It also appears that your iScroll is created with a timeout delay. Is your function being called before the library is instantiated?

Related

Game loop appears to be breaking at the end of iterating through array. Uncaught TypeError

Morning all,
Definitely a novice question here, this is my first real JS project - so apologies in advance for the clunky code.
The following functions are being used to show the light sequence for a "simon" game. The code seems to work fine initially, as I've tested multiple lengths of array, however on exiting the loop I get the following error:
Uncaught TypeError: Cannot read property 'setAttribute' of null
at show (script.js:95)
at showLights (script.js:83)
at script.js:88
I've looked around a lot for fixes to this error, and the majority of feedback is that it's related to the DOM and a wrapper will fix. I've found that a wrapper doesn't resolve. Similarly, I can't see that it's an issue with the CSS or HTML as the functions work ok until exit.
The looping functions are copied below:
// iterates through simon.array then allows button press
function showLights(x) {
if (x >= simon.array.length) {
clearTimeout(timer);
show(x);
allowPress();
} else {
show(x);
var timer = setTimeout(function(){
showLights(x+1);
},500);
}
}
// adds then removes flash class to light pads.
function show(x){
var display = document.getElementById("light" + simon.array[x]);
display.setAttribute("class", "flasher");
setTimeout(function(){
display.setAttribute("class", "game-box");
},500);
}
Apologies in advance for any errors or faux pas in posting this. I strongly suspect that I'll be kicking myself when this is fixed.
Kind Regards
Andy
The issue is related to you checking the length of an array, then trying to use an element of that array that does not exist. You are possibly also trying to set an attribute to an element that does not exist.
At a guess, this is the real cause of the issue:
if (x >= simon.array.length) {
clearTimeout(timer);
show(x);
allowPress();
Simply removing show(x) should help. The reason is you are checking for the length of simon.array, then later in function show(x) you make a request for simon.array[x], but that is not going to find anything, as x is greater than the length of that array.
The other possible issue is in the following chunk, but could be solved a number of ways. One way is to check x before passing. Another is making sure the element (display) is not null before setting the attribute.
// adds then removes flash class to light pads.
function show(x){
var display = document.getElementById("light" + simon.array[x]);
display.setAttribute("class", "flasher");
setTimeout(function(){
display.setAttribute("class", "game-box");
},500);
}
My suggestion would be as follows:
// adds then removes flash class to light pads.
function show(x){
var display = document.getElementById("light" + simon.array[x]);
if (display) {
display.setAttribute("class", "flasher");
setTimeout(function(){
display.setAttribute("class", "game-box");
},500);
}
}
You may want to check out classList as well as an alternative to setAttribute.
Something else to consider instead of using setTimeout would be to use a CSS animation.

javascript How to make an odometer to start counting onload?

How to make an odometer to start counting onload https://jsfiddle.net/aht87opr/6/ ? (I've tried but to no avail, the snipet which should start it is at the bottom of javascript). I am javascript beginner please help :)
This is Gavin Brock's Odometer http://brock-family.org/gavin/software/web/odometer.html
//<![CDATA[
var n = 0;
var myOdometer;
function startcounting () {
var div = document.getElementById("odometerDiv");
myOdometer = new Odometer(div, {value: n, digits: 6, tenths: true});
update();
}
function update () {
n=n+0.0025
myOdometer.set(n);
setTimeout("update()", 0);
}
//]]>
startcounting();
it does not work because setTimeout wants you to pass a function handle (you pass a string)
try setTimeout(update, 0);
From MDN:
A string passed to setTimeout is evaluated in the global context, so local symbols in the context where setTimeout() was called will not be available when the string is evaluated as code.
Additionally,
This syntax is not recommended for the same reasons that make using eval() a security risk.
Your code isn't working because setTimeout, when passed code as a string, can't see your update method. You can both fix this and improve the quality of your code by just passing update directly, as #dolek recommends

slideshow counter disappears

I have this code that is supposed to generate a counter for a slideshow and then change the picture and the corresponding number color in the counter. However, after the slideshow cycles through twice, the counter changes to display:none and then reappears and disappears every time the slideshow begins its cycle.
//icons for newsreel guide
for(i=0;i<document.getElementsByClassName("news").length;i++){
var count=i+1;
$('#counter').append('<span class="count">'+count+'</span>');
}
//newsreel script
$(".news").hide();
setTimeout (function() {
var wait = $(".news:last").index()*12000+12000;
function newsreel(){
var i=0;
(function showNews(elem){
if(i==document.getElementsByClassName("count").length){
i=0;
}
document.getElementsByClassName("count")[i].style.color="#000";
elem.fadeIn(2000,function(){
elem.delay(8000).fadeOut(2000,function(){
document.getElementsByClassName("count")[i].style.color="#3159a0";
i=i+1;
$(this).next().length && showNews($(this).next());
});
});
})
( $(".news:first"));
setTimeout (arguments.callee, wait);
}/*end newsreel()*/
newsreel();
}, 2000);
At first I thought it was using the deprecated arguments.callee but I changed that and it still happens on cue. Any ideas?
I checked your code, and the problem is in this line :
$(this).next().length && showNews($(this).next())
.next() is getting the next sibling. Your counter is a sibling of .news. To solve your problem, do this:
$(this).next().length && showNews($(this).next('.news'))
That will select the next sibling with the class news.
I suspect it's because your showNews function is never running. I think the JavaScript engine is evaluating
(function showNews(elem){
//...
})
and
( $(".news:first"));
as two different expressions, rather than passing $(".news:first") as a parameter to showNews as you intend. Since ; at the end of a line is optional in JS, the parser will insert one automatically if the result is valid JavaScript. In this case, it defines a function but never calls it, then builds a jQuery sequence but never uses it.
Try removing the carriage return between the two:
(function showNews(elem){
//...
})($(".news:first"));

Does javascript/jquery "hate" negative number as part of id name?

I have a snippet of JQuery code that do some bar scrolling.
Since I have three, four, ... n bar to slide into my PHP page, I assign them dinamically an id and pass it to JQuery for be sure that my snippet slide the correct bar on a mouseOver event.
That's the snippet of code that do the "inizialization" of my scrolls
(function($){
$.fn.horizontalScroll = function(options) {
var rid = arguments[0];
var oid = arguments[1];
var defaults = { };
var options = $.extend(defaults, options);
return this.each(function() {
var horiz_scroll = new dw_scrollObj($(this).attr('id'), $(this).children().attr('id'), $(this).children().children().attr('id'));
horiz_scroll.setUpScrollbar("dragBar_"+rid+"_offer_"+oid, "track_"+rid+"_offer_"+oid, "h", 1, 1);
horiz_scroll.setUpScrollControls('scrollbar_'+rid+'_offer_'+oid);
As you can see, "dragBar_"+rid+"_offer_"+oid dinamically concatenates my id(s) to other string part.
That's fine and all goin' well, except when my oid became something like -1
In that case I have an error that says
identifier starts immediately after numeric literal
That's confuse me, because i've read on StackOverflow some questions like this (just a random one) and I expect that behaviour for all concatenation that involves number.
That the snippet of code where all "breaks"
this.timerId = setInterval(this.animString + ".scroll()", 10);
Where this.animString is "dw_scrollObj.col.horiz_container_outer_55_offer_-1" while in other case (where it works) is "dw_scrollObj.col.horiz_container_outer_62_offer_234"
Anyone can explain me why this happen?
You are trying to access a global variable named dw_scrollObj.col.horiz_container_outer_55_offer_-1. Some browsers will make all elements accessible by their ID like that, but it's not recommended.
The reason it doesn't work in your specific case is that what you've written is not a valid javascript variable name. Your attempt to access a variable will be interpreted as
dw_scrollObj.col.horiz_container_outer_55_offer_ - 1
If you would instead access your object by
document.getElementById('dw_scrollObj.col.horiz_container_outer_55_offer_-1')
or
$('#dw_scrollObj.col.horiz_container_outer_55_offer_-1')
you would not have this same problem.
For your setInterval code, that would mean
this.timerId = setInterval("$('#" + this.animString + "').scroll()", 10);
or preferably
this.timerId = setInterval(function() {
$('#' + this.animString).scroll();
}, 10);
If your code is in a loop, where animString will change over time, inside the context, you will need to create a new closure:
this.timerId = setInterval((function(x) {
return function() {
$('#'+x).scroll();
};
})(this.animString), 10);
Your setInterval snippet breaks because the string you pass to setInterval is evaluated as JavaScript. It becomes
dw_scrollObj.col.horiz_container_outer_55_offer_-1.scroll()
but a hyphen (-) is not valid in identifiers.
E.g. this throws an error
var some-name = 'foo';

Why is setInterval calling a function with random arguments?

So, I am seeing a curious problem. If I have a function
// counter wraps around to beginning eventually, omitted for clarity.
var counter;
cycleCharts(chartId) {
// chartId should be undefined when called from setInterval
console.log('chartId: ' + chartId);
if(typeof chartId == 'undefined' || chartId < 0) {
next = counter++;
}
else {
next = chartId;
}
// ... do stuff to display the next chart
}
This function can be called explicitly by user action, in which case chartId is passed in as an argument, and the selected chart is shown; or it can be in autoplay mode, in which case it's called by a setInterval which is initialized by the following:
var cycleId = setInterval(cycleCharts, 10000);
The odd thing is, I'm actually seeing the cycleCharts() get a chartId argument even when it's called from setInterval! The setInterval doesn't even have any parameters to pass along to the cycleCharts function, so I'm very baffled as to why chartId is not undefined when cycleCharts is called from the setInterval.
setInterval is feeding cycleCharts actual timing data ( so one can work out the actual time it ran and use to produce a less stilted response, mostly practical in animation )
you want
var cycleId = setInterval(function(){ cycleCharts(); }, 10000);
( this behavior may not be standardized, so don't rely on it too heavily )
It tells you how many milliseconds late the callback is called.
var cycleId = setInterval(cycleCharts, 10000, 4242);
From the third parameter and onwards - they get passed into the function so in my example you send 4242 as the chartId. I know it might not be the answer to the question you posed, but it might the the solution to your problem? I think the value it gets is just random from whatever lies on the stack at the time of passing/calling the method.

Categories

Resources