Vertical scrolling in div animation by changing css top - javascript

I'm trying to set up horizontal slider. I have div with overflow: hidden and inside I have 16 divs with height of 60px. Parent div has height so you can see only 4 childs at the time.
Now I want to change childs top: css to make them slide up and 4 new come from bottom.
Here's what I've done so far
lastAddedService.getLastAdded()
.then(function (response) {
$scope.lastAddedElements = response.data;
var i = 0, g = 0, c = 0, p = 0;
var k = 1, b = 1, h = 1;
var slider = {
step: 1,
positionTop: 0,
init: function (step) {
var that = this;
el[0].querySelectorAll('.a').forEach(function (element) {
if(step === 1) {
if(i < 16) {
that.positionTop = i * 60;
i++;
return angular.element(element).css('top', that.positionTop);
}
}
if(step === 2) {
if(i < 4) {
that.positionTop = k * 60 * -1;
i++; k++;
return angular.element(element).css('top', that.positionTop);
}
if(i >= 4) {
k = 0;
that.positionTop = g * 60;
i++; g++;
return angular.element(element).css('top', that.positionTop);
}
}
if(step === 3) {
if(i < 8) {
that.positionTop = b * 60 * -1;
i++; b++;
return angular.element(element).css('top', that.positionTop);
}
if(i >= 8) {
that.positionTop = c * 60;
i++; c++;
return angular.element(element).css('top', that.positionTop);
}
}
if(step === 4) {
if(i < 12) {
that.positionTop = h * 60 * -1;
i++; h++;
return angular.element(element).css('top', that.positionTop);
}
if(i >= 12) {
that.positionTop = p * 60;
i++; p++;
return angular.element(element).css('top', that.positionTop);
}
}
});
},
changeSlide: function (step) {
this.step = step;
this.init(this.step);
}
};
$timeout(function () {
slider.changeSlide(1);
});
setTimeout(function () {
setInterval(function () {
var q = 1;
q++;
slider.changeSlide(q);
if(q === 4) {
q = 1;
}
}, 5000);
}, 5000);
}, function (err) {
console.log('error getting last added');
});
}
So I'm gathering records from backend and then there is this slider object which has logic which I explained above.
Backend call works fine, I did console response and it's 16 records which I display in layout layer later on. Question is mainly about the logic for this sliding object.
I'm using $timeout to start code work because this code is indeed in angularJS directive and NodeList which I get by querySelectorAll would be empty otherwise because it's evaluated after async backend call finish and then DOM is fully loaded. But it's not really relevant to real logic of this script, it's just additional info.
This code looks very bad to me. How I can improve it?
It's starting to update top after around 20 seconds and 1 div has 960px I don't know why.
It's not reseting this variables values so it doesn't loop but it increase top further and further.
I add HTML from my directive if anyone want to reproduce issue
<div class="col-lg-8 col-md-8 col-sm-12 col-xs-12">
<div class="row u-no-margin">
<div class="col-lg-11 col-xs-11">
<h2 class="main__heading">
Ostatnio dodane
</h2>
<div class="main__last-added-field">
<div class="main__last-added a" data-ng-repeat="n in lastAddedElements">
<div class="row u-no-margin main__last-added-container">
<div class="col-lg-3 col-md-2 col-sm-2 col-xs-2">
<h4 class="main__last-added-heading">
{{ n.data.attributes.price }}
</h4>
</div>
<div class="col-lg-7 col-xs-8 u-no-padding">
<h4 class="main__last-added-heading u-no-padding">
{{ n.data.attributes.name }}
</h4>
</div>
<div class="col-lg-2 col-xs-2">
<button type="button" class="btn btn__primary">
Zobacz
</button>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-1 col-xs-1">
<div class="main__last-added-dot-container">
<span class="main__last-added-dot main__last-added-dot--active"></span>
<span class="main__last-added-dot"></span>
<span class="main__last-added-dot"></span>
<span class="main__last-added-dot"></span>
</div>
</div>
</div>
</div>
JS code is within directive link: function and the templateUrl is above HTML code.
** EDIT **
I update question I add plunker showing issue and I explain one more, step by step what I want to accomplish.
Step1: all element has top: x css so they are align vertically. I'm using overflow: hidden on parent so you see only 4 and 12 are hidden below like this
Step2 I move first 4 element to top: -x so you don't see first 4 and element 5,6,7,8 take their place so elements 5,6,7,8 now slide to the top and first 4 are hidden.
step 3 same as Step2: elements 5,6,7,8 move to negative top and you now see elements 9,10,11,12
step 4 same as Step3: elements 9,10,11,12 move to negative top and you now see elements 13,14,15,16
here's demo
I don't know why but in plunker it doesn't udpate css top of elements at all.

