Pagination, bootstrap and knockout - javascript

So I don't have the option to use external third party libraries that would make my life so much easier, so I have to build this from scratch.
And I think I over complicated this.
So the idea is that if a client passes in, via the url, something like: showPages=4. Then we have something like:
<< < 1 2 3 4 _5_ 6 7 8 9 > >>
Where 5 is the current page, you should see 4 to the left and 4 to the right of the current page (lets say the max pages are 20)
My view model, so far, looks like:
var ViewModel = {
self.pagesBefore = ko.observable(4);
self.pagesAfter = ko.observable(4);
self.currentPage = ko.observable(5);
self.totalPages = ko.observable(20);
self.pageStart = ko.observable(0);
self.pageEnd = ko.observable(0);
}
I think I overcomplicated this because I don't think I need the pages before and pages after, I think I can change that into: self.showPages(4)
The problem I am having is laying this out in the view, I have no issue figuring out where to start, so for example there might be a method in the view model that does:
var endPage = self.currentPage() + self.pagesAfter();
if (endPage <= self.totalPages()) {
self.pageEnd(endPage); // In our example above its 9
} else {
self.pageEnd(self.totalPages());
}
To get the "final" page to the right, in this case 9.
And another that calculates what the "starting page (or pages before the current page)" is:
var startPage = self.currentPage() - self.pagesBefore();
if (startPage > 1) {
self.pageStart(startPage); // In our example above its 1
} else {
self.pageEnd(1);
}
So I would end up with a view model variables looking like:
var ViewModel = {
self.pagesBefore = ko.observable(4);
self.pagesAfter = ko.observable(4);
self.currentPage = ko.observable(5);
self.totalPages = ko.observable(20);
self.pageStart = ko.observable(1);
self.pageEnd = ko.observable(9);
}
So my question is: How do I translate this to the view so that I have a paginated element that has 5 selected with 4 to the right and 4 to the left with a total of 20 pages?

It is probably easier to get your JavaScript to make an array of objects to show on the page. You can do this with a ko.computed function.
Then to display it, you can just use a knockout foreach in your HTML.
As it is a computed function, changing the currentPage or totalPage observable will automatically cause your HTML to update.
Something like:
function ViewModel() {
var self = this;
self.currentPage = ko.observable(5);
self.totalPages = ko.observable(20);
self.pagesBefore = ko.observable(4);
self.pagesAfter = ko.observable(4);
self.pages = ko.computed(function() {
// Work out the start and end pages - same logic as you already had
var startPage = self.currentPage() - self.pagesBefore();
if (startPage < 1) {
startPage = 1
}
var endPage = self.currentPage() + self.pagesAfter();
if (endPage > self.totalPages()) {
endPage = self.totalPages();
}
// Make the page array
var pageArray = [];
for (var i = startPage; i <= endPage; i++) {
pageArray.push({ page: i, highlight: i == self.currentPage() });
}
return pageArray;
});
}
ko.applyBindings(new ViewModel());
<!-- Stuff to get the snippet to work -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<style>
ul li {
display: inline;
}
.high { color: red; }
</style>
<!-- output the pages (the important bit) -->
<ul data-bind="foreach: pages">
<li data-bind="text: page, css: (highlight ? 'high' : '')"></li>
</ul>

Related

Compare array items with HTML dataset with pure Javascript?

