Convert script for working with multiple instances - javascript

Lets see this script, that it's a simple carrousel
$script = {
init: function(){
this.heros(3000);
},
heros: function (time) {
var t;
var $hero = $('.hero');
var $images = $('.hero > div');
$hero.data('current', 0);
var $bullets = $('<div>').addClass('bullets');
for ( var i = 0; i<$images.length; i++ ) {
var $item = $('<span>');
$item.on('click', function () {
clearTimeout(t);
play( $(this).index() );
});
if(i==0) { $item.addClass('active') }
$bullets.append( $item );
}
var play = function (current) {
if(current==undefined) {
current = $hero.data('current');
}
var nextMargin;
if ( (current+1) == $images.length ) {
nextMargin = 0 ;
$hero.data('current',0);
} else {
nextMargin = (current + 1 )*100;
$hero.data('current', (current + 1));
}
$images.eq(0).css('marginLeft', -nextMargin + '%');
$bullets.find('span').eq($hero.data('current')).addClass('active').siblings().removeClass('active');
clearTimeout(t);
t = setTimeout(play, time);
}
$hero.append($bullets);
t = setTimeout(play, time);
},
}
The thing is that it works great, but only if there's just one .hero element.. if there are multiple the bullets mix up and it doesn't respect the .length
I know that option one should be rewrite it again, but Does anyone of you sees a quick fix that would make it reusable?
A single fiddle: https://jsfiddle.net/6z8n5pnq/
A multiple fiddle: https://jsfiddle.net/6z8n5pnq/1/
-EDIT-
I tried:
Defining a previous function, that is called on init
preheros: function(time) {
var self = this;
$('.heros').each(function(){
self.heros($(this), time);
});
},
And editing The begining of heros:
heros: function ($hero, time) {
var t;
/*var $hero = $('.hero');*/
var $images = $hero.find('>div');
but no success...
any idea?
-EDIT-
GOD, it's $('.hero').each not $('.heros').each it was working!

The easiest way to do this is to isolate context for each .hero component by using $(selector).each function. Slightly corrected your fiddle https://jsfiddle.net/6z8n5pnq/2/
function apply($hero, time){
var t;
var $images = $hero.children('div');
//all your logic here...
}
$script = {
init: function () {
this.heros(3000);
},
heros: function (time) {
$('.hero').each(function(){
apply($(this), time);
});
},
}

Related

How to stop function from another function then start it again with another parameter

i am trying to make a slider, i have function that getting array of objects and loop it, and i have select that change models list, but when i change select, old instance of function still work, they are starting to work together. So i add function stopper, but it wont work. Help please, thank you!
var keepGoing = true;
function slideList(models) {
$.each(models, function (index, model) {
setTimeout(function () {
if (keepGoing != false) {
moditem.innerHTML = "";
modlist.value = model.id;
var photo = document.createElement('IMG');
photo.src = model.photos[0].file;
photo.classList.add('img');
moditem.appendChild(photo);
if (index >= models.length - 1) {
slideList(models);
}
} else {
return false;
}
},
5000 * index);
});
}
function startLoop() {
keepGoing = true;
}
function stopLoop() {
keepGoing = false;
}
$("#car-type-select").on('change', function () {
stopLoop();
getModels(this.value);
});
Clear timeout:
var timer;
function slideList(models) {
$.each(models, function (index, model) {
timer = setTimeout(function () {
moditem.innerHTML = "";
modlist.value = model.id;
var photo = document.createElement('IMG');
photo.src = model.photos[0].file;
photo.classList.add('img');
moditem.appendChild(photo);
if (index >= models.length - 1) {
slideList(models);
}
},
5000 * index);
});
}
$("#car-type-select").on('change', function () {
clearTimeout(timer);
getModels(this.value);
});
Other unimportant functions
function getModels(cartype_id) {
$.ajax({
type: 'POST',
url: '/home/models/get',
data: {
'cartype_id': cartype_id
},
success: function (models) {
makeList(models);
slideList(models)
}
});
}
function makeList(models) {
modlist.innerHTML = "";
$.each(models, function (index, model) {
var option = document.createElement("option");
option.text = model.manufacturer.name + ' ' + model.name;
option.value = model.id;
modlist.add(option);
});
}
You need to use clearTimeout to stop function in setTimout to stop executing.
Example:
var timer = setTimeout(function(){ /* code here */ }, 3000)
clearTimeout(timer) //it will stop setTimeout function from executing.
After looking at code update:
Can you please try:
var timers = [];
function slideList(models) {
$.each(models, function(index, model) {
timers.push(setTimeout(function() {
moditem.innerHTML = "";
modlist.value = model.id;
var photo = document.createElement('IMG');
photo.src = model.photos[0].file;
photo.classList.add('img');
moditem.appendChild(photo);
if (index >= models.length - 1) {
slideList(models);
}
},
5000 * index));
});
}
$("#car-type-select").on('change', function() {
$.each(timers, function(i, timer) {
clearTimeout(timer);
})
getModels(this.value);
});
setTimeout is getting called in loop to need array of setTimeout references

javascript, setInterval function starts counting not from 0

I have noticed, that my setInterval function starts counting from 1, and sometimes even from 10. But if i increase the interval to some 20 seconds, it starts counting correctly from 0. Subsequent counting is correct - adds one in every step, but the initial cnt value, if i reduce to internval to some 5 seconds, becomes wrong.
var stepProt = function () {
console.log('started stepProt constructor');
this.step = 20; //seconds
this.cnt = 0; //init counter, pointer to rtArr
};
stepProt.prototype.countingFnc = function () {
console.log('started stepFnc.prototype.countingFnc');
var msec = this.step*1000;
var that = this;
that.cnt=0;
this.nameToStop = window.setInterval( function () {
that.stepFnc(); }, msec );
}
stepProt.prototype.stepFnc = function() {
console.log (' 132 startedFnc rtG.prototype.stepFnc, this.cnt='+this.cnt ); //if interval is 5seconds, this.cnt usually starts from 1, but sometimes from 10, instead of starting from 0. All other steps are correct, +1 each time.
/* here there is some logics, which takes time */
this.cnt++;
};
var stepIn = new stepProt(); //instance
stepIn.stepFnc();
What could be the reason and how to resolve?
p.s.
Actually, i use this function before window onload. Maybe this is the reason?
I include many scripts before window.onload.
Later i make single script for window.onload functionality.
I put
var stepIn = new stepFnc(); //instance
stepIn.stepFnc();
before window onload, because if i use it in window.onload, for some reason, other functions does not understand stepIn instance as a global variable accessable everythere. Maybe it is because i use php template.
You should call stepIn.countingFnc(); to start the process. Another thing is that I'd change the name of the function stepFnc so it doesn't match with the constructor name for readability.
var stepFnc = function () {
console.log('started stepFnc constructor');
this.step = 20; //seconds
this.cnt = 0; //init counter, pointer to rtArr
};
stepFnc.prototype.countingFnc = function () {
console.log('started stepFnc.prototype.countingFnc');
var msec = this.step*1000;
var that = this;
that.cnt=0;
this.nameToStop = setInterval( function () {
that.triggerFnc(); }, msec );
}
stepFnc.prototype.triggerFnc = function() {
console.log (' 132 startedFnc rtG.prototype.stepFnc, this.cnt='+this.cnt ); //if interval is 5seconds, this.cnt usually starts from 1, but sometimes from 10, instead of starting from 0. All other steps are correct, +1 each time.
/* here there is some logics, which takes time */
this.cnt++;
};
var stepIn = new stepFnc();
stepIn.countingFnc();
Hope this helps. ;)
var stepFnc = function () {
console.log('started stepFnc constructor');
this.step = 1; //seconds
this.cnt = 0; //init counter, pointer to rtArr
};
stepFnc.prototype.countingFnc = function () {
console.log('started stepFnc.prototype.countingFnc');
var msec = this.step*1000;
var that = this;
that.cnt=0;
this.nameToStop = window.setInterval( function () {
that.stepFnc(); }, msec );
};
stepFnc.prototype.stepFnc = function() {
console.log (' 132 startedFnc rtG.prototype.stepFnc, this.cnt='+this.cnt ); //if interval is 5seconds, this.cnt usually starts from 1, but sometimes from 10, instead of starting from 0. All other steps are correct, +1 each time.
/* here there is some logics, which takes time */
this.cnt++;
};
var stepIn = new stepFnc();
stepIn.countingFnc();
Seems the reason is that i use setInterval in script not in window.onload, thus the first counter is wrong. I created function to check if javascript is loaded, and than i use boolen in setInterval to start counting only after the all javascript is loaded.
var loadIn - checks if javascript is loaded ,and sets loadIn.jsLoad =true.
if(loadIn.jsLoad) { that.stepFnc(); }
Code checking if
javascript is loaded : this.jsLoad = true (mainly i need this),
html is loaded : this.htmlLoad= true,
both js and html are loaded: this.bLoaded =true
console.log('loading check started' );
var loadProt = function () {
this.bLoaded = "";
this.checkLoadInt="";
this.jsLoadFnc="";
this.bDomainCheckPass = false; //assumes that domain is wrong
this.beforeunload = ""; //event
this.jsLoad = false;
this.htmlLoad = false;
this.bLoaded =false;
};
loadProt.prototype.checkLoadFnc = function() {
console.log('startedFnc checkLoadFnc');
this.htmlLoad = false;
this.jsLoad = false;
if(document.getElementById("bottomPreloadSpan")) { this.htmlLoad =true; }
this.jsLoad = this.jsLoadFnc();
console.log( 'htmlLoad='+this.htmlLoad +', jsLoad=' +this.jsLoad ) ;
this.bLoaded = this.htmlLoad && this.jsLoad;
if( this.bLoaded ) {
this.stopIntervalFnc();
}
};
loadProt.prototype.stopIntervalFnc = function() {
console.log('startedFnc stopIntervalFnc');
document.getElementById("preloadSpan").style.visibility = "hidden";
var preloadImg = document.getElementById('preloadImage');
preloadImg.parentNode.removeChild(preloadImg);
clearInterval(this.checkLoadInt);
this.bDomainCheckPass = this.checkAllowedDomains(); // i do not give it here
//this.evalStep();
if(this.bDomainCheckPass) {
console.log('ERROR right domain');
} else {
console.log('ERROR Wrong domain');
//window.location.assign loads a new document - to login page, saying you was redirected ....
}
}
var loadIn = new loadProt();
loadIn.checkLoadInt = window.setInterval(
function() { loadGIn.checkLoadFnc(); }, 1000 );
loadIn.jsLoadFnc = document.onreadystatechange = function () { return (document.readyState=='complete') ? true : false ; }
Counter function:
var stepProt = function () {
console.log('started stepFnc constructor');
this.step = 20; //seconds
this.cnt = 0; //init counter, pointer to rtArr
};
stepProt.prototype.countingFnc = function () {
console.log('started stepFnc.prototype.countingFnc');
var msec = this.step*1000;
var that = this;
that.cnt=0;
this.nameToStop = window.setInterval( function () {
if(loadIn.jsLoad) { that.stepFnc(); }
}, msec );
}
stepProt.prototype.stepFnc = function() {
console.log (' 132 started stepFnc, this.cnt='+this.cnt );
/* here there is some logics, which takes time */
this.cnt++;
};
var stepIn = new stepProt(); //instance
stepIn.countingFnc();

