Create Pagination in JavaScript with an Array of Objects - javascript

How could I create a Pagination System in JavaScript? There should be 10 products per page.
I have created an Array of products. I want to loop through all of these products and dsiplay the first 10 products on the first page, and then the next 10 products on the next page.
I have created this Array:
let products = {
data: [
{
productName: "Product1",
},
{
productName: "Product2",
},
{
productName: "Product3",
},
{
productName: "Product4",
},
{
productName: "Product5",
},
{
multiple other products
},
],
};
I have looped through all of the products and displayed them on screen like this:
for (let i of products.data) {
let card = document.createElement("div");
let name = document.createElement("h5");
container.appendChild(name);
card.appendChild(container);
document.getElementById("products").appendChild(card);
}
I want to do this in Vanilla JavaScript

Use the .slice method on the array to to get only a subset of what's within it. .slice(start, end) returns the items in the array starting with <start> and ending with <item before end>.
console.log([0,1,2,3,4,5].slice(2,4));
// returns [2,3]
You'd need additional code and buttons elsewhere on the page to keep track of the start position, but loop would be modified as follows:
for (let i of products.data.slice(start, start + 10)) {

I would make an array for each page:
let pages = new Object;
let pageNumber = 1;
for (let i = 0; i < products.data.length; i++) {
if(i === 0) {
pageNumber = 1
} else {
pageNumber = Math.ceil(i / 10);
}
if (Array.isArray(pages[`page${pageNumber}`])){
pages[`page${pageNumber}`].push(products.data[i]);
} else {
pages[`page${pageNumber}`] = new Array;
pages[`page${pageNumber}`].push(products.data[i]);
}
}
Change this:
for (let i of products.data) {
...
}
To this:
function displayPage(pageNumber) {
for (let i of pages[pageNumber]) {
...
}
}
Then I would run a for loop looping over the pages and making a button for each and displaying it when necessary. I would give each button an onclick that will call the
displayPage()

Related

Reset randomization after it goes through all the items in the array

I'm learning JS and I just finished a project, here the code:
const menu = {
_meal: "",
_price: 0,
//Let set the new value of meal only if it's a string.
set meal(mealToCheck) {
if (typeof mealToCheck === "string") {
return this._meal = mealToCheck;
}
},
//Let set the new value of price only if it's a number.
set price(priceToCheck) {
if (typeof priceToCheck === "number") {
return this._price = priceToCheck;
}
},
//If both setters are true, then return a message using them, otherwise return message saying the values are wrong.
get todaysSpecial() {
if (this._meal && this._price) {
return `Today's Special is ${this._meal}, for just ${this._price}£!!`;
} else {
return "Meal and Price wasn't entered correctly!!";
}
}
};
//Arrays for the meal options and respective prices, also a constant to get a random number in the array range.
const meals = ["Pizza", "Steak", "Pie", "Roast", "Moussaka", "Lasagne", "Tacos"];
const prices = [/*Pizza*/9, /*Steak*/13, /*Pie*/11, /*Roast*/14, /*Moussaka*/9, /*Lasagne*/10, /*Tacos*/9];
const random = Math.floor(Math.random() * meals.length);
//Assigns a new random value from the arrays. I used a single randomizer so that you can combine a plate to its price by the index number.
menu.meal = meals[random];
menu.price = prices[random];
//Check if the number of items in the meals and prices array it's equal, and if it is, creates the menu of the day string.
if (meals.length === prices.length) {
console.log(menu.todaysSpecial);
} else {
console.log("The number of prices and meals don't match!!");
}
At the end of the code I added a couple of arrays and a Math.random so that every time I run it, it gives me a different value.
Now I'm trying to find a way to have the random value give unique values until it reaches the array length, and then restart. At the moment I have 7 items in the array simulating the day of the week, I'd like to have each item coming out once per week and then reset.
I know how to do it by following the array index order, but I can't come out with a way to do it randomly, any input?
You can combine your prices and meals array to make it a bit simpler, then shuffle it.
const menu = {
_meal: "",
_price: 0,
//Let set the new value of meal only if it's a string.
set meal(mealToCheck) {
if (typeof mealToCheck === "string") {
return (this._meal = mealToCheck);
}
},
//Let set the new value of price only if it's a number.
set price(priceToCheck) {
if (typeof priceToCheck === "number") {
return (this._price = priceToCheck);
}
},
//If both setters are true, then return a message using them, otherwise return message saying the values are wrong.
get todaysSpecial() {
if (this._meal && this._price) {
return `Today's Special is ${this._meal}, for just ${this._price}£!!`;
} else {
return "Meal and Price wasn't entered correctly!!";
}
}
};
//Arrays for the meal options and respective prices, also a constant to get a random number in the array range.
let meals = [
{ name: "Pizza", price: 9 },
{ name: "Steak", price: 13 },
{ name: "Pie", price: 11 },
{ name: "Roast", price: 14 },
{ name: "Moussaka", price: 9 },
{ name: "Lasagne", price: 10 },
{ name: "Tacos", price: 9 }
];
// Used to shuffle your meals array
function shuffle(array) {
let currentIndex = array.length,
randomIndex;
// While there remain elements to shuffle.
while (currentIndex != 0) {
// Pick a remaining element.
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex],
array[currentIndex]
];
}
return array;
}
meals = shuffle(meals);
// Iterate meals
for (let i = 0; i < meals.length; i++) {
menu.meal = meals[i].name;
menu.price = meals[i].price;
console.log(menu.todaysSpecial);
}
It is easy every time you pick value from the array remove it and when the array end just reset the array to the initial value
For not having probleme with rand nomber it should be like this
Rand=Math.random()*array.lenght;