First of all I recommend that you use a bootstrap only solution for your html/css view because its responsive, tested and you will have cleaner code.
I have made some modification to your slider logic in a way that the logic is the as if your slider were a pagination directive.
Basically, you divide your data into pages and then you keep track of the current page to be displayed on the view.
In your elements directive you use two filters on the data (startFrom, limitTo). The 'limitTo' is a built-in filter in Angular and 'startFrom' is a custom filter that you have to create.
<div class="" data-ng-repeat="n in elements | startFrom:currentPage*pageSize | limitTo:pageSize">
This is just an ideia that might help you refactor you code such that you won't need css positioning to determine which items will be displayed. Here is my demo:
https://plnkr.co/edit/IROsQWr5z4oYgZzmR2GF?p=preview
I hope this helps!

I've done it with this code:
<div class="main__last-added a"
data-ng-repeat="n in lastAddedElements"
data-order="{{ $index+1 }}">
(function () {
'use strict';
angular
.module('igt')
.directive('lastAdded', Directive);
Directive.$inject = ['$timeout', 'lastAddedService'];
function Directive($timeout, lastAddedService) {
return {
restrict: 'E',
scope: {
destiny: '='
},
templateUrl: 'html/directives/lastAdded.html',
link: function ($scope, el) {
lastAddedService.getLastAdded()
.then(function (response) {
$scope.lastAddedElements = response.data;
$scope.slider = {
increment: 0,
step: 1,
positionTop: 0,
init: function (step) {
var that = this;
var elements = el[0].querySelectorAll('.a');
if(step === 1) {
console.log('run step 1 ..............');
this.step = 1;
elements.forEach(function (e) {
var order = angular.element(e).attr('data-order');
if(order <= 16) {
that.positionTop = order * 60 - 60;
return angular.element(e).css('top', that.positionTop);
}
});
}
if(step === 2) {
console.log('run step 2 ..............');
this.step = 2;
elements.forEach(function (e) {
var order = angular.element(e).attr('data-order');
if (order <= 4) {
that.positionTop = order * 60 * -1;
return angular.element(e).css('top', that.positionTop);
}
if (order > 4) {
that.positionTop = that.increment * 60;
that.increment++;
console.log(that.increment);
if (that.increment === 12) {
that.increment = 0;
console.log('reset inc in step 2');
}
return angular.element(e).css('top', that.positionTop);
}
});
}
if(step === 3) {
console.log('run step 3 ..............');
this.step = 3;
elements.forEach(function (e) {
var order = angular.element(e).attr('data-order');
if (order <= 8) {
that.positionTop = order * 60 * -1;
return angular.element(e).css('top', that.positionTop);
}
if (order > 8) {
that.positionTop = that.increment * 60;
that.increment++;
console.log(that.increment);
if (that.increment === 8) {
that.increment = 0;
console.log('reset inc in step 3');
}
return angular.element(e).css('top', that.positionTop);
}
});
}
if(step === 4) {
console.log('run step 4 ..............');
this.step = 4;
elements.forEach(function (e) {
var order = angular.element(e).attr('data-order');
if (order <= 12) {
that.positionTop = order * 60 * -1;
return angular.element(e).css('top', that.positionTop);
}
if (order > 12) {
that.positionTop = that.increment * 60;
that.increment++;
console.log(that.increment);
if (that.increment === 4) {
that.increment = 0;
console.log('reset inc in step 4');
}
return angular.element(e).css('top', that.positionTop);
}
});
}
},
changeSlide: function (step) {
this.step = step;
this.init(this.step);
}
};
$timeout(function () {
var i = 1;
$scope.slider.changeSlide(i);
setInterval(function () {
i++; if(i === 5) i = 1;
$scope.slider.changeSlide(i);
}, 5000);
});
}, function (err) {
console.log('error getting last added: ' + err);
});
}
}
}
})();
But this code still look very lame although it's a bit better than first version. I feel like it can be done in much much simplier way.