Using Jquery you can do:
array[0].data('id') == array[1].data('id')
and compare 2 items in an same array by their HTML dataset (in this case it's data-id="1"). Is there a way to do it with pure Javascript???
This is HTML. It's a list of images.
<li class="card" data-id="1"><img src="images/labrys.svg" alt=""></li>
<li class="card" data-id="2"><img src="images/laurel.svg" alt=""></li>
....and so on
This is JS:
let cardArray = []; //Empty Array for selected cards
cards.addEventListener("click", function (e) {
e.preventDefault();
if (e.target.nodeName==="LI"){ // If a list element is hit...
const data = e.target.dataset.id; //checking
console.log(data);
cardArray.push(e.target); //Place current card into array...
var hit = cardArray[0].dataset.id;
var hot = cardArray[1].dataset.id;// throws error
console.log (hit);
console.log (hot);
}
I am trying to do this:
var match = cardArray[0].dataset.id=== cardArray[1].dataset.id;
This project is a memory game:
https://github.com/StamatisDeli/memory-game.github.io
You have to check how many items are in the array before accessing their index.
I believe that you are trying to avoid duplicating items when the user selects a particular card multiple times through click events. if that is what you are trying to achieve, You will be facing two scenerio.
first is to make sure that the listener function does not misbehave on multiple clicks.
second is to implement a binary search algorithm to help locate items easily rather than iterating through the items one after the other during searching. the id is a great stuff to use in sorting the list items.
var processing = false, //used to handle radical click event triggers
cardArray = [];
//note, it is better to add your event listener, to the card container `ul`
//since click events on the li items will will bubble up to it.
cardContainer.addEventListener('click', function(e){
e.preventDefault();
if (processing) {
return;
}
if (e.target.tagName.tolowerCase() !== 'li') {
return;
}
processing = true;
var cardlocation = searchCard(e.target.dataset.id);
if (cardlocation > -1) {
//card is already in array. do what you wish here
}
else {
//this is a new selection. do whatever you wish here
cardArray.push(e.target);
}
processing = false; //done processing.
});
Implement a search algorithm
/**
*This one will be slow if there loads of cards in the array
*#returns int returns the card index or -1 if not found
*/
var searchCard = function(id) {
var len = cardArray.length;
while (--len >= 0) {
if (id == cardArray[len].dataset.id) {
return len;
}
}
return -1;
}
Binary Search
/**
*used when sorting the cards
*/
var sortCard = function(card1, card2) {
var id1 = parseInt(card1.dataset.id),
id2 = parseInt(card2.dataset.id);
return id1 - id2;
};
/**
* used for checking the cards search
*/
var checkCard = function(id, card) {
return parseInt(id) - parseInt(card.dataset.id);
};
/**
*performs binary search
*/
var searchCard = function(id) {
if (cardArray.length === 0) {
return -1;
}
var low = 0,
high = cardArray.length - 1,
middle = parseInt((high + low + 1)/2, 10),
locationindex = -1,
searchindex = 0;
cardArray.sort(sortCard); //sort the card array
do {
searchindex = checkCard(id, cardArray[middle]);
if (searchindex === 0) {
locationindex = middle;
}
else {
//split and recalculate the middle
if (searchindex < 0) {
high = middle - 1;
}
else {
low = middle + 1;
}
middle = parseInt((high + low + 1) / 2, 10);
}
}
while (low <= high && locationindex === -1);
return locationindex;
}

How to transform a generic Animated JS script to work with many classes id

I don't know how I can explain my problem... but I have a Animated JS script and this JS Works fine.
This script identify by CLASS NAME each ICONS on the page marked by the class name - and animated this icons with a delay between each icon.
Then I have in my page 3 sections (all in the same page):
1- About Us
2- Services
3- Clients
I create this script to use in SERVICES SECTION where I have 20 services, with 20 icons - animated one after other on screen.
But now, I want to use this script in About Us and Clients Sections to animated the icons in this sections
My problem:
The script Works fine for 1 section. If I use in other section I need to wait all animations from the other sections stop to start the animations from the actual sector. (All animations are "scrollbar controlled")
To correct this I clone the script 2x and change the class name for each section.
Problem solved!
But I need to write 3x the same script and only change a class name..
If I need to create another 10 sections, a I will need to write the same script 10x..
There is a way to avoid this?
SORRY! I'M A BEGINNER IN JS.. I understand many things, but I'm not a expert.
var $animation_elements = $('.animation-element');
var $window = $(window);
const MULTIPLIER = 800;
var countInView = 0;
var timeouts = [];
for (i = 0; i < $animation_elements.length; i++)
timeouts[i] = [];
function check_if_in_view() {
var window_height = $window.height();
var window_top_position = $window.scrollTop();
var window_bottom_position = (window_top_position + window_height + 15);
for(var i=0; i < $animation_elements.length ; i++) {
var $element = $animation_elements.eq(i);
var element_height = $element.outerHeight();
var element_top_position = $element.offset().top;
var element_bottom_position = (element_top_position + element_height);
if ((element_bottom_position >= window_top_position) &&
(element_top_position <= window_bottom_position)) {
if($element.is($('i').parent()) && !$element.hasClass('in-view')) {
var delay = MULTIPLIER * ++countInView;
$element.addClass('paused');
(function(delay, $element, savedtimeout){
savedtimeout[i][0] = setTimeout(function() {
$element.removeClass('paused');
countInView--;
}, delay);
}(delay, $element, timeouts));
}
$element.addClass('in-view');
} else {
if($element.hasClass('in-view')) {
$element.removeClass('in-view');
}
if($element.hasClass('paused')) {
if(timeouts[i][0] != null) {
//Retira o timeout da fila
clearTimeout(timeouts[i][0]);
countInView--;
}
$element.removeClass('paused');
} // end if
} // end if
} // end for
}
$window.on('scroll resize', check_if_in_view);
$window.trigger('scroll');
Then i change:
var $animation_elements = $('.animation-element');
var $animation_elements = $('.animation-element2');
var $animation_elements = $('.animation-element3');
And copy+paste all the rest

carousel controls not working

see my fiddle : https://jsfiddle.net/1bc8j418/1/
may b i'm wrong with the code please modify it i was trying different things but failed . thanks for the help!
or you can see the code here
MY HTML
<div class="carouselBg">
<p id="demoSliderFirst" class="textSliders">
Life must be lived forwards, but can only be understood backwards.
</p>
<span onclick="prev()">back</span>
<span onclick="next()">next</span>
</div>
MY JQUERY
var demoSlider1 = $('#demoSliderFirst');
var DemoSliderSet1 = [
'Do not dwell in the past, do not dream of the future, concentrate the mind on the present moment',
'What screws us up the most in life is the picture in our head of how it is supposed to be.',
'Life shrinks or expands in proportion to one’s courage.'];
var index1 = 0;
function demoSliderCarousel1(){
var newDemoSliderSet1 = DemoSliderSet1[index1];
demoSlider1.fadeOut('400',function(){
demoSlider1[0].innerHTML = newDemoSliderSet1;
}).fadeIn('400');
index1++;
if(index1 >= DemoSliderSet1.length){
index1 = 0;
}
this.prev = function(){
if(--this.index1 < 0) this.index = this.DemoSliderSet1.length - 1;
this.start()
};
this.next = function(){
if(++this.index1 >= this.DemoSliderSet1.length) this.index = 0;
this.start()
};
}
setInterval(demoSliderCarousel1,4000);
You are creating the next() and prev() functions in the wrong scope. Create the functions outside of the demoSliderCarousel1() function and everything is working fine.
var demoSlider1 = $('#demoSliderFirst');
var DemoSliderSet1 = [
'Do not dwell in the past, do not dream of the future, concentrate the mind on the present moment',
'What screws us up the most in life is the picture in our head of how it is supposed to be.',
'Life shrinks or expands in proportion to one’s courage.'];
var index1 = 0;
var demoSliderCarousel1 = function() {
var newDemoSliderSet1 = DemoSliderSet1[index1];
demoSlider1.fadeOut('400',function(){
demoSlider1[0].innerHTML = newDemoSliderSet1;
}).fadeIn('400');
index1++;
if(index1 >= DemoSliderSet1.length){
index1 = 0;
}
}
var prev = function(){
if(--index1 < 0) index = DemoSliderSet1.length - 1;
demoSliderCarousel1();
};
var next = function(){
if(++index1 >= DemoSliderSet1.length) index = 0;
demoSliderCarousel1();
};
setInterval(demoSliderCarousel1,4000);

Javascript slider function - How to objectify the selectors?

I'm currently working on a project where a custom slider was needed and i quickly grabbed a neat looking tutorial of the web and went away and staticly it all works great.
Now i want to be able to put several sliders on my page and therefore need to add the controls dynamicly rather than just selecting a certain slider with jquery like I've done below.
This is my code with comments added to explain what im trying to achieve:
var Slider = function() { this.initialize.apply(this, arguments) };
Slider.prototype = {
initialize: function(slider) {
this.ul = slider.children[2];
this.li = this.ul.children;
this.nav = slider.children[3]; //Why cant i use .append on this element?
// make <ul> as large as all <li>’s
this.ul.style.width = (100 * this.li.length) + '%';
// set width of the li's
for(i = 0; i < this.li.length; i++) {
this.li[i].style.width = (100 / this.li.length) + '%';
$(".slider-nav").append( '<div class="slider-dot"></div>'); //Want to make it a this.nav or something similar instead of an external selector
//console.log(this.nav);
}
this.currentIndex = 0;
},
goTo: function(index) {
if (index < 0 || index > this.li.length - 1)
return;
// move <ul> left
this.ul.style.left = '-' + (100 * index) + '%';
this.currentIndex = index
},
goToPrev: function() {
this.goTo(this.currentIndex - 1)
},
goToNext: function() {
this.goTo(this.currentIndex + 1)
}}
var sliders = [];
$('.slider').each(function() {
sliders.push(new Slider(this));
});
//Find a way to implement theese 2 within the slider function, how to find out what position in the array a slider has?
$(".prev-btn").click(function() {
sliders[0].goToPrev();
});
$(".next-btn").click(function() {
sliders[0].goToNext();});
The marks up for the slider looks like this: http://puu.sh/hAUH1/a865792137.png
I managed to get it done by defining this as another var
var sliderEle = this;
I could then call it like this:
$(this.prev).click(function(e) {
e.preventDefault();
sliderEle.goToPrev();
});
with prev and next defined like this:
this.prev = slider.children[0];
this.next = slider.children[1];

Image slide won't slide

I have programmed an image slider in javascript, and it's "functional," but it doesn't alternate the images except for the very first and last images. For example, if I'm on the first image and press the right button, it won't change to the next image in the array. However, if I were to push the left button, it will change to last image in the array. The same thing will happen for the last image. I don't know how to fix this. Can you help?
I think it might have to do something with the "total" variable, but I'm not sure.
Here's the code...
window.onload = function () {
var nmbr_imgs = 4;
var imgs_holder = ["IMGS/Actinium.png", "IMGS/Aluminum.png", "IMGS/Astatine.png", "IMGS/Barium.png"];
var total = imgs_holder.length;
var left_btn = document.getElementById('left_btn');
var right_btn = document.getElementById('right_btn');
var imgs_display = document.getElementById('imgs_display');
left_btn.addEventListener('click', function() {
var lefting = total - 1;
imgs_display.src = imgs_holder[lefting];
if (lefting < 0) {
imgs_display.src = imgs_holder[(nmbr_imgs - 1)];
}
}, false);
right_btn.addEventListener('click', function() {
var righting = total + 1;
imgs_display.src = imgs_holder[righting];
if (righting > (nmbr_imgs - 1)) {
imgs_display.src = imgs_holder[0];
}
}, false);
}
Your listeners are off a bit ...
total = total - 1;
imgs_display.src = imgs_holder[total];
if(lefting < 0) {
total = nmbr_imgs - 1;
imgs_display = imgs_holder[total]
}
... try incrementing/decrementing total, not lefting/righting which are reset to total +/- 1 each time.

Categories