I'm trying to execute a rotating banner (Calling it through an array). I set an interval but the image only shows after 10 seconds (10000) and only then begins the rotation. I removed the cluttered HTML of the array, but here's the rest of it:
var current = 0;
var banners = new Array();
banners[0]=;
banners[1]=;
banners[2]=;
banners[3]=;
var myTimeout = setInterval("rotater()",10000);
function rotater() {
document.getElementById("placeholderlayer").innerHTML=banners[current];
if(current==banners.length-1){
current = 1;
}else{
current += 1;
}
}
window.onload = rotater();
window.onload = rotater;
is the correct syntax. You don't want to call the function. However, the bulletproof solution is rather this:
onload = function() {
rotater();
window.myTimeout = setInterval(rotater, 10000); // Never pass a string to `setInterval`.
};
ProTip™: Don't use new Array(), use an array literal. For example, this:
var arr = new Array();
arr[0] = 'Hello';
arr[1] = 'world!';
Should be written as:
var arr = ['Hello', 'world!'];
Just a comment:
Instead of:
if(current==banners.length-1) {
current = 1;
} else {
current += 1;
}
you can do:
current = ++current % banners.length;
Related
This is all the js code, when i console log the raw variable it returns the shuffled deck, I do not understand that, i am new to js and i've tried this. but i don't really know how it works, also, what's the difference between var and let if you guys dont mind me asking? thank you.
function drawDeck(){
var deck = []
var value = [2,3,4,5,6,7,8,9,10,10,10,10,11]
for(var i=0;i<4;i++){
for (var j=0;j<13;j++){
deck.push(value[j])
}
}
return deck
}
function shuffleDeck(deck){
var currentPos = deck.length, tempPos , randPos
while (currentPos != 0){
randPos = Math.floor(Math.random() * currentPos)
currentPos -= 1
tempPos = deck[currentPos]
deck[currentPos] = deck[randPos]
deck[randPos] = tempPos
}
return deck
}
function drawCard(deck){
var card = deck.shift()
return card
}
var raw = drawDeck()
var deck = shuffleDeck(raw)
var card = drawCard(deck)
console.log(raw)
The shuffle function operates on the input element itself. Since you input raw to the shuffle function it self will be modified and thus you get the shuffled deck when logging it. It doesn't matter if it gets returned or not.
If you wanna preserve the original array, clone the array to a new variable inside the shuffle function and do the shuffling on the clone and return that.
var raw = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];
var shuffled;
function shuffleDeck(deck) {
var currentPos = deck.length,
tempPos, randPos
var tempDeck = Array.from(deck);
while (currentPos != 0) {
randPos = Math.floor(Math.random() * currentPos)
currentPos -= 1
tempPos = tempDeck[currentPos]
tempDeck[currentPos] = tempDeck[randPos]
tempDeck[randPos] = tempPos
}
return tempDeck
}
shuffled = shuffleDeck(raw);
alert('original: ' + raw);
alert('shuffled: ' + shuffled);
I have 3 messages in variables.
var msg1 = "hello1";
var msg2 = "hello2";
var msg3 = "hello3";
I am trying to create a function that when i click it the first time it console.log(msg1), when i click it the second time it console.log(msg2), 3rd time console.log(msg3), 4th time console.log(msg1) and 5th msg2 etc.
$scope.clickMsg = function () {
console.log(msg1);
}
i've tried loops, timers etc but i could not make it work.
Does anyone know how to do this?
Use an array instead, and it's a bit easier, you'd just increment a number on each click, and use that number to select the item from the array
var msg = [
"hello1",
"hello2",
"hello3"
];
var i = 0;
var $scope = {};
$scope.clickMsg = function () {
console.log( msg[i] );
i++; // increment
if (i === msg.length) i = 0; // reset when end is reached
}
document.getElementById('test').addEventListener('click', $scope.clickMsg)
<button id="test">Click</button>
ES6 Generators based version:
var messages = (function*() {
for(;;) { yield msg1; yield msg2; yield msg3; }
})()
$scope.clickMsg = function () {
console.log(messages.next().value);
}
Unlike other answers, does not require you to use a different datatype and will also work for the locally scoped variables (i.e. non-window scoped variables).
Try It Online !
There are a few ways to do this in terms of accessing the string, I'd recommend putting them into an array rather than accessing the global/scoped object but it's up to you. Anyway on to the code.
var messagesArray = ["hello1", "hello2", "hello3"];
var messagesObject = {
msg1: "hello1",
msg2: "hello2",
msg3: "hello3"
}
var counter = 0;
function LogMessage() {
console.log(messagesArray[counter % 3]);
console.log(messagesObject["msg" + (counter % 3 + 1)]);
counter++
}
<button onclick="LogMessage()">Click Me</button>
Simply use with increment value like this
var msg1 = "hello1";
var msg2 = "hello2";
var msg3 = "hello3";
var c = 1;
$scope.clickMsg = function () {
c = c > 3 ? 1 : c;
console.log(window['msg'+c])
c++;
}
Working snippet
var msg1 = "hello1";
var msg2 = "hello2";
var msg3 = "hello3";
var c = 1;
var $scope={} //for testing
$scope.clickMsg = function () {
c = c > 3 ? 1 : c;
console.log(window['msg'+c])
c++;
}
function check(){ //for testing
$scope.clickMsg();
}
<button onclick="check()">click</button>
The alternative is using scopes, defining them as
this["msg"+i] = "some stuff";
and retrieving them as
this.msg0;
just do something like this, will work for you, make sure you reset it back if needed or do something, otherwise after first loop, you get undefined:
var msgs = ["hello1","hello2","hello3"], i=0;
$scope.clickMsg = function() { //angular $scope for example
console.log(msgs[i]);
if(i < msgs.length-1) {
i++;
} else {
i=0; //reset the loop
}
}
I have certain timers which are updating every second. I want to execute some function on change of timer variable. If anyone can help me out. I have provided the code below.
for(var i=0; i<listingTime.length; i++){
if (listingTime[i].time >= 0) {
var second = listingTime[i].time / 1000;
var currentHour = parseInt(second / 3600);
}
}
Here, I want to detect change of currentHour variable.
You can set a previous value variable prior to the loop, and whenever updating the currentHour, just match it with previousValue variable. If they are same, they are not changes, if they are not same, it is changed and you can execute the callback.
One more other way is to use the object prototypes to changes the value of currentHour. Following code shows that:
Above code can be modified to following to add a changeListner
var HourListner = {
currentHour: null,
update: function(newValue, callback){
if(this.currentHour !== newValue){
this.currentHour = newValue;
callback(newValue);
}
}
}
timer = Object.create(HourListner);
var changeListner = function(value){
//value is the new value of currentHour
console.log(value)
}
for(var i=0; i<listingTime.length; i++){
if (listingTime[i].time >= 0) {
var second = listingTime[i].time / 1000;
var currentHour = parseInt(second / 3600);
timer.update(currentHour, changeListner)
}
}
And the trick can be tested independently in following code:
var HourListner = {
currentHour: null,
update: function(newValue, callback) {
if (this.currentHour !== newValue) {
this.currentHour = newValue;
callback(newValue);
}
}
}
timer = Object.create(HourListner);
var changeListner = function(value) {
//value is the new value of currentHour
console.log(value)
$('body').append('<p>'+value+'</p>')
}
var interval = setInterval(function(){
var t = new Date();
timer.update(t.getMinutes(), changeListner)
}, 200)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
This will execute the changeListner if there is a change from previous value.
Hi I want to use 3 different counters that show me 3 different increasing numbers starting from a certain date. I've tryed this:
<script>
var START_DATE_1 = new Date("July 18, 2016 10:30:00"); // put in the starting date here
var INTERVAL_1 = 5; // in seconds
var INCREMENT_1 = 1; // increase per tick
var START_VALUE_1 = 0; // initial value when it's the start date
var count_1 = 0;
window.onload = function()
{
var msInterval_1 = INTERVAL_1 * 1000;
var now_1 = new Date();
count_1 = parseInt((now_1 - START_DATE_1)/msInterval_1) * INCREMENT_1 + START_VALUE_1;
document.getElementById('counter_1').innerHTML = count_1;
setInterval("count_1 += INCREMENT_1; document.getElementById('counter_1').innerHTML = count_1;", msInterval_1);
}
</script>
<script>
var START_DATE_2 = new Date("July 18, 2016 10:30:00"); // put in the starting date here
var INTERVAL_2 = 5; // in seconds
var INCREMENT_2 = 1; // increase per tick
var START_VALUE_2 = 0; // initial value when it's the start date
var count_2 = 0;
window.onload = function()
{
var msInterval_2 = INTERVAL_2 * 1000;
var now_2 = new Date();
count_2 = parseInt((now_2 - START_DATE_2)/msInterval_2) * INCREMENT_2 + START_VALUE_2;
document.getElementById('counter_2').innerHTML = count_2;
setInterval("count_2 += INCREMENT_2; document.getElementById('counter_2').innerHTML = count_2;", msInterval_2);
}
</script>
<script>
var START_DATE_3 = new Date("July 18, 2016 10:30:00"); // put in the starting date here
var INTERVAL_3 = 5; // in seconds
var INCREMENT_3 = 1; // increase per tick
var START_VALUE_3 = 0; // initial value when it's the start date
var count_3 = 0;
window.onload = function()
{
var msInterval_3 = INTERVAL_3 * 1000;
var now_3 = new Date();
count_2 = parseInt((now_3 - START_DATE_3)/msInterval_3) * INCREMENT_3 + START_VALUE_3;
document.getElementById('counter_3').innerHTML = count_2;
setInterval("count_3 += INCREMENT_3; document.getElementById('counter_3').innerHTML = count_3;", msInterval_3);
}
</script>
<div id="counter_1"></div>
<div id="counter_2"></div>
<div id="counter_3"></div>
This doesn't work as expected and only the 3td div is populated but now working as expected too (as soon as I load the page it show me a number then after few seconds restart from 1).
What's wrong? How should I do it without using JQuery also?
Thanks in advance.
I don't do a code analysis - this would be something for SE-CodeReview (highly recommended to post there too once you got it working), but your error is, that you are assigning something to a function more than once - hence, only the last assignment is actually called onload.
So -- you are assigning window.onload = function() in your first <script> tag, then you are overriding it in your second; and you're overriding the second assignment again in your third <script> tag.
You can't do that if you want to assign all 3 functions to a single (onload) event.
If you want to add multiple listeners for a single event, use
document.addEventListener("DOMContentLoaded", function() {});
Now inside that function, you can add all your code that you want to have executed onload of your page; in addition to the code you wanted to have executed onload in another function!
Here's a simple demonstration using the same techniques as described above, but with click listeners. Notice the first function will never be called.
document.getElementById("a").onclick = function() {
alert("I will never alert, because of the next function");
}
document.getElementById("a").onclick = function() {
alert("I will alert, because I'm not overriden");
}
document.getElementById("a").addEventListener('click', function() {
alert("I will alert too");
});
document.getElementById("a").addEventListener('click', function() {
alert("And a third alert. Disturbing");
});
<div id="a">Click me!</div>
I have this closure :
function CFetchNextData(ofs, pag, fetchFunction) {
var offset = ofs;
var limit = pag;
return function(options, cb) {
//do stuff to create params
fetchFunction(params, cb);
offset += limit;
};
}
I then create a variable this way:
var fetchInfo = CFetchNextData(0, 10, specificFetchFunction);
fetchInfo(options, myCB);
So that everytime I call fetchInfo, pagination is automatically set to the next set of data. That works great, althought
I'd like to have multiple instance of : "fetchInfo", each one having its own scope.
var A = fetchInfo; // I'd like a clone with its own scope, not a copy
var B = fetchInfo; // I'd like a clone with its own scope, not a copy
I could do:
var A = new CFetchNextData(ofs, pag, fetchFunction);
var B = new CFetchNextData(ofs, pag, fetchFunction);
But obviously I would have to setup "ofs" and "pag" each time, whereas by cloning fetchInfo, I'd have a stable pagination, set only once and for good.
Do you know how to achieve that ?
Thanks in advance
There isn't a concept of cloning a function in JavaScript. You need to call CFetchNextData (or another function) multiple times if you want to create multiple closures.
You could have CFetchNextData return a factory function instead of returning the actual function. But I'm not sure that's really an improvement.
function CFetchNextDataFactory(ofs, pag, fetchFunction) {
return function() {
var offset = ofs;
var limit = pag;
return function(options, cb) {
//do stuff to create params
fetchFunction(params, cb);
offset += limit;
};
};
}
var fetchInfoFactory = CFetchNextData(0, 10, specificFetchFunction);
var A = fetchInfoFactory();
var B = fetchInfoFactory();
This may not answer all of your question but just to pitch in , you could try assigning your parameters to a default / fallback value which will allow you to avoid setting ofs and pag each declaration . Below is a prototype of what I came up with . Its using oop :
class CFetchNextData {
constructor(ofs, pag){
this.OFS = 1; //default value
this.PAG = 10; //default value
this.ofs = ofs;
this.pag = pag;
if(ofs == null || ofs == undefined){
this.ofs = this.OFS;
}
if(pag = null || pag == undefined){
this.pag = this.PAG;
}
}
fetchInfo(){
var data = this.ofs += this.pag;
return data;
}
}
var task1 = new CFetchNextData(); // Falls back to default values..
var task2 = new CFetchNextData(32,31); // Uses values from specified in args...
document.write(task1.fetchInfo() + "\n")
document.write(task2.fetchInfo())
Hope this helps...