Related

How to fix clearInterval() not stopping the interval?

I made an interval connected to a button that only runs when you have a certain amount of money and lemonade. Then I created an if statement that makes it so that when you run out of lemonade, then the interval stops. I used clearInterval() and for some reason the interval doesn't stop, and the number of lemonade goes into the negatives. Obviously you can't have a negative amount of something!
I've looked at all of the other questions with similar problems to me, but they didn't really answer my question. They all have different variables and it was hard to find an answer pertaining to my code.
Here's my code:
let autoBtnTwo = document.getElementById("autoBtnTwo");
let lemonade = 0;
let btnTwo = document.getElementById("btnTwo")
function btnTwoCost() {
wallet.removeCash(20);
update();
document.getElementById("lemonade").innerHTML = lemonade += 30
}
function double() {
if (wallet.getCash() >= 50) {
wallet.addCash(2)
update();
document.getElementById("lemonade").innerHTML = lemonade -= 1;
}
}
function autoLemonade() {
if (wallet.getCash() >= 3000) {
wallet.removeCash(3000);
var myint = setInterval(double, 1000);
autoBtnTwo.disabled = false;
update();
}
if (wallet.getCash() <= 2999) {
autoBtnTwo.disabled = true;
}
if (lemonade <= 0) {
autoBtnTwo.disabled = true;
btnTwo.disabled = true;
}
}
function stopInterval() {
var myint = setInterval(double, 1000);
if (lemonade <= 0) {
clearInterval(myint);
stopInterval();
}
}
function thousand() {
wallet.addCash(1000)
update();
if (wallet.getCash() >= 3000) {
autoBtnTwo.disabled = false;
}
}
function Wallet() {
return {
addCash: function(val) {
number += val;
},
getCash: function() {
return number;
},
removeCash: function(val) {
number -= val;
}
}
}
var number = 0;
const wallet = new Wallet();
var SUFFIXES = 'KMBTqQsSOND';
function update() {
document.getElementById('number').textContent = getSuffixedNumber(wallet.getCash());
}
function getSuffixedNumber(num) {
var power = Math.floor(Math.log10(num));
var index = Math.floor(power / 3)
num = num / Math.pow(10, (index * 3)); // first 3 digits of the number
return num.toFixed(1) + (SUFFIXES[index - 1] || ''); // default to no suffix if it gets an out of bounds index
}
<button onclick="autoLemonade()" class="chocolate-bar-auto" id="autoBtnTwo" disabled>
Hire worker: <br> -$3000<br> Sells Lemonade
</button>
<button onclick="thousand()">to get to $3000 for testing </button>
<button onclick="btnTwoCost()"> buy lemonade -$20</button>
<button onclick="double()">sell lemonade </button>
<div class="cash-div">
Cash: <div id="number">0</div>
</div>
<div class="lemonade-div">
Lemonade: <div id="lemonade">0</div>
</div>
Sorry if this version is glitchy. All of the code I used to prevent the glitches makes the code longer, which it is already long enough. press the $3,000 button 4 times, then the buy lemonade, and then the hire worker button and you will see what happens once it gets to 0.
The interval should stop adding money, and stop reducing the amount of lemonade when lemonade reaches 0, but instead it keeps going into the negatives.