add or push a 10th index number to the array

I was working on a chart where i need my data to be sliced into small object based for better visibility. My array that i have is
{
"size":[
{
"timestamp":"1641329889000",
"size":12345,
"fees":123456,
"cost":168
},
{
"timestamp":"1641387032",
"size":456789,
"fees":4567891,
"cost":249
},
{
"timestamp":"1641435786",
"size":98765,
"fees":987654,
"cost":987
},
{
"timestamp":"1641435786",
"size":98765,
"fees":987654,
"cost":987
},
{
"timestamp":"1641435786",
"size":98765,
"fees":987654,
"cost":987
}
]
}
in which i want the array to be in this form
{
"size":{
"timestamp": ["1641329889000","1641387032","1641435786"],
"size": [12345,456789,98765],
"fees": [123456,4567891,987654],
"cost": [168,249,987]
}
}
i can achieve this using foreach and push like this
result.forEach(element => {
this.state.timestamp.push(element.timestamp);
this.state.size.push(element.size);
});
But i want this array to have the items only from the 10,20,30,40th index alone
I want not all the value. the values should be chosen only in the basis of x+10
Could anyone help me on this
Instead of forEach why not just use a for loop, and on the condition use the modulus % operator with 10? Like if (i % 10 == 0) inside of the for loop, or just increment i by 10 like i+=10.
You could take a for loop and a step for incrementing the index.
const
step = 10,
keys = ["timestamp", "size", "fees", "cost"],
result = Object.fromEntries(keys.map(k => [k, []]));
for (let i = 0; i < size.lenght; i += step) {
keys.forEach(key => result[key].push(size[i][key]));
}
Using forEach is a waste of resources.
You can use for instead:
for(let i=0;i<result.length;i+10){
this.state.timestamp.push(result[i].timestamp);
this.state.size.push(result[i].size);
}
For setting the state you should use setState not just push to it.
let tmp = {
...this.state
}
for(let i=0;i<result.length;i+10){
tmp.size.timestamp.push(result[i].timestamp);
tmp.size.push(result[i].size);
}
this.setState(tmp)
As mentioned by #cybercoder, you probably don't want to change the state variable within the forEach, as that will cause render to be called excessively.
You could simply use a counter and only push elements when the index is divisible by 10:
let i = 0;
let {timestamp, size} = this.state;
result.forEach(element => {
if (i % 10 === 0) {
timestamp.push(element.timestamp);
size.push(element.size);
}
i++;
});
this.setState({
...this.state,
timestamp,
size
});
If you do not want to include the very first (index 0) element:
let i = 0;
let {timestamp, size} = this.state;
result.forEach(element => {
// Exclude very first element
if (i % 10 === 0 && i !== 0) {
timestamp.push(element.timestamp);
size.push(element.size);
}
i++;
});
this.setState({
...this.state,
timestamp,
size
});

Very simple increment function in objects list