Jquery Mobile stopwatch

Im trying to make a stopwatch in a JqueryMobile app. I've been following the guide from a previous post How to create a stopwatch using JavaScript?
This works but the function to create the button, essential just makes 3 links, where as I want them as buttons. So at present it will generate the html of:
start
where as I need it to be
start
I've played around with the function to try to get it to work, and even just added my own buttons into the HTML with hrefs of #start, #stop, #reset but cant get them to work
The function is:
function createButton(action, handler) {
var a = document.createElement("a");
a.href = "#" + action;
a.innerHTML = action;
a.addEventListener("click", function(event) {
handler();
event.preventDefault();
});
return a;
}
Add the classes ui-btn ui-btn-inline to the links in createButton. As you are using jQuery anyway, I hvae also updated the stopwatch to use jQuery for DOM manipulation:
(function($) {
var Stopwatch = function (elem, options) {
var timer = createTimer(),
startButton = createButton("start", start),
stopButton = createButton("stop", stop),
resetButton = createButton("reset", reset),
offset,
clock,
interval;
// default options
options = options || {};
options.delay = options.delay || 1;
var $elem = $(elem);
// append elements
$elem.empty()
.append(timer)
.append(startButton)
.append(stopButton)
.append(resetButton);
// initialize
reset();
// private functions
function createTimer() {
return $('<span class="swTime"></span>');
}
function createButton(action, handler) {
var a = $('<a class="' + action + ' ui-btn ui-btn-inline">' + action + '</a>');
a.on("click",function (event) {
handler();
event.preventDefault();
});
return a;
}
function start() {
if (!interval) {
offset = Date.now();
interval = setInterval(update, options.delay);
}
}
function stop() {
if (interval) {
clearInterval(interval);
interval = null;
}
}
function reset() {
clock = 0;
render();
}
function update() {
clock += delta();
render();
}
function render() {
timer.text(clock / 1000);
}
function delta() {
var now = Date.now(),
d = now - offset;
offset = now;
return d;
}
// public API
this.start = start;
this.stop = stop;
this.reset = reset;
};
$.fn.stopwatch = function(options) {
return this.each(function(idx, elem) {
new Stopwatch(elem, options);
});
};
})(jQuery);
$(document).on("pagecreate","#page1", function(){
$(".stopwatch").stopwatch();
});
DEMO

Init a function into a specific div

I have this code
var wrapper = {
init: function (elemClass) {
this.className = elemClass || '.full-description';
this.wrapElems();
},
wrapElems: function () {
var $lines = $(this.className),
holder = [];
$lines.each(function (i, item) {
holder.push(item);
if (holder.length === 2) {
$(holder).wrapAll('<div class="w-row" />');
holder.length = 0;
}
});
$(holder).wrapAll('<div class="w-row" />');
}
};
wrapper.init();
I want to init the wrapper into a specific div, I try this
var init = wrapper.init();
$("#div-content").append(init);
It does not work.
Thanks for the help
you can append like this
$("#div-content").append("<script>wrapper.init();</script>");

"$.______ is not a function" error. What is wrong?

I'm trying to add an image rotator to my site but for some reason firebug tells me the function I need to call to start the rotator isn't defined. My jQuery file is loading just fine and the image rotator script is loading so I'm not sure what is wrong. The site is heritage.newcoastmedia.com but I'll go ahead and post the script:
;(function($) {
$.fn.featureList = function(options) {
var tabs = $(this);
var output = $(options.output);
new jQuery.featureList(tabs, output, options);
return this;
};
$.featureList = function(tabs, output, options) {
function slide(nr) {
if (typeof nr == "undefined") {
nr = visible_item + 1;
nr = nr >= total_items ? 0 : nr;
}
tabs.removeClass('current').filter(":eq(" + nr + ")").addClass('current');
output.stop(true, true).filter(":visible").fadeOut();
output.filter(":eq(" + nr + ")").fadeIn(function() {
visible_item = nr;
});
}
var options = options || {};
var total_items = tabs.length;
var visible_item = options.start_item || 0;
options.pause_on_hover = options.pause_on_hover || true;
options.transition_interval = options.transition_interval || 5000;
output.hide().eq( visible_item ).show();
tabs.eq( visible_item ).addClass('current');
tabs.click(function() {
if ($(this).hasClass('current')) {
return false;
}
slide( tabs.index( this) );
});
if (options.transition_interval > 0) {
var timer = setInterval(function () {
slide();
}, options.transition_interval);
if (options.pause_on_hover) {
tabs.mouseenter(function() {
clearInterval( timer );
}).mouseleave(function() {
clearInterval( timer );
timer = setInterval(function () {
slide();
}, options.transition_interval);
});
}
}
};
});
And here is the script to start the image rotator:
<script language="javascript">
$(document).ready(function() {
$.featureList(
$("#tabs li a"),
$("#output li"), {
start_item : 1
}
);
});
</script>
Your code creates an anonymous function, but doesn't call it.
You need to call the function by adding (jQuery) at the end.
You cannot do $.featureList(
See Chrome error:
The plugin needs to applied to an object
You've just slightly missed out on the right syntax for creating a plugin. What you really want is:
(function($) {
$.fn.featureList = function() { // etc; }
$.featureList = function() { // yet more etc; }
})(jQuery);

Categories

Resources