Paging next button jumping by page number * 6

I'm having a problem with my pagination. it seems to take the number of the page I am on and multiplies it by 6 when clicking the "next array" arrow function IE: "clicking on the second page then the next arrow function it jumps to page 13-18 instead of jumping to page 7-12.
next buttons, first array
second array clicking arrow buttons after click on page two jumps to the wrong section
This is the code that creates the pagination.
CreatePages() {
this.pages = [];
console.log({'this.iteration':this.iteration,'this.iteration * 6 - 6':this.iteration * 6 - 6,'this.iteration * 6':this.iteration * 6,'this.allPages':this.allPages})
for (var i = this.iteration * 6 - 6; i < this.iteration * 6 && i < this.allPages; i++) //populate the pages array
{
console.log({'this.iteration':this.iteration,'(this.iteration - 1) * 6':(this.iteration - 1) * 6})
if (i == (this.iteration - 1) ) {
this.pages.push({ id: i + 1, current: true });
}
else
this.pages.push({ id: i + 1, current: false });
}
console.log({pages:this.pages})
}
age(id: number) {
this.pages.forEach(function (p) {
if (p.id != id)
p.current = false;
else
p.current = true;
})
this.iteration =id;
this.postSearch(this.query,this.iteration,this.pagesize,this.categories)
}
PagingPrev() {
this.iteration--;
if (this.iteration <= 0) {
this.iteration = 1;
}
else
this.CreatePages();
this.Page(this.iteration)
}
PagingNext() {
this.iteration++;
if (this.iteration > Math.ceil(this.allPages / 1)) {
this.iteration = Math.ceil(this.allPages / 6);
}
else{
this.CreatePages();
}
console.log({"mattspages":this.iteration})
this.Page(this.iteration)
}

Why my Javascript progress bar doesn't work in IE11?

I have a long running script that broke down in a progress bar:
HTML
<div id="progressbar-wrapper">
<div id="progressbar-outer" style="display: table;margin: 0 auto;background-color: #FFFFFF;border: 5px solid #000000;width: 50%;height: 30px;opacity: 1;z-index: 9998">
<div id="progressbar" style="float:left;width: 0;height: 30px;background-color:#000000;border: 0;opacity: 1;z-index: 99999">
</div>
</div>
<div id="loading-animation" style="position: fixed;top: 150px;left: 0;height: 120px;width: 100%;font-size: 100px;line-height: 120px;text-align: center;color: #000000;z-index: 9999;">
...SAVING...<br /><small>Saving Lines</small>
</div>
</div>
JavaScript
var uiprogressbar = {};
$(function () {
uiprogressbar = {
/** initial progress */
progress: 0,
/** maximum width of progressbar */
progress_max: 0,
/** The inner element of the progressbar (filled box). */
$progress_bar: $('#progressbar'),
/** Method to set the progressbar.
*/
set: function (num) {
if (this.progress_max && num) {
this.progress = num / this.progress_max * 100;
console.log('percent: ' + this.progress + '% - ' + num + '/' + this.progress_max);
this.$progress_bar.width(String(this.progress) + '%');
}
},
fn_wrap: function (num) {
setTimeout(function () {
this.set(num);
}, 0);
}
};
});
//PROGRESS BAR ================================================
//max progress bar
uiprogressbar.progress_max = iterations;
var mainGrid = $("#mainGrid").data("kendoGrid");
var i = 0; //partition #
var j = 0; //line #
var linesUpdated = 0; //update complete #
//make the progress bar visable before updating
$("#progressbar-wrapper").css("display", "block");
//then loop through update grid methods
(function innerloop() {
try {
//If end
var testPart = (partitions[i].length - 1); //30 but starts at 0
} catch (err) {
//exit loop
return;
}
//Get the length of the partition
var thisPartitionLength = (partitions[i].length - 1); //30 but starts at 0
if (thisPartitionLength >= j && successComplete === 2) {
$.each(mainGrid.dataSource.data(),
function () {
if (this.RowSelected === true) {
//get id
var row = mainGrid.dataSource.getByUid(this.uid);
//unselect and turn off dirty
row.set("RowSelected", "false");
row.set("dirty", "false");
linesUpdated++;
}
});
//update line #
j++;
//update progressbar
uiprogressbar.set(linesUpdated);
}
if (j <= thisPartitionLength) {
//loop if not complete with partition
setTimeout(innerloop, 0);
} else {
if (j > thisPartitionLength) {
//if end of partition reset the line # and increase partition # and continue loop
i++;
j = 0;
setTimeout(innerloop, 0);
}
//on complete
if (linesUpdated === iterations) {
//Success message
alert("Saved");
}
}
})();
Which works perfectly in chrome. But doesn't appear AT ALL in IE11 (which is what my clients use). When i run it in IE it even gives and error
...not responding due to a long-running script.
which was the exact reason i implemented a progress bar. Is there something I'm missing that IE has that Chrome does not? How can i change this to make it work in IE?
OK so IE waits till the function is complete to make changes. I has to strip out the progress bar method into a separate function and wrap it in a timeout:
function updateProgressBar(){
//PROGRESS BAR ================================================
//max progress bar
uiprogressbar.progress_max = iterations;
var mainGrid = $("#mainGrid").data("kendoGrid");
var i = 0; //partition #
var j = 0; //line #
var linesUpdated = 0; //update complete #
//make the progress bar visable before updating
$("#progressbar-wrapper").css("display", "block");
//then loop through update grid methods
(function innerloop() {
try {
//If end
var testPart = (partitions[i].length - 1); //30 but starts at 0
} catch (err) {
//exit loop
return;
}
//Get the length of the partition
var thisPartitionLength = (partitions[i].length - 1); //30 but starts at 0
if (thisPartitionLength >= j && successComplete === 2) {
$.each(mainGrid.dataSource.data(),
function () {
if (this.RowSelected === true) {
//get id
var row = mainGrid.dataSource.getByUid(this.uid);
//unselect and turn off dirty
row.set("RowSelected", "false");
row.set("dirty", "false");
linesUpdated++;
}
});
//update line #
j++;
//update progressbar
uiprogressbar.set(linesUpdated);
}
if (j <= thisPartitionLength) {
//loop if not complete with partition
setTimeout(innerloop, 0);
} else {
if (j > thisPartitionLength) {
//if end of partition reset the line # and increase partition # and continue loop
i++;
j = 0;
setTimeout(innerloop, 0);
}
//on complete
if (linesUpdated === iterations) {
//Success message
alert("Saved");
}
}
})();
}
then call it using:
setTimeout(function() {
updateProgressBar();
}, 0);

Jquery hide first 12 elementes, show next 12 elements Previous and Next

what i am trying to do is make the first 12 elements hidden and show the next 12 elements and reverse, its like a next page and previous page in a search result.
Got this code from Jquery hide first 12 elementes, show next 12 elements
DEMO
<div class="inner-content">
<div class="front-pro">151</div>
<div class="front-pro">151</div>
<div class="front-pro">151</div>
<div class="front-pro">151</div>
<div class="front-pro">151</div>
<div class="front-pro">151</div>
<div class="front-pro">151</div>
<div class="front-pro">151</div>
<div class="front-pro">151</div>
<div class="front-pro">151</div>
<div class="front-pro">151</div>
<div class="front-pro">151</div>
<div class="front-pro">152</div>
<div class="front-pro">152</div>
etc...
</div>
<div>next</div>
var x = $(".inner-content div").hide();
$("div:contains(next)").click(function() {
var cnt = $(this).data("cnt") || 0;
if((cnt * 12) > x.length){ cnt = 0; }
x.hide().filter(":eq("+ (cnt * 12) + "), :lt(" + ((cnt * 12) + 12) + "):gt(" + (cnt * 12) + ")").show();
$(this).data("cnt", ++cnt);
});
This code works but i want to reverse it with a previous button
You could try this :
JQuery
$(".next").click(function() {
var childEls = $('.inner-content').find('.front-pro').not(".visible") ; // array
var count = 1;
$.each(childEls, function() {
if (count <= 12) {
$(this).toggleClass('visible');
}
count++;
});
});
$(".prev").click(function() {
var count = 1;
$($('.inner-content').find('.visible').get().reverse()).each(function() {
if (count <= 12) {
$(this).toggleClass('visible');
}
count++;
});
})
Here's a link to demonstrate - JsFiddle
Something along these lines would have been my approach.
Since you retrieve all of the elements that you are working with in x.
I would look into the Jquery Slice() method where you can ask for a subset of the selector results. Not complete per say, but I hope it helps you get to where you want.
var x = $(".inner-content div").hide();
var $nextdiv = $("div:contains(next)");
var $previousdiv = $("div:contains(previous)");
var pageNum = 0;
var numOfPages = Math.ceil(x.length / 12);
$nextdiv.click(function() {
if (pageNum < numOfPages) {
var toshow = x.slice(pageNum * 12, pageNum * 12 + 12).show(); // show next 12
x.not(toshow).hide(); // hide all others
pageNum++;
}
});
$previousdiv.click(function() {
if (pageNum > 0) {
pageNum--;
var toshow = x.slice((pageNum - 1) * 12, (pageNum - 1) * 12 + 12).show(); // show last pages 12 records
x.not(toshow).hide(); // hide all others
}
});
https://jsfiddle.net/3rk53h7L/5/

Js and Divs, (even <div> is difference)

I Have find a javascript code that works perfectly for showing a DIV.
but this code works only for showing one div for each page.
i want to include many DIVS for hiding and showing in the same page.
I was try to replace the div id and show/hide span id with a rundom php number for each include, but still is not working.
so how i have to do it?
the JS code:
var done = true,
fading_div = document.getElementById('fading_div'),
fade_in_button = document.getElementById('fade_in'),
fade_out_button = document.getElementById('fade_out');
function function_opacity(opacity_value) {
fading_div.style.opacity = opacity_value / 100;
fading_div.style.filter = 'alpha(opacity=' + opacity_value + ')';
}
function function_fade_out(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'none';
done = true;
}
}
function function_fade_in(opacity_value) {
function_opacity(opacity_value);
if (opacity_value == 1) {
fading_div.style.display = 'block';
}
if (opacity_value == 100) {
done = true;
}
}
// fade in button
fade_in_button.onclick = function () {
if (done && fading_div.style.opacity !== '1') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_in(x)
};
})(i), i * 10);
}
}
};
// fade out button
fade_out_button.onclick = function () {
if (done && fading_div.style.opacity !== '0') {
done = false;
for (var i = 1; i <= 100; i++) {
setTimeout((function (x) {
return function () {
function_fade_out(x)
};
})(100 - i), i * 10);
}
}
};
Check out the Fiddle, you can edit code based on your needs ;)
$(function() {
$('.sub-nav li a').each(function() {
$(this).click(function() {
var category = $(this).data('cat');
$('.'+category).addClass('active').siblings('div').removeClass('active');
});
});
});
finaly i found my self:
<a class="showhide">AAA</a>
<div>show me / hide me</div>
<a class="showhide">BBB</a>
<div>show me / hide me</div>
js
$('.showhide').click(function(e) {
$(this).next().slideToggle();
e.preventDefault(); // Stop navigation
});
$('div').hide();
Am just posting this in case someone was trying to answer.

Categories