I have a product page with images and product description that all loads dynamically from a json file. Everything works perfectly except for the owl carousel when I click on either the prev/next arrows. The main image and the data updates as it should, but the carousel does not.
I logged the new image urls and they are being updated properly.
I tried using this everywhere in the code
$("#owl-focus").trigger('refresh.owl.carousel');
This is the javascript for the page
// ========== Compile Product Data =======================================
$.getJSON("../../json/guitars.json", function(data) {
var jsonLength = data.length
// ------- Parse & Returns URL Parameters -----------------------------
function getUrlVars(guitar) {
var vars = {}
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
vars[key] = value;
})
return vars
}
// ------------ Append Clicked Image -------------------------------------
var guitar = parseInt(getUrlVars()["product"], 10)
loadGuitar(guitar)
function loadGuitar(guitar) {
// Images
var image1 = data[guitar].img1
var image2 = data[guitar].img2
var image3 = data[guitar].img3
var image4 = data[guitar].img4
var alt = data[guitar].alt
// description
var title = data[guitar].title
var brand = data[guitar].brand
var code = data[guitar].code
var price = data[guitar].price
var description = data[guitar].description
var specs = data[guitar].specs
$('#clickImg').attr({src: `../${image1}`, alt: `${alt}`})
$('#img1').attr({src: `../${image1}`, alt: `${alt}`})
$('#img2').attr({src: `../${image2}`, alt: `${alt}`})
$('#img3').attr({src: `../${image3}`, alt: `${alt}`})
$('#img4').attr({src: `../${image4}`, alt: `${alt}`})
$('#title').html(title)
$('#brand').html(brand)
$('#variant-sku').html(code)
$('#price').html(price)
$('#description').html(description)
$('#specs').empty();
specs.forEach(spec => {
$("#specs"). append(`<li>${spec}</li>`)
})
}
// -------------- Owl Carousel -------------------------------------------
$(document).ready(function () {
$('#owl-focus').owlCarousel({
loop: true,
margin: 10,
nav: true,
navText: [$('.owl-navigation .owl-nav-prev'), $('.owl-navigation .owl-nav-next')],
responsiveClass: true,
responsive: {
0: {
items: 3,
},
1050: {
items: 4,
}
}
})
})
// -------- Next / Previous Arrows -------------------------------------
$("#prev-btn").click(function() {
if (guitar === 0) {
guitar = jsonLength - 1
} else {
guitar = guitar - 1
}
loadGuitar(guitar)
onPageChg()
})
$("#next-btn").click(function() {
if (guitar === jsonLength - 1) {
guitar = 0
} else {
guitar = guitar + 1
}
loadGuitar(guitar)
onPageChg()
})
})
// ========== Compile Product Data End ===================================
Figured it out. Instead of trying to reload owl I reloaded the page as I should have with new data. Similar functions that take me to that product page in the first place with a few adjustments.
$("#prev-btn").on("click", function(e) {
$.getJSON("../../json/guitars.json", function(json) {
if (guitar === 0) {
new_id = jsonLength - 1
} else {
new_id = guitar - 1
}
window.location.href = "product.html?product=" + new_id
})
})
$("#next-btn").on("click", function(e) {
$.getJSON("../../json/guitars.json", function(json) {
if (guitar === jsonLength - 1) {
new_id = 0
} else {
new_id = guitar + 1
}
window.location.href = "product.html?product=" + new_id
})
})
Before I was just changing the attributes on the photos, description, etc
I'm stuck.. I want to create multiple range sliders with noUiSlider. Each slider has to handle between to values [0,100]; (min=0, max=100,). Moreover i need a output and input of values by handler and entered by User.
See my current code here:
function data ( element, key ) {
return element.getAttribute('data-' + key);
}
var connectSlider = document.getElementsByClassName('slider');
var input0 = document.getElementsByClassName('input-format-0');
var input1 = document.getElementsByClassName('input-format-1');
var inputs = [input0, input1];
function createSlider ( slider ) {
noUiSlider.create( connectSlider,{
start: [0, 100],
connect: false,
step: Number(data(slider, 'step')) || 1,
range: {
'min': [0],
'max': [100],
},
tooltips: true,
connect: true,
format: {
to: function (value) {
return value + '%';
},
from: function (value) {
return value.replace('%', '');
},
}
});
}
connectSlider.noUiSlider.on('update', function( values, handle ) {
inputs[handle].value = values[handle];
});
Array.prototype.forEach.call(document.querySelectorAll('.slider'), createSlider);
function setSliderHandle(i, value) {
var r = [null,null];
r[i] = value;
connectSlider.noUiSlider.set(r);
}
// Listen to keydown events on the input field.
inputs.forEach(function(input, handle) {
input.addEventListener('change', function(){
setSliderHandle(handle, this.value);
});
input.addEventListener('keydown', function( e ) {
var values = connectSlider.noUiSlider.get();
var value = Number(values[handle]);
// [[handle0_down, handle0_up], [handle1_down, handle1_up]]
var steps = connectSlider.noUiSlider.steps();
// [down, up]
var step = steps[handle];
var position;
// 13 is enter,
// 38 is key up,
// 40 is key down.
switch ( e.which ) {
case 13:
setSliderHandle(handle, this.value);
break;
case 38:
// Get step to go increase slider value (up)
position = step[1];
// false = no step is set
if ( position === false ) {
position = 1;
}
// null = edge of slider
if ( position !== null ) {
setSliderHandle(handle, value + position);
}
break;
case 40:
position = step[0];
if ( position === false ) {
position = 1;
}
if ( position !== null ) {
setSliderHandle(handle, value - position);
}
break;
}
});
});
<link href="https://refreshless.com/noUiSlider/distribute/nouislider.min.css" rel="stylesheet"/>
<script src="https://refreshless.com/noUiSlider/distribute/nouislider.js"></script>
<div class="rangefilter">
<div class="slider"></div>
<ul>
<li class="left"><input class="input-format-0" type="text"></li>
<li class="right"><input class="input-format-1" type="text"></li>
</ul>
</div>
Would be really nice if somebody could help me.
Thank's.
Best regards.
Faced a similar problem. Spent 3 days on the solution. The solution is not optimal. But now this is the best I can offer.
HTML:
<div class="custom-range-slider">
<span class="custom-range-slider__input-text">from</span>
<input class="custom-range-slider__input custom-range-slider__input--from" type="number">
<span class="custom-range-slider__input-text">to</span>
<input class="custom-range-slider__input custom-range-slider__input--to" type="number">
<div class="custom-range-slider__track"></div>
</div>
<br>
<br>
<br>
<div class="custom-range-slider">
<span class="custom-range-slider__input-text">from</span>
<input class="custom-range-slider__input custom-range-slider__input--from" type="number">
<span class="custom-range-slider__input-text">to</span>
<input class="custom-range-slider__input custom-range-slider__input--to" type="number">
<div class="custom-range-slider__track"></div>
</div>
<br>
<br>
<br>
<div class="custom-range-slider">
<span class="custom-range-slider__input-text">from</span>
<input class="custom-range-slider__input custom-range-slider__input--from" type="number">
<span class="custom-range-slider__input-text">to</span>
<input class="custom-range-slider__input custom-range-slider__input--to" type="number">
<div class="custom-range-slider__track"></div>
</div>
JS:
var rangeSlidersTrack = document.querySelectorAll('.custom-range-slider .custom-range-slider__track');
var rangeSlidersInputFrom = document.querySelectorAll('.custom-range-slider .custom-range-slider__input--from');
var rangeSlidersInputTo = document.querySelectorAll('.custom-range-slider .custom-range-slider__input--to');
var rangeSliderInputs = [];
for(var i = 0; i < rangeSlidersTrack.length; i++) {
rangeSliderInputs.push([rangeSlidersInputFrom[i], rangeSlidersInputTo[i]]);
}
[].slice.call(rangeSlidersTrack).forEach(function(slider, index) {
noUiSlider.create(slider, {
start: [0, 500],
connect: true,
range: {
'min': 0,
'max': 500
}
}).on('update', function(values, handle) {
rangeSliderInputs[index][handle].value = parseInt(values[handle]);
});
function setSliderHandle(i, value) {
var r = [null,null];
r[i] = value;
slider.noUiSlider.set(r);
}
rangeSliderInputs[index].forEach(function(input, handle) {
input.addEventListener('change', function(){
setSliderHandle(handle, this.value);
});
input.addEventListener('keydown', function(e) {
var values = slider.noUiSlider.get();
var value = Number(values[handle]);
// [[handle0_down, handle0_up], [handle1_down, handle1_up]]
var steps = slider.noUiSlider.steps();
// [down, up]
var step = steps[handle];
var position;
// 13 is enter,
// 38 is key up,
// 40 is key down.
switch (e.which) {
case 13:
setSliderHandle(handle, this.value);
break;
case 38:
// Get step to go increase slider value (up)
position = step[1];
// false = no step is set
if ( position === false ) {
position = 1;
}
// null = edge of slider
if ( position !== null ) {
setSliderHandle(handle, value + position);
}
break;
case 40:
position = step[0];
if ( position === false ) {
position = 1;
}
if ( position !== null ) {
setSliderHandle(handle, value - position);
}
break;
}
});
});
});
Fiddle
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Fist time i am using phaser.io, i am repeating background and also loading other thing in update function but after few second later my game is slowing time . it look like background is not moving more. Please have a look of my code and help me in for sort out this problem. Or please give any idea to change background repeatedly without changing other thing.
I have some code indentation problem sorry for that but please try to manage and help me.
Game.js
var scoreTxt, score, speed, scoreTextValue, ques_label, ques_label_pizza, scoreTextKey, timerTextValue, timerTextKey, textStyle_Key, textStyle_Value, anscloud, astroid1, astroid2, astroid3, astroid4;
/*var gameType;*/ //Pizza or Noun
var bullets, quesTextValue, ansTextValue, sprite;
var fireRate = 100;
var nextFire = 0;
var xAxis = [];
var yAxis = [];
var tempQues = [];
var tempAns = [];
var result = [];
var answear = [];
var ques = [];
var astroidContains = [];
var astroidContainsText = []; //['right', 'wrong', 'wrong', 'wrong']
var astroid, spaceShip, quesbar, diamond, randomAnsPosition;
var s1Copy;
var cloudContains = []; //['noun', 'pronoun', 'pronoun']
var QbarContainsQue = [];
var ans,rightans;
var isAnswerCorrect = false;
var allowClick = false;
var spaceShipXAxis = 40, loader1Width = 85, loader2Width = 70;
var bar, loader1, loader2, timer, timerSprite, timerSpriteCount = 0;
var timerCounter = 45; //timer counter will be of 45 seconds.
//var timerCounter_ = 100; //timer counter will be of 45 seconds.
var questCounter = 0; //question counter no. of question played.
var maxQuest = 10;//max questions will be displayed is 10.
var diamondTextColor = "#8D4FA8";
var defTextColor = "#5BEFFE";
var ansTextColor = "#9E13DA";
var errTextColor = '#FF0000';
var corrTextColor = '#228B22';
var corr_ans_fst;
var corr_ans_sec;
var fun_bckg, randQues;
var wrong_ans;
var barre1_x = 150;
var barre1_y = 115;
var healthValue = 100;
var x_loader = 180;
var check =0;
var setAns = [];
var setOne = [['12+16=','28'], ['15+11=','26'], ['16+22=','38'], ['13+14=','27'], ['15+24=','39'], ['14+12=','26'], ['10+17=','27'], ['11+11=','22'],
['13+15=','28'], ['12+21=','33'], ['24+13=','37'], ['33+21=','54'], ['40+18=','58'], ['34+31=','65'], ['25+42=','67'], ['22+15=','37'],
['24+12=','36'], ['20+15=','35'], ['25+14=','39'], ['21+21=','42'], ['41+25=','66'], ['53+24=','77'], ['35+31=','66'], ['62+37=','99'],
['54+35=','89']];
var setTwo = [['15+18=','33'], ['17+17=','34'], ['13+19=','32'], ['18+14=','32'], ['15+27=','42'], ['18+17=','35'], ['27+29=','56'], ['23+28=','51'],
['36+37=','73'], ['45+25=','70'], ['46+45=','91'], ['38+57=','95'], ['49+43=','92'], ['37+53=','90'], ['48+33=','81']];
var Game = {
preload : function() {
// Load the needed image for this(play) game screen.
//load the menu screen
this.load.image('menu', './assets/images/menu.png');
// Here we load all the needed resources for the level.
// background image screen
this.load.image('playgame', './assets/images/back.png');
// globe image screen
this.load.image('playgame', './assets/images/back.png');
// win image screen
//this.load.image('win', './assets/images/win.png');
// spaceship image screen
this.load.image('spaceship', './assets/images/spaceship.png');
// Question bar image screen
this.load.image('quesbar', './assets/images/quesbar.png');
// Diamond image screen
this.load.image('diamond', './assets/images/diamond.png');
// Astroid image screen
this.load.image('astroid1', 'assets/images/asteroid1.png');
this.load.image('astroid2', 'assets/images/asteroid2.png');
this.load.image('astroid3', 'assets/images/asteroid3.png');
this.load.image('astroid4', 'assets/images/asteroid4.png');
// Loader image screen
this.load.image('loaderbck', 'assets/images/loaderbck.png');
this.load.image('loader1', 'assets/images/loader1.png');
this.load.image('loader2', 'assets/images/loader2.png');
//Load the bullet
this.load.image('bullet', 'assets/images/bullet.png');
},
create : function() {
// By setting up global variables in the create function, we initialise them on game start.
// We need them to be globally available so that the update function can alter them.
textStyle_Value = { font: "bold 20px Segoe UI", fill: defTextColor, align: "center" };
textStyleAns = { font: "bold 22px 'Comic Sans MS', 'Comic Sans'", fill: ansTextColor, wordWrap: true, wordWrapWidth: 10, align: "center"};
textStyleQues = { font: "bold 20px 'Comic Sans MS', 'Comic Sans'", fill: defTextColor, wordWrap: true, wordWrapWidth: 10, align: "center"};
sprite = game.add.sprite(310, 485, 'spaceship');
sprite.anchor.set(0.5);
// Loading backround image
this.playBackground();
this.playBackground1();
// Additional Sprites, like cloud
this.addSprites();
// Loading spaceship image
//this.spaceship();
// Loading questionbar image
this.questionbar();
// Call fun. for ques
this.comeQus();
// csll fun. for place astroid
// this.astroid();
// call fun. for Ans
this.generateQues();
this.generateAns();
// Loading Diamond image
this.diamond();
// Start timer
this.startTimer();
// Set timer.
this.setTimer();
this.initLoader();
},
update: function() {
// The update function is called constantly at a high rate (somewhere around 60fps),
// updating the game field every time - also destroying previous objects and creating new.
// Our bullet group
//bullets.destroy();
sprite.destroy();
bullets = game.add.group();
bullets.enableBody = true;
bullets.physicsBodyType = Phaser.Physics.ARCADE;
bullets.createMultiple(200, 'bullet', 100, false);
bullets.setAll('anchor.x',0);
bullets.setAll('anchor.y', 0.9);
bullets.setAll('outOfBoundsKill', true);
bullets.setAll('checkWorldBounds', true);
//Repeating background..
if(playgame != null && playgame.body.y > 600) {
playgame.destroy();
this.playBackground();
}
if(playgame1.body.y > 0) {
playgame1.destroy();
this.playBackground1();
this.initLoader();
}
if(astroid1 != undefined) astroid1.destroy();
if(astroid2 != undefined) astroid2.destroy();
if(astroid3 != undefined) astroid3.destroy();
if(astroid4 != undefined) astroid4.destroy();
this.addSprites();
//timerTextValue.text = "00:" + timerCounter;
this.initLoader();
//destroing old diamond obj and creating new while change background
//diamond.destroy();
this.diamond();
//destroing old questionbar obj and creating new while change background
quesbar.destroy();
this.questionbar();
//Call comeQus, comeAns for show ques and ans at every background change
// quesTextValue.destroy();
if(quesTextValue != undefined) quesTextValue.destroy();
this.comeQus();
//ansTextValue.destroy();
if(ansTextValue != undefined) ansTextValue.destroy();
this.comeAns();
if (game.input.activePointer.isDown) {
this.fire();
}
allowClick = true;
},
playBackground: function() {
// console.log("playBackground called");
playgame = this.add.sprite(0, 0, 'playgame', 5);
playgame.scale.set(1);
playgame.smoothed = false;
anim_playgame = playgame.animations.add('walk');
anim_playgame.play(10, true);
this.physics.enable(playgame, Phaser.Physics.ARCADE);
playgame.body.velocity.y = 50;
},
playBackground1: function() {
//console.log("playBackground1 called");
//Second background..
playgame1 = this.add.sprite(0, -600, 'playgame', 5);
playgame1.scale.set(1);
playgame1.smoothed = false;
anim_playgame1 = playgame1.animations.add('walk');
anim_playgame1.play(10, true);
this.physics.enable(playgame1, Phaser.Physics.ARCADE);
playgame1.body.velocity.y = 50;
},
questionbar: function() {
quesbar = game.add.image(10, 530, 'quesbar');
},
diamond: function() {
diamond = game.add.image(680, 20, 'diamond');
},
addSprites: function() {
// loading answer cloud
astroid1 = this.add.button(30, 90, 'astroid1', this.astroidClicked, this);
astroid2 = this.add.button(220, 30, 'astroid2', this.astroidClicked, this);
astroid3 = this.add.button(400, 40, 'astroid3', this.astroidClicked, this);
astroid4 = this.add.button(600, 90, 'astroid4', this.astroidClicked, this);
},
inCorrectAnswerHit: function(index) {
allowClick = false;
isAnswerCorrect = false;
//this.playFx('wrong_ans');
for(i=0; i<=3; i++) {
if(cloudContains[i] == "right") {
//cloudContainsText[i].fill = corrTextColor;
console.log("right ans hit");
break;
}
}
},
checkAnswer: function(index) {
// If clicked Ans is right so astroid will destroy.
if(astroidContainsText[index] == "wrong") {
//Here collization function will call
isAnswerCorrect = true;
}
// If clicked word is noun (correct answer) and obstacle is redbird or blackbird - the dude will slide.
else {
this.inCorrectAnswerHit(index);
}
},
generateQues: function(){
var que;
// Generating random questions from given list of ques - setOne.
s1Copy = setOne.slice();
//var result = [];
for (var i = 0; i < 3; i++) {result.push(s1Copy.splice(~~(Math.random()*s1Copy.length),1)[0]);}
s1Copy.push(...setTwo);
for (var i = 0; i < 7; i++) {result.push(s1Copy.splice(~~(Math.random()*s1Copy.length),1)[0]);}
result.toString();
for(var i = 0; i < result.length ; i++ ) {
que = result[i];
ques.push(que[0]);
ques.toString();
//console.log(ques);
answear.push(que[1]);
}
},
comeQus: function() {
quesTextValue = this.add.text(50,541, ques[0],textStyleQues);
this.generateQues();
//tempNoun = [];
},
generateAns: function() {
//Generate two digitd rendom no. and create an array of ans setAns[]
// Add digitd in array
for(var i = 0; i < 3 ; i++) {
var digit = Math.floor(Math.random() * 90 + 10);
//console.log(digit);
setAns.push(digit);
astroidContains[i] = "wrong";
}
console.log(astroidContains);
//console.log(answear);
setAns.push(answear[0]);
astroidContains[i] = "right";
console.log(astroidContains);
shuffle(setAns);
randomAnsPosition = [0, 1, 2, 3];
shuffle(randomAnsPosition);
},
comeAns: function() {
// x and y axis param for placing Answers text.
xAxis = [ 85, 255, 453, 675];
yAxis = [130, 48, 60, 120];
// console.log(setAns);
// Set Answers from above array of Ans - setAns.
for (var i = 0; i < setAns.length; i++) {
var ans = setAns[i];
//console.log(ans);
ansTextValue = this.add.text(xAxis[randomAnsPosition[i]], yAxis[randomAnsPosition[i]], ans, textStyleAns);
astroidContainsText[i] = ansTextValue;
//console.log(ansTextValue.text);
}
},
// Observing which cloud is clicked and checking answer accordingly.
astroidClicked: function() {
// alert("HEllo called");
if(!allowClick) {
return;
}
if(astroid1.game.input._x > 85 && astroid1.game.input._x < 130) {
console.log("cloud_1_Clicked, Clicked:" + astroidContains[0]);
this.checkAnswer(0);
}
else if(astroid2.game.input._x > 255 && astroid2.game.input._x < 48) {
//console.log("cloud_2_Clicked, Clicked:" + astroidContains[1]);
this.checkAnswer(1);
}
else if(astroid3.game.input._x > 453 && astroid3.game.input._x < 60) {
//console.log("cloud_3_Clicked, Clicked:" + astroidContains[2]);
this.checkAnswer(2);
}
else if(astroid4.game.input._x > 675 && astroid4.game.input._x < 120) {
//console.log("cloud_3_Clicked, Clicked:" + astroidContains[2]);
this.checkAnswer(3);
}
allowClick = false;
},
startTimer: function() {
// Create our Timer
timer = game.time.create(false);
// Set a TimerEvent to occur after 1 seconds
timer.loop(1000, this.updateCounter, this);
// Set a TimerEvent to occur after 1 seconds
// timer.loop(100, this.timerStripeChange, this);
// Start the timer running - this is important!
// It won't start automatically, allowing you to hook it to button events and the like.
timer.start();
},
gameOver: function() {
//Gameover screen
this.state.start('Game_Over', true, false);
},
initLoader: function() {
//*******Loader
check +=1;
var bmd = this.game.add.bitmapData(185, 30);
bmd.ctx.beginPath();
bmd.ctx.rect(0, 0, 185, 36);
bmd.ctx.fillStyle = '#00685e';
bmd.ctx.fill();
var bglife = this.game.add.sprite(100, 38, bmd);
bglife.anchor.set(0.5);
if(check != 0)
bmd = this.game.add.bitmapData(x_loader-4, 26);
else
bmd = this.game.add.bitmapData(x_loader, 26);
bmd.ctx.beginPath();
bmd.ctx.rect(0, 0, 180, 26);
if(x_loader <= 120 && x_loader > 60) {
bmd.ctx.fillStyle = "#FFFF00";
} else if(x_loader <= 60) {
bmd.ctx.fillStyle = "#EA0B1E";
} else {
bmd.ctx.fillStyle = '#00f910';
}
bmd.ctx.fill();
this.widthLife = new Phaser.Rectangle(0, 0, bmd.width, bmd.height);
this.totalLife = bmd.width;
//x_loader = ;
/*console.log(this.totalLife);
console.log(this.widthLife);*/
this.life = this.game.add.sprite(93 - bglife.width/2 + 10, 38, bmd);
this.life.anchor.y = 0.5;
this.life.cropEnabled = true;
this.life.crop(this.widthLife);
// this.game.time.events.loop(1450, this.cropLife, this);
},
updateCounter: function() {
if(timerCounter <= 0) {
this.gameOver();
return;
}
timerCounter--;
if(this.widthLife.width <= 0){
this.widthLife.width = this.totalLife;
}
else{
//this.game.add.tween(this.widthLife).to( { width: (x_loader - 4) }, 200, Phaser.Easing.Linear.None, true);
//console.log(this.widthLife.width);
this.widthLife.width = x_loader - 4;
x_loader = this.widthLife.width;
}
},
fire: function () {
if (game.time.now > nextFire && bullets.countDead() > 0)
{
nextFire = game.time.now + fireRate;
var bullet = bullets.getFirstDead();
bullet.reset(sprite.x - 80, sprite.y - 80);
game.physics.arcade.moveToPointer(bullet, 300);
}
}
}
/**
* Shuffles array in place.
* #param {Array} a items The array containing the items.
*/
function shuffle(a) {
var j, x, i;
for (i = a.length; i; i -= 1) {
j = Math.floor(Math.random() * i);
x = a[i - 1];
a[i - 1] = a[j];
a[j] = x;
}
}
As already noted it is a lot of code.
So far what I can see, is a memory leak in the update() function:
bullets = game.add.group();
bullets.enableBody = true;
bullets.physicsBodyType = Phaser.Physics.ARCADE;
bullets.createMultiple(200, 'bullet', 100, false);
bullets.setAll('anchor.x',0);
bullets.setAll('anchor.y', 0.9);
bullets.setAll('outOfBoundsKill', true);
bullets.setAll('checkWorldBounds', true);
With that you are constantly creating new bullets. Put that in the create() function and try again.
I'm trying to create a simple jQuery plugin that allows for multiple instances of a "timepicker". I haven't done much JavaScript OOP in the past so I figured that create this would be an excellent learning experience for me. That being said, I cannot seem to figure out why all instances are affected when I changed the time. This is my first post on StackOverflow so please bear with me.
Here's the code:
(function($) {
//Helper functions
if (typeof String.prototype.endsWith != 'function') {
String.prototype.endsWith = function(str) {
return str.length > 0 && this.substring(this.length - str.length, this.length) === str;
}
}
//Find if area is on the clickable list
var findOne = function(haystack, arr) {
return arr.some(function(v) {
return haystack.indexOf(v) >= 0;
});
};
var Timepicker = function(element, options) {
this.defaults = {
now: new Date()
};
this.element = $(element);
this.createTimepicker();
this.options = $.extend({}, this.defaults, options);
this.timepicker = $('.wicked-picker'); //The outer portion of the picker
this.up = $('.wicked-picker__controls__control-up'); //the up control(s)
this.down = $('.wicked-picker__controls__control-down'); //the down control(s)
this.hoursElem = $('.wicked-picker__controls__control--hours'); //the hours text
this.minutesElem = $('.wicked-picker__controls__control--minutes'); //the minutes text
this.meridiemElem = $('.wicked-picker__controls__control--meridiem'); //the am or pm text
this.canClick = ['timepicker', this.timepicker.selector.substring(1), this.up.selector.substring(1), this.down.selector.substring(1), this.hoursElem.selector.substring(1), this.minutesElem.selector.substring(1), this.meridiemElem.selector.substring(1)]; //the clickable areas
this.selectedHour = ((this.defaults.now.getHours() + 11) % 12) + 1; //the default hour
this.selectedMin = ((this.defaults.now.getMinutes() < 10) ? '0' : '') + this.defaults.now.getMinutes(); //the default minute
this.selectedMeridiem = (this.defaults.now.getHours > 12) ? 'PM' : 'AM'; //the defaut meridiem
this.attach(element); //attach events to this element
};
$.extend(Timepicker.prototype = {
showTimepicker: function(element) {
var timepickerPos = this.element.offset();
//set time to default time (now)
this.setText(element);
//if the timepicker's time differs from the input field's time change it
if (this.getText(element) !== this.getTime()) {
var inputTime = this.getText(element).replace(':', '').split(' ');
var newTime = new Date();
newTime.setHours(inputTime[0]);
newTime.setMinutes(inputTime[2]);
this.setTime(newTime);
}
//Positioning
this.timepicker.css({
'z-index': this.element.zIndex() + 1,
position: 'absolute',
left: timepickerPos.left,
top: timepickerPos.top + element.target.offsetHeight + 5
}).show();
//Time up/down events
//Most likely the area with issues
//Needs to know which instance
$(this.up).on('click', $.proxy(this.changeValue, this, '+', element));
$(this.down).on('click', $.proxy(this.changeValue, this, '-', element));
},
hideTimepicker: function(element) {
var targetClass = element.target.className.split(' ');
//Check if area is clickable before hiding
if (findOne(targetClass, this.canClick) === false) {
this.timepicker.hide();
}
},
//Create only one timepicker per page
createTimepicker: function() {
if ($('.wicked-picker').length === 0)
$('body').append('<div class="wicked-picker"> <p class="wicked-picker__title">Timepicker</p> <ul class="wicked-picker__controls"> <li class="wicked-picker__controls__control"> <span class="wicked-picker__controls__control-up"></span><span class="wicked-picker__controls__control--hours">00</span><span class="wicked-picker__controls__control-down"></span> </li> <li class="wicked-picker__controls__control"> <span class="wicked-picker__controls__control-up"></span><span class="wicked-picker__controls__control--minutes">00</span><span class="wicked-picker__controls__control-down"></span> </li> <li class="wicked-picker__controls__control"> <span class="wicked-picker__controls__control-up"></span><span class="wicked-picker__controls__control--meridiem">AM</span><span class="wicked-picker__controls__control-down"></span> </li> </ul> </div>');
},
//Attach the show and hide picker events
attach: function(element) {
$(element).on('focus', $.proxy(this.showTimepicker, this));
$('body').on('click', $.proxy(this.hideTimepicker, this));
},
//set the timepicker's time
setTime: function(time) {
this.setHours(time.getHours());
this.setMinutes(time.getMinutes());
this.setMeridiem();
},
//get the timepicker's time in the form H : MM : AM || PM
getTime: function() {
return [this.getHours + ' : ' + this.getMinutes() + ' ' + this.getMeridiem()];
},
//set the timepicker's and input field's hours
setHours: function(hours) {
var hour = new Date();
hour.setHours(hours);
var hoursText = ((hour.getHours() + 11) % 12) + 1;
this.hoursElem.text(hoursText);
this.selectedHour = hoursText;
},
//set the timepicker's hours
getHours: function() {
var hours = new Date();
hours.setHours(this.hoursElem.text());
return hours.getHours();
},
//set the timepicker's and input field's minutes
setMinutes: function(minutes) {
var minute = new Date();
minute.setMinutes(minutes);
var minutesText = minute.getMinutes();
var min = ((minutesText < 10) ? '0' : '') + minutesText;
this.minutesElem.text(min);
this.selectedMin = min;
},
//set the timepicker's minutes
getMinutes: function() {
var minutes = new Date();
minutes.setMinutes(this.minutesElem.text());
var minutesText = minutes.getMinutes();
return ((minutesText < 10) ? '0' : '') + minutesText;
},
//set the timepicker's and input field's meridiem
setMeridiem: function() {
var meridiem = this.getMeridiem();
var newMeridiem = (meridiem === 'PM') ? 'AM' : 'PM';
this.meridiemElem.text(newMeridiem);
this.selectedMeridiem = newMeridiem;
},
//set the timepicker's meridiem
getMeridiem: function() {
return this.meridiemElem.text();
},
//change the input field's time based on the arrow selected for each time unit
//input is the input field to be changed
//element is the up or down arrow clicked
//operator is the '+' or '-' sign
changeValue: function(operator, input, element) {
var target = (operator === '+') ? element.target.nextSibling : element.target.previousSibling;
var targetClass = $(target).attr('class');
if (targetClass.endsWith('hours')) {
this.setHours(eval(this.getHours() + operator + 1));
} else if (targetClass.endsWith('minutes')) {
this.setMinutes(eval(this.getMinutes() + operator + 1));
} else {
this.setMeridiem();
}
console.log('changed ' + $(input.target).attr('name'));
this.setText(input);
},
//Set the input field's time
setText: function(input) {
console.log('set ' + $(input.target).attr('name') + ' to ' + this.selectedHour + ' : ' + this.selectedMin + ' ' + this.selectedMeridiem);
$(input.target).val(this.selectedHour + ' : ' + this.selectedMin + ' ' + this.selectedMeridiem);
},
//Get the input field's time
getText: function(input) {
return $(input.target).val();
}
});
//Create timepickers
$.fn.timepicker = function(options) {
return this.each(function() {
new Timepicker(this, options);
});
};
}(jQuery));
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<input type="text" name="event-start-time" id="event-start-time" class="form-input timepicker grid-5" />
<input type="text" name="event-end-time" id="event-end-time" class="form-input timepicker grid-5" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$('.timepicker').timepicker({});
</script>
</body>
</html>
I was able to solve the problem by removing the previous up and down event click event handlers and then reapplying the new click event handlers. This was accomplished by changing
$(this.up).on('click', $.proxy(this.changeValue, this, '+', element));
$(this.down).on('click', $.proxy(this.changeValue, this, '-', element));
to
$(this.up).off('click').on('click', $.proxy(this.changeValue, this, '+', element));
$(this.down).off('click').on('click', $.proxy(this.changeValue, this, '-', element));
Thanks for all the advice!
A working version of this is here: http://est.pagodabox.com/client/svedka
I have the following function which I'm trying to convert into a module pattern, but when I try to use one of the function that I return at the bottom, for example:
est_project.closeContent($html);
I get an error that it's not a function. Is there something i'm doing wrong here?
Thanks!
var est_project = (function(){
// Setup functions
var flexDestroy,
cloneCurrent,
clonePosition,
switchSlide,
projectLayout,
contentHeight,
slidePos,
slideClick,
infoToggle,
closeContent;
// Destroy flexslider
flexDestroy = function($slider,$cleanSlider, $projBg) {
// Insert the clone of the un-initialized slide element, and remove the current flexslider
// Effectively "destroys" the current slider
var $curSlide = $slider.find('.flex-active-slide'),
// Get the zero based index of current slide
curSlideIndex = $curSlide.index() - 1,
curBg = $curSlide.find('img').attr('src'),
slideCount = $cleanSlider.data('count'),
i = 0,
$rearrange = $('');
// When you switch projects, the current slide should stay put
if(curSlideIndex !== 0 && slideCount > 1) {
// Cut from the current slide to the end, paste at the beginning
for(i = 0 ; i < slideCount; i += 1) {
if(curSlideIndex > i) {continue;}
$rearrange = $rearrange.add( $cleanSlider.find('li:eq(' + i + ')') );
}
$rearrange.remove();
$cleanSlider.find('li:first-child').before($rearrange)
$cleanSlider.css({'background-image' : 'url(' + curBg + ')'});
}
$slider.after($cleanSlider).remove();
clonePosition(slideheight);
};
return {
// Clone current
cloneCurrent: function($el) {
var $clean,
slideCount = $el.find('li').length;
$clean = $el.clone();
$clean.removeClass('project-current').find('div').removeClass('img-loading');
$clean.data('count',slideCount);
return $clean;
},
// Set the clone position, for when we add it to the DOM or resize the window
clonePosition: function(slideheight) {
var n = $cleanSlider.index(),
$myBg = $cleanSlider.find('div'),
myPosition = n * slideheight;
// Set the position of the inserted clone
$cleanSlider
.css({height: slideheight, top: myPosition, position : 'absolute'});
$myBg
.css({height: slideheight});
},
switchSlide: function($me, $slider) {
$('.project-current').removeClass('project-current');
$me.addClass('project-current');
// Get rid of current flexslider
flexDestroy($slider,$cleanSlider);
// Clone the unitialized slider so we can add it back in later when it gets destroyed
$cleanSlider = cloneCurrent($me);
$me.addClass('flexslider').flexslider({
animation: "slide",
animationSpeed: 500,
slideshow: false,
manualControls: '.dot-nav li a'
});
// After the flexslider initializes, slide the content
setTimeout(function(){
slidePos($me, $slidewrap, slideheight, $win);
},100);
},
// Custom "masonry" function, absolutely positions each project div according to the slide height
projectLayout: function(slideheight,$proj,$projBg) {
var n = 0;
$proj.each(function(){
var $me = $(this),
myPosition = n * slideheight;
// Set all the heights
$me
.css({top: myPosition, position : 'absolute'})
.add($projBg)
.css({height: slideheight});
n++;
});
},
// Set slide wrapper height to window height
contentHeight: function($win, $slidewrap) {
var winHeight = $win.height();
$slidewrap.css({height: winHeight});
},
// Set slide wrapper position to slide to the clicked slide, and set content position
slidePos: function($me, $slidewrap, slideheight, $win) {
var $contentText = $('.project-content .text'),
projNavHeight = Math.round( $win.height() * .1 ),
curIndex = $me.index(),
curTop = 0 - (curIndex * slideheight) + projNavHeight;
$slidewrap.css({transform: 'translate(0,' + curTop.toString() + 'px)'});
$('.corner-btn').add($contentText).css({'padding-top' : projNavHeight});
setTimeout(function(){
$slidewrap.removeClass('tr-none movin').addClass('tr-all');
$('.project').css({opacity: .4})
}, 100);
},
// Click a project, slide to it
slideClick: function($proj) {
$('.project').live('click',function(){
var $me = $(this),
myHref = $me.data('href'),
myTitle = $me.data('title'),
$slider = $('.flexslider'),
indexMy = $me.index(),
indexCur = $('.project-current').index(),
projDir;
$me.css({opacity: 1});
// Stop here if we click on the current project
if($me.hasClass('project-current')) {
return false;
}
History.pushState(null,myTitle,myHref);
});
},
// Hide and show content
infoToggle: function() {
// Open content
$('#corner-btn-info').on('click',function(){
$html.addClass('show-content');
if($('.project-content .text').height() <= $win.height()) {
$html.addClass('no-overflow');
}
$('.project-content-wrap').css({'z-index': 10});
});
// Close content
$('#corner-btn-close').live('click',function(){
closeContent($html);
});
},
closeContent: function($html) {
$html.removeClass('show-content');
setTimeout(function(){
$('.project-content-wrap').css({'z-index': -1});
$html.removeClass('no-overflow');
$('#classy').animate({scrollTop: 0})
},300);
}
};
});
The problem is that you're not executing the anonymous function, your code is the equivalent of:
var est_project = function() {};
You need to execute the function if you want it to return the functions defined in it.
Just replace the last line:
});
By:
}());
Or you can keep your code and call the closeContent function like this:
est_project().closeContent();
But I guess that's not what you want :-) You'd instantiate a new object everytime you call the est_project function.
At the start and end of your file just attach the object to window with the executed function and wrap whole function inside a self executing function. like this
(function(global) {
//your code goes here
global.est_project = est_project();
})(this)