I’m trying to replicate a very simple function that I can get to work with arrays but not with objects. I just want to be able to run a function that logs the next object number as with the numbers array.
Take this working array as an example:
var numbers = [4,2,6],
count = 0;
incrementArr();
function incrementArr() {
if (count < numbers.length) { // if not last array element
console.log(numbers[count]);
count++;
} else {
console.log(numbers[0]);
count = 1;
}
}
Whenever you run the incrementArr function, it’ll just log the next number and then return to the start if the current state (count) is at the end.
However, I cannot replicate the same principle with this object list:
var objs = {
first: { // doesn't have to have 'first'
"number": 4
},
second: { // doesn't have to have 'second'
"number": 2
},
third: { // doesn't have to have 'third'
"number": 6
}
},
count = 0;
incrementObj();
function incrementObj() {
if (count < Object.keys(objs).length) { // if not last obj element
//objs["first"].number
console.log(objs[count].number);
count++;
} else {
console.log(objs["first"].number); // what if no "first" in objects?
count++;
}
}
How could the incrementObj function work the same way that the previous incrementArr function works?
It seems that I can’t pick the specific object instance (e.g. numbers[1] from the array would pick the 2nd number, but only objs[“second”].number would pick the 2nd object, which isn’t iterable if you know what I mean). How could I get a workaround for typical circumstances like this?
So essentially, what’s the difference between this:
first: { // doesn't have to have 'first'
"number": 4
}
and:
{ // doesn't have to have 'first'
"number": 4
}
Why have the "first" etc? (called the key?)
Is there generally a better way of going about object lists (it's difficult to explain)? Thanks for any advice here.
You could take a closure over the object and get the keys and store an index. The returned function get the value and increment and adjusts the index.
function increment(object) {
var keys = Object.keys(object),
index = 0;
return function() {
var value = object[keys[index]].number;
index++;
index %= keys.length;
return value;
};
}
var objs = { first: { number: 4 }, second: { number: 2 }, third: { number: 6 } },
incrementObj = increment(objs);
console.log(incrementObj());
console.log(incrementObj());
console.log(incrementObj());
console.log(incrementObj());
Try this, it access keys through the array generated from keys, objects are unordered list that means you will have to at least order the keys and access them in the array order.
const keysArr = Object.keys(objs);
function incrementObj() {
if (count < keysArr.length) { // if not last obj element
//
console.log(objs[keysArr[count]].number);
count++;
} else {
console.log(objs["first"].number); // what if no "first" in objects?
count++;
}
}
I propose using iterators
See this codepen
If your object have specific shapes, then you use this as a lens to find the number property you want. I'm not sure how you want to use the iterator and have return both the key and the value as separate properties, but you can as well return { [keys[nextIndex]]: values[nextIndex] } or find other shape (the world is your oyster).
Provided you go this length, why not try use RxJs to make your object an observable?
var objs = {
first: { // doesn't have to have 'first'
"number": 4
},
second: { // doesn't have to have 'second'
"number": 2
},
third: { // doesn't have to have 'third'
"number": 6
}
}
function propertyIterator(obj) {
const keys = Object.keys(obj)
const values = Object.values(obj)
const length = keys.length
let nextIndex = 0
return {
next: function() {
const value = {
key: keys[nextIndex],
value: values[nextIndex]
}
let done = false
if (nextIndex >= length) {
done = true
}
nextIndex += 1
return { current: value, done: done}
}
}
}
const incrementObj = propertyIterator(objs)
let result = incrementObj.next()
console.log(result.current.key, result.current.value.number || NaN)
result = incrementObj.next()
console.log(result.current.key, result.current.value.number || NaN)
result = incrementObj.next()
console.log(result.current.key, result.current.value.number || NaN)
using generators, see this codepen:
const objs = {
first: { // doesn't have to have 'first'
"number": 4
},
second: { // doesn't have to have 'second'
"number": 2
},
third: { // doesn't have to have 'third'
"number": 6
}
}
const inc = defaultValue => prop => function* (obj) {
for(let key in obj) {
yield obj[key][prop] || defaultValue
}
}
const getNumber = inc(NaN)('number')
const it = getNumber(objs)
let result = it.next()
while (!result.done) {
console.log(result.value)
result = it.next()
}

Find next available id in array of objects

I have an array of objects. These objects have a property id. I need a function which returns the next available id (which is not used by an object).
array = [
{
id: 1
},
{
id: 2
},
{
id: 5
},
{
id: 3
}
]
I would like to have a function which takes an array as an input and returns a number (which is the next free id).
In the example case:
findFreeId(array){
magic happens
}
result --> 4
How about something like this?
function findFreeId (array) {
const sortedArray = array
.slice() // Make a copy of the array.
.sort(function (a, b) {return a.id - b.id}); // Sort it.
let previousId = 0;
for (let element of sortedArray) {
if (element.id != (previousId + 1)) {
// Found a gap.
return previousId + 1;
}
previousId = element.id;
}
// Found no gaps.
return previousId + 1;
}
// Tests.
let withGap = [{id: 1}, {id: 2}, {id: 5}, {id: 3}];
let noGap = [{id: 1}, {id: 2}];
let empty = [];
console.log(findFreeId(withGap)); // 4
console.log(findFreeId(noGap)); // 3
console.log(findFreeId(empty)); // 1
A simple approach is to get all the ID values, sort them, then starting at 0 look for the first missing number in the sequence. That may be OK where efficiency doesn't matter, but a more efficient method is to:
Get the IDs
Sort them
Step through the values to get the next available number
Insert the value in the list of IDs
Store the value so next time it starts at #3 from the previous value + 1
E.g.
class IDStore {
constructor(dataArray) {
if (!Array.isArray(dataArray)) {
return null;
}
this.previousIndex = 0;
this.indexes = dataArray.map(obj => obj.id).sort();
}
get nextIndex() {
while (this.indexes[this.previousIndex] == this.previousIndex) {
this.previousIndex++;
}
return this.previousIndex;
}
addIndex(index) {
if (!Number.isInteger(index) || this.indexes.find[index]) {
return null;
}
this.indexes.push(index);
this.indexes.sort();
return index;
}
}
var data = [ { id: 1 }, { id: 2 }, { id: 5 }, { id: 3 } ];
// Create an ID store
var idStore = new IDStore(data);
// Insert more objects in the array with unique IDs
for (var i=0, next; i<4; i++) {
// Current list of indexes
console.log('Indexes: ' + idStore.indexes);
// Get the next available index
next = idStore.nextIndex;
console.log('Next available: ' + next);
// Calling nextIndex doesn't affect next index
next = idStore.nextIndex;
console.log('Next available: ' + next);
// Use next index
data.push({id: next});
// Adding next index is manual
idStore.addIndex(next);
console.log('Added: ' + next);
}
// Data structure is independent
console.log('End: ' + JSON.stringify(data));
This is somewhat simplistic in that it assumes the IDs are sequential integers starting at 0 and doesn't have much validation or error handling.
Maintaining the id is separate from adding new members to the data array. It would be much better to combine the operations, so an "add object" method gets the next available ID, adds it to the object, adds the object to the array, updates the index and returns the new ID.
const findFreeId = (ids) => {
let id = 0;
for (id; ; id++) {
let isFree = true;
for (let i = 0; i < array.length; i++) {
const e = ids[i];
if (e === id) {
isFree = false;
break;
}
}
if (isFree) break;
}
return id;
}

Overlong Object Manipulation for Order Form

I'm trying to write an order form for a food delivery website (to learn more about objects in Javascript), so that each item, when selected, populates an array. It should also recognise the quantity requested, if an item is clicked twice, and not create a duplicate. This is my code, which works, but seems overlong. In particular, my final for loop, for increasing quantity, seems as if it should be superfluous. Is there a smarter way doing this?
The JSON data I'm drawing from looks like this:
"dishes": [
{
"id": "1",
"name": "Jumbo Chicken Wings",
"description": "Honey, Ginger, Chilli, Soy",
"price": "4.50"
},
{
"id": "2",
"name": "Spiced Whitebait",
"description": "Lemon Mayonaise",
"price": "5"
}
And this is my (probably overlong) code:
// ORDER FORM
// begin with empty array
var orderform = [];
function chooseDish() {
// when clicking on item...
$("#menu li").click(function(){
//create new object from item listed properties
var item = {
id: $(this).attr('id'),
dish: $(this).find("span.dish-name").text(),
price: $(this).find("span.dish-price").text()
};
// either add first item to array...
if (!orderform.length) {
item.quantity = 1;
orderform.push(item);
}
// or see if an object is already in the array.
else {
var hasDishBeenSelected = false;
for (var i = 0; i < orderform.length; i++) {
if (orderform[i].id === item.id) {
hasDishBeenSelected = true;
}
}
// if the item hasn't already been selected add the item...
if (!hasDishBeenSelected) {
item.quantity = 1;
orderform.push(item);
}
// otherwise increase that item's quantity by 1
else {
for (var j = 0; j < orderform.length; j++) {
if (orderform[j].id === item.id) {
orderform[j].quantity += 1;
}
}
}
}
console.table(orderform);
});
}
Thanks for any tips!

Categories