I am trying to make pagination for my site. (http://anuntorhei.md)
CODE:
var someVar = 50;
function someStupidFunction() {
if (objJson.length > 50) {
document.getElementById("nextPage").style.visibility = "visible";
}
if (someVar <= 50) {
document.getElementById("prevPage").style.visibility ="hidden";
} else {
document.getElementById("prevPage").style.visibility = "visible";
}
}
function nextPage() {
document.getElementById("listingTable").innerHTML = "";
if (someVar < objJson.length) {
document.getElementById("nextPage").style.visibility = "visible";
} else {
document.getElementById("nextPage").style.visibility = "hidden";
}
for (var i = someVar - 50; i < someVar; i++) {
document.getElementById("listingTable").innerHTML += objJson[i].adName + "<br>";
}
someVar += 50;
document.getElementById("prevPage").style.visibility = "visible";
}
function prevPage() {
document.getElementById("listingTable").innerHTML = "";
if (someVar > 50) {
document.getElementById("prevPage").style.visibility = "visible";
} else {
document.getElementById("prevPage").style.visibility = "hidden";
}
for (var i = someVar - 50; i < someVar; i++) {
document.getElementById("listingTable").innerHTML += objJson[i].adName + "<br>";
}
someVar -= 50;
document.getElementById("nextPage").style.visibility = "visible";
}
But I can't understand how to "hide" nextPage button when someVar is bigger than objJson.length.
And when I reach the "end", nextPage button disappear after than objJson is smaller than someVar. What is wrong in this code?
How can I change it to make it perfect? Sorry for my bad English, can't explain all what I need, hope you understand what I need!
I'll address any questions you have... but here is an improved pattern you should follow to reduce code duplication.
As a sidenote though, you should consider not doing pagination on client-side. Since if you have a huge dataset, it would mean you need to download all the data before your page loads. Better to implement server-side pagination instead.
Fiddle: http://jsfiddle.net/Lzp0dw83/
HTML
<div id="listingTable"></div>
Prev
Next
page: <span id="page"></span>
Javascript (put anywhere):
var current_page = 1;
var records_per_page = 2;
var objJson = [
{ adName: "AdName 1"},
{ adName: "AdName 2"},
{ adName: "AdName 3"},
{ adName: "AdName 4"},
{ adName: "AdName 5"},
{ adName: "AdName 6"},
{ adName: "AdName 7"},
{ adName: "AdName 8"},
{ adName: "AdName 9"},
{ adName: "AdName 10"}
]; // Can be obtained from another source, such as your objJson variable
function prevPage()
{
if (current_page > 1) {
current_page--;
changePage(current_page);
}
}
function nextPage()
{
if (current_page < numPages()) {
current_page++;
changePage(current_page);
}
}
function changePage(page)
{
var btn_next = document.getElementById("btn_next");
var btn_prev = document.getElementById("btn_prev");
var listing_table = document.getElementById("listingTable");
var page_span = document.getElementById("page");
// Validate page
if (page < 1) page = 1;
if (page > numPages()) page = numPages();
listing_table.innerHTML = "";
for (var i = (page-1) * records_per_page; i < (page * records_per_page); i++) {
listing_table.innerHTML += objJson[i].adName + "<br>";
}
page_span.innerHTML = page;
if (page == 1) {
btn_prev.style.visibility = "hidden";
} else {
btn_prev.style.visibility = "visible";
}
if (page == numPages()) {
btn_next.style.visibility = "hidden";
} else {
btn_next.style.visibility = "visible";
}
}
function numPages()
{
return Math.ceil(objJson.length / records_per_page);
}
window.onload = function() {
changePage(1);
};
UPDATE 2014/08/27
There is a bug above, where the for loop errors out when a particular page (the last page usually) does not contain records_per_page number of records, as it tries to access a non-existent index.
The fix is simple enough, by adding an extra checking condition into the for loop to account for the size of objJson:
Updated fiddle: http://jsfiddle.net/Lzp0dw83/1/
for (var i = (page-1) * records_per_page; i < (page * records_per_page) && i < objJson.length; i++)
I created a class structure for collections in general that would meet this requirement. and it looks like this:
class Collection {
constructor() {
this.collection = [];
this.index = 0;
}
log() {
return console.log(this.collection);
}
push(value) {
return this.collection.push(value);
}
pushAll(...values) {
return this.collection.push(...values);
}
pop() {
return this.collection.pop();
}
shift() {
return this.collection.shift();
}
unshift(value) {
return this.collection.unshift(value);
}
unshiftAll(...values) {
return this.collection.unshift(...values);
}
remove(index) {
return this.collection.splice(index, 1);
}
add(index, value) {
return this.collection.splice(index, 0, value);
}
replace(index, value) {
return this.collection.splice(index, 1, value);
}
clear() {
this.collection.length = 0;
}
isEmpty() {
return this.collection.length === 0;
}
viewFirst() {
return this.collection[0];
}
viewLast() {
return this.collection[this.collection.length - 1];
}
current(){
if((this.index <= this.collection.length - 1) && (this.index >= 0)){
return this.collection[this.index];
}
else{
return `Object index exceeds collection range.`;
}
}
next() {
this.index++;
this.index > this.collection.length - 1 ? this.index = 0 : this.index;
return this.collection[this.index];
}
previous(){
this.index--;
this.index < 0 ? (this.index = this.collection.length-1) : this.index;
return this.collection[this.index];
}
}
...and essentially what you would do is have a collection of arrays of whatever length for your pages pushed into the class object, and then use the next() and previous() functions to display whatever 'page' (index) you wanted to display. Would essentially look like this:
let books = new Collection();
let firstPage - [['dummyData'], ['dummyData'], ['dummyData'], ['dummyData'], ['dummyData'],];
let secondPage - [['dumberData'], ['dumberData'], ['dumberData'], ['dumberData'], ['dumberData'],];
books.pushAll(firstPage, secondPage); // loads each array individually
books.current() // display firstPage
books.next() // display secondPage
A simple client-side pagination example where data is fetched only once at page loading.
// dummy data
const myarr = [{ "req_no": 1, "title": "test1" },
{ "req_no": 2, "title": "test2" },
{ "req_no": 3, "title": "test3" },
{ "req_no": 4, "title": "test4" },
{ "req_no": 5, "title": "test5" },
{ "req_no": 6, "title": "test6" },
{ "req_no": 7, "title": "test7" },
{ "req_no": 8, "title": "test8" },
{ "req_no": 9, "title": "test9" },
{ "req_no": 10, "title": "test10" },
{ "req_no": 11, "title": "test11" },
{ "req_no": 12, "title": "test12" },
{ "req_no": 13, "title": "test13" },
{ "req_no": 14, "title": "test14" },
{ "req_no": 15, "title": "test15" },
{ "req_no": 16, "title": "test16" },
{ "req_no": 17, "title": "test17" },
{ "req_no": 18, "title": "test18" },
{ "req_no": 19, "title": "test19" },
{ "req_no": 20, "title": "test20" },
{ "req_no": 21, "title": "test21" },
{ "req_no": 22, "title": "test22" },
{ "req_no": 23, "title": "test23" },
{ "req_no": 24, "title": "test24" },
{ "req_no": 25, "title": "test25" },
{ "req_no": 26, "title": "test26" }];
// on page load collect data to load pagination as well as table
const data = { "req_per_page": document.getElementById("req_per_page").value, "page_no": 1 };
// At a time maximum allowed pages to be shown in pagination div
const pagination_visible_pages = 4;
// hide pages from pagination from beginning if more than pagination_visible_pages
function hide_from_beginning(element) {
if (element.style.display === "" || element.style.display === "block") {
element.style.display = "none";
} else {
hide_from_beginning(element.nextSibling);
}
}
// hide pages from pagination ending if more than pagination_visible_pages
function hide_from_end(element) {
if (element.style.display === "" || element.style.display === "block") {
element.style.display = "none";
} else {
hide_from_beginning(element.previousSibling);
}
}
// load data and style for active page
function active_page(element, rows, req_per_page) {
var current_page = document.getElementsByClassName('active');
var next_link = document.getElementById('next_link');
var prev_link = document.getElementById('prev_link');
var next_tab = current_page[0].nextSibling;
var prev_tab = current_page[0].previousSibling;
current_page[0].className = current_page[0].className.replace("active", "");
if (element === "next") {
if (parseInt(next_tab.text).toString() === 'NaN') {
next_tab.previousSibling.className += " active";
next_tab.setAttribute("onclick", "return false");
} else {
next_tab.className += " active"
render_table_rows(rows, parseInt(req_per_page), parseInt(next_tab.text));
if (prev_link.getAttribute("onclick") === "return false") {
prev_link.setAttribute("onclick", `active_page('prev',\"${rows}\",${req_per_page})`);
}
if (next_tab.style.display === "none") {
next_tab.style.display = "block";
hide_from_beginning(prev_link.nextSibling)
}
}
} else if (element === "prev") {
if (parseInt(prev_tab.text).toString() === 'NaN') {
prev_tab.nextSibling.className += " active";
prev_tab.setAttribute("onclick", "return false");
} else {
prev_tab.className += " active";
render_table_rows(rows, parseInt(req_per_page), parseInt(prev_tab.text));
if (next_link.getAttribute("onclick") === "return false") {
next_link.setAttribute("onclick", `active_page('next',\"${rows}\",${req_per_page})`);
}
if (prev_tab.style.display === "none") {
prev_tab.style.display = "block";
hide_from_end(next_link.previousSibling)
}
}
} else {
element.className += "active";
render_table_rows(rows, parseInt(req_per_page), parseInt(element.text));
if (prev_link.getAttribute("onclick") === "return false") {
prev_link.setAttribute("onclick", `active_page('prev',\"${rows}\",${req_per_page})`);
}
if (next_link.getAttribute("onclick") === "return false") {
next_link.setAttribute("onclick", `active_page('next',\"${rows}\",${req_per_page})`);
}
}
}
// Render the table's row in table request-table
function render_table_rows(rows, req_per_page, page_no) {
const response = JSON.parse(window.atob(rows));
const resp = response.slice(req_per_page * (page_no - 1), req_per_page * page_no)
$('#request-table').empty()
$('#request-table').append('<tr><th>Index</th><th>Request No</th><th>Title</th></tr>');
resp.forEach(function (element, index) {
if (Object.keys(element).length > 0) {
const { req_no, title } = element;
const td = `<tr><td>${++index}</td><td>${req_no}</td><td>${title}</td></tr>`;
$('#request-table').append(td)
}
});
}
// Pagination logic implementation
function pagination(data, myarr) {
const all_data = window.btoa(JSON.stringify(myarr));
$(".pagination").empty();
if (data.req_per_page !== 'ALL') {
let pager = `<a href="#" id="prev_link" onclick=active_page('prev',\"${all_data}\",${data.req_per_page})>«</a>` +
`<a href="#" class="active" onclick=active_page(this,\"${all_data}\",${data.req_per_page})>1</a>`;
const total_page = Math.ceil(parseInt(myarr.length) / parseInt(data.req_per_page));
if (total_page < pagination_visible_pages) {
render_table_rows(all_data, data.req_per_page, data.page_no);
for (let num = 2; num <= total_page; num++) {
pager += `<a href="#" onclick=active_page(this,\"${all_data}\",${data.req_per_page})>${num}</a>`;
}
} else {
render_table_rows(all_data, data.req_per_page, data.page_no);
for (let num = 2; num <= pagination_visible_pages; num++) {
pager += `<a href="#" onclick=active_page(this,\"${all_data}\",${data.req_per_page})>${num}</a>`;
}
for (let num = pagination_visible_pages + 1; num <= total_page; num++) {
pager += `<a href="#" style="display:none;" onclick=active_page(this,\"${all_data}\",${data.req_per_page})>${num}</a>`;
}
}
pager += `<a href="#" id="next_link" onclick=active_page('next',\"${all_data}\",${data.req_per_page})>»</a>`;
$(".pagination").append(pager);
} else {
render_table_rows(all_data, myarr.length, 1);
}
}
//calling pagination function
pagination(data, myarr);
// trigger when requests per page dropdown changes
function filter_requests() {
const data = { "req_per_page": document.getElementById("req_per_page").value, "page_no": 1 };
pagination(data, myarr);
}
.box {
float: left;
padding: 50px 0px;
}
.clearfix::after {
clear: both;
display: table;
}
.options {
margin: 5px 0px 0px 0px;
float: left;
}
.pagination {
float: right;
}
.pagination a {
color: black;
float: left;
padding: 8px 16px;
text-decoration: none;
transition: background-color .3s;
border: 1px solid #ddd;
margin: 0 4px;
}
.pagination a.active {
background-color: #4CAF50;
color: white;
border: 1px solid #4CAF50;
}
.pagination a:hover:not(.active) {
background-color: #ddd;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<table id="request-table">
</table>
</div>
<div class="clearfix">
<div class="box options">
<label>Requests Per Page: </label>
<select id="req_per_page" onchange="filter_requests()">
<option>5</option>
<option>10</option>
<option>ALL</option>
</select>
</div>
<div class="box pagination">
</div>
</div>
Below is the pagination logic as a function
function Pagination(pageEleArr, numOfEleToDisplayPerPage) {
this.pageEleArr = pageEleArr;
this.numOfEleToDisplayPerPage = numOfEleToDisplayPerPage;
this.elementCount = this.pageEleArr.length;
this.numOfPages = Math.ceil(this.elementCount / this.numOfEleToDisplayPerPage);
const pageElementsArr = function (arr, eleDispCount) {
const arrLen = arr.length;
const noOfPages = Math.ceil(arrLen / eleDispCount);
let pageArr = [];
let perPageArr = [];
let index = 0;
let condition = 0;
let remainingEleInArr = 0;
for (let i = 0; i < noOfPages; i++) {
if (i === 0) {
index = 0;
condition = eleDispCount;
}
for (let j = index; j < condition; j++) {
perPageArr.push(arr[j]);
}
pageArr.push(perPageArr);
if (i === 0) {
remainingEleInArr = arrLen - perPageArr.length;
} else {
remainingEleInArr = remainingEleInArr - perPageArr.length;
}
if (remainingEleInArr > 0) {
if (remainingEleInArr > eleDispCount) {
index = index + eleDispCount;
condition = condition + eleDispCount;
} else {
index = index + perPageArr.length;
condition = condition + remainingEleInArr;
}
}
perPageArr = [];
}
return pageArr;
}
this.display = function (pageNo) {
if (pageNo > this.numOfPages || pageNo <= 0) {
return -1;
} else {
console.log('Inside else loop in display method');
console.log(pageElementsArr(this.pageEleArr, this.numOfEleToDisplayPerPage));
console.log(pageElementsArr(this.pageEleArr, this.numOfEleToDisplayPerPage)[pageNo - 1]);
return pageElementsArr(this.pageEleArr, this.numOfEleToDisplayPerPage)[pageNo - 1];
}
}
}
const p1 = new Pagination(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 3);
console.log(p1.elementCount);
console.log(p1.pageEleArr);
console.log(p1.numOfPages);
console.log(p1.numOfEleToDisplayPerPage);
console.log(p1.display(3));
This is the best one for me so far, it will include ´...´ at specific offset
function pages(current_page, last_page, onSides = 3) {
// pages
let pages = [];
// Loop through
for (let i = 1; i <= last_page; i++) {
// Define offset
let offset = (i == 1 || last_page) ? onSides + 1 : onSides;
// If added
if (i == 1 || (current_page - offset <= i && current_page + offset >= i) ||
i == current_page || i == last_page) {
pages.push(i);
} else if (i == current_page - (offset + 1) || i == current_page + (offset + 1)) {
pages.push('...');
}
}
return pages;
}
i am assuming you will display 10 data in every page
HTML:-
<!DOCTYPE html>
<html>
<head>
<title>pagination</title>
<link rel="stylesheet" href="pathofcssfile.css">
</head>
<body>
<div>
<table id="user"></table>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<ul>
<li value="1">1</li>
<li value="2">2</li>
<li value="3">3</li>
<li value="4">4</li>
<li value="5">5</li>
<li value="6">6</li>
<li value="7">7</li>
<li value="8">8</li>
<li value="9">9</li>
<li value="10">10</li>
</ul>
<script src="pathnameofjsfile.js" type="text/javascript"></script>
</body>
</html>
JS:-
var xhr = new XMLHttpRequest();
xhr.open('GET',"https://jsonplaceholder.typicode.com/albums",true);
xhr.send();
var udata;
xhr.onload = function()
{
if(this.status == 200)
{
var userdata = JSON.parse(this.responseText);
console.log(userdata);
udata = userdata;
data(1);
}
}
$("li").click(function ()
{
var a = $(this).attr("value");
console.log("value li "+ a);
data(a);
});
function data(a)
{
var output = "";
for(i=((a-1)*10);i<(a*10);i++)
{
output +='<tr>'+
'<td>'+ udata[i].userId + '</td>'+
'<td>'+ udata[i].id + '</td>'+
'<td>'+ udata[i].title + '</td>'+ '<br>'
'</tr>';
}
document.getElementById('user').innerHTML = output;
}
CSS:-
ul{
display: flex;
list-style-type:none;
padding: 20px;
}
li{
padding: 20px;
}
td,tr{
padding: 10px;
}
Following is the Logic which accepts count from user and performs pagination in Javascript.
It prints alphabets. Hope it helps!!. Thankyou.
/*
*****
USER INPUT : NUMBER OF SUGGESTIONS.
*****
*/
var recordSize = prompt('please, enter the Record Size');
console.log(recordSize);
/*
*****
POPULATE SUGGESTIONS IN THE suggestion_set LIST.
*****
*/
var suggestion_set = [];
counter = 0;
asscicount = 65;
do{
if(asscicount <= 90){
var temp = String.fromCharCode(asscicount);
suggestion_set.push(temp);
asscicount += 1;
}else{
asscicount = 65;
var temp = String.fromCharCode(asscicount);
suggestion_set.push(temp);
asscicount += 1;
}
counter += 1;
}while(counter < recordSize);
console.log(suggestion_set);
/*
*****
LOGIC FOR PAGINATION
*****
*/
var totalRecords = recordSize, pageSize = 6;
var q = Math.floor(totalRecords/pageSize);
var r = totalRecords%pageSize;
var itr = 1;
if(r==0 ||r==1 ||r==2) {
itr=q;
}
else {
itr=q+1;
}
console.log(itr);
var output = "", pageCnt=1, newPage=false;
if(totalRecords <= pageSize+2) {
output += "\n";
for(var i=0; i < totalRecords; i++){
output += suggestion_set[i] + "\t";
}
}
else {
output += "\n";
for(var i=0; i<totalRecords; i++) {
//output += (i+1) + "\t";
if(pageCnt==1){
output += suggestion_set[i] + "\t";
if((i+1)==(pageSize+1)) {
output += "Next" + "\t";
pageCnt++;
newPage=true;
}
}
else {
if(newPage) {
output += "\n" + "Previous" + "\t";
newPage = false;
}
output += suggestion_set[i] + "\t";
if((i+1)==(pageSize*pageCnt+1) && (pageSize*pageCnt+1)<totalRecords) {
if((i+2) == (pageSize*pageCnt+2) && pageCnt==itr) {
output += (suggestion_set[i] + 1) + "\t";
break;
}
else {
output += "Next" + "\t";
pageCnt++;
newPage=true;
}
}
}
}
}
console.log(output);
file:icons.svg
<svg aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="icon-triangle-left" viewBox="0 0 20 20">
<title>triangle-left</title>
<path d="M14 5v10l-9-5 9-5z"></path>
</symbol>
<symbol id="icon-triangle-right" viewBox="0 0 20 20">
<title>triangle-right</title>
<path d="M15 10l-9 5v-10l9 5z"></path>
</symbol>
</defs>
</svg>
file: style.css
.results__btn--prev{
float: left;
flex-direction: row-reverse; }
.results__btn--next{
float: right; }
file index.html:
<body>
<form class="search">
<input type="text" class="search__field" placeholder="Search over 1,000,000 recipes...">
<button class="btn search__btn">
<svg class="search__icon">
<use href="img/icons.svg#icon-magnifying-glass"></use>
</svg>
<span>Search</span>
</button>
</form>
<div class="results">
<ul class="results__list">
</ul>
<div class="results__pages">
</div>
</div>
</body>
file: searchView.js
export const element = {
searchForm:document.querySelector('.search'),
searchInput: document.querySelector('.search__field'),
searchResultList: document.querySelector('.results__list'),
searchRes:document.querySelector('.results'),
searchResPages:document.querySelector('.results__pages')
}
export const getInput = () => element.searchInput.value;
export const clearResults = () =>{
element.searchResultList.innerHTML=``;
element.searchResPages.innerHTML=``;
}
export const clearInput = ()=> element.searchInput.value = "";
const limitRecipeTitle = (title, limit=17)=>{
const newTitle = [];
if(title.length>limit){
title.split(' ').reduce((acc, cur)=>{
if(acc+cur.length <= limit){
newTitle.push(cur);
}
return acc+cur.length;
},0);
}
return `${newTitle.join(' ')} ...`
}
const renderRecipe = recipe =>{
const markup = `
<li>
<a class="results__link" href="#${recipe.recipe_id}">
<figure class="results__fig">
<img src="${recipe.image_url}" alt="${limitRecipeTitle(recipe.title)}">
</figure>
<div class="results__data">
<h4 class="results__name">${recipe.title}</h4>
<p class="results__author">${recipe.publisher}</p>
</div>
</a>
</li>
`;
var htmlObject = document.createElement('div');
htmlObject.innerHTML = markup;
element.searchResultList.insertAdjacentElement('beforeend',htmlObject);
}
const createButton = (page, type)=>`
<button class="btn-inline results__btn--${type}" data-goto=${type === 'prev'? page-1 : page+1}>
<svg class="search__icon">
<use href="img/icons.svg#icon-triangle-${type === 'prev'? 'left' : 'right'}}"></use>
</svg>
<span>Page ${type === 'prev'? page-1 : page+1}</span>
</button>
`
const renderButtons = (page, numResults, resultPerPage)=>{
const pages = Math.ceil(numResults/resultPerPage);
let button;
if(page == 1 && pages >1){
//button to go to next page
button = createButton(page, 'next');
}else if(page<pages){
//both buttons
button = `
${createButton(page, 'prev')}
${createButton(page, 'next')}`;
}
else if (page === pages && pages > 1){
//Only button to go to prev page
button = createButton(page, 'prev');
}
element.searchResPages.insertAdjacentHTML('afterbegin', button);
}
export const renderResults = (recipes, page=1, resultPerPage=10) =>{
/*//recipes.foreach(el=>renderRecipe(el))
//or foreach will automatically call the render recipes
//recipes.forEach(renderRecipe)*/
const start = (page-1)*resultPerPage;
const end = page * resultPerPage;
recipes.slice(start, end).forEach(renderRecipe);
renderButtons(page, recipes.length, resultPerPage);
}
file: Search.js
export default class Search{
constructor(query){
this.query = query;
}
async getResults(){
try{
const res = await axios(`https://api.com/api/search?&q=${this.query}`);
this.result = res.data.recipes;
//console.log(this.result);
}catch(error){
alert(error);
}
}
}
file: Index.js
onst state = {};
const controlSearch = async()=>{
const query = searchView.getInput();
if (query){
state.search = new Search(query);
searchView.clearResults();
searchView.clearInput();
await state.search.getResults();
searchView.renderResults(state.search.result);
}
}
//event listner to the parent object to delegate the event
element.searchForm.addEventListener('submit', event=>{
console.log("submit search");
event.preventDefault();
controlSearch();
});
element.searchResPages.addEventListener('click', e=>{
const btn = e.target.closest('.btn-inline');
if(btn){
const goToPage = parseInt(btn.dataset.goto, 10);//base 10
searchView.clearResults();
searchView.renderResults(state.search.result, goToPage);
}
});
Just create and save a page token in global variable with window.nextPageToken. Send this to API server everytime you make a request and have it return the next one with response and you can easily keep track of last token. The below is an example how you can move forward and backward from search results. The key is the offset you send to API based on the nextPageToken that you have saved:
function getPrev() {
var offset = Number(window.nextPageToken) - limit * 2;
if (offset < 0) {
offset = 0;
}
window.nextPageToken = offset;
if (canSubmit(searchForm, offset)) {
searchForm.submit();
}
}
function getNext() {
var offset = Number(window.nextPageToken);
window.nextPageToken = offset;
if (canSubmit(searchForm, offset)) {
searchForm.submit();
}
}
var data = [1, 2, 3, 4, 5, 6, 7];
var item_per_page = 3;
var current_page = 1;
var pagination = {
total: data.length,
per_page: item_per_page,
current_page: current_page,
last_page: Math.ceil(data.length / item_per_page),
from: (current_page - 1) * item_per_page + 1,
to: current_page * item_per_page,
};
changePage();
function changePage() {
var temp = [];
for (let i = pagination.from; i <= pagination.to; i++) {
temp.push(data[i - 1]);
}
document.getElementById("result").innerHTML = temp.filter(x => x);
console.log(pagination);
}
function up() {
if (pagination.from == 1) {
return false;
}
pagination.current_page -= 1;
pagination.from = (pagination.current_page - 1) * item_per_page + 1;
pagination.to = pagination.current_page * item_per_page;
changePage();
}
function down() {
if (pagination.last_page == pagination.current_page) {
return false;
}
pagination.current_page += 1;
pagination.from = (pagination.current_page - 1) * item_per_page + 1;
pagination.to = pagination.current_page * item_per_page;
changePage();
}
console.log(pagination);
button {
width: 100px;
}
<div style="display: grid">
<button type="button" onclick="up()">Up</button>
<div id="result"></div>
<button type="button" onclick="down()">Down</button>
</div>
You can use the code from this minimal plugin.
https://www.npmjs.com/package/paginator-js
Array.prototype.paginate = function(pageNumber, itemsPerPage){
pageNumber = Number(pageNumber)
itemsPerPage = Number(itemsPerPage)
pageNumber = (pageNumber < 1 || isNaN(pageNumber)) ? 1 : pageNumber
itemsPerPage = (itemsPerPage < 1 || isNaN(itemsPerPage)) ? 1 : itemsPerPage
var start = ((pageNumber - 1) * itemsPerPage)
var end = start + itemsPerPage
var loopCount = 0
var result = {
data: [],
end: false
}
for(loopCount = start; loopCount < end; loopCount++){
this[loopCount] && result.data.push(this[loopCount]);
}
if(loopCount == this.length){
result.end = true
}
return result
}
Related
I've been struggling with value inputting into tables and table sorting. Finally I got happy when I got my first project working as inteded in jsbin while writing it, but when I exported it into my VSCode it stopped working. In the snippet initially it works, but after inputting something into the table the sorting stops working. In VSCode while ran on liveserver the table is missing implying that there's something wrong in the js.
This code is based on two examples that I found online and tried to combine them together but I assume they are overlapping each other somehow. Unfortunately I have no idea where to even start looking from.
Also how and where I could insert array.reverse() if I wanted to get reverse sorting?
And I just started learning Javascript, so my knowledge and understanding is really limited. Sorry and thank you.
class Product{
constructor(name, price, count){
this.name = name;
this.price = price;
this.count = count;
}
static get SORT_ORDER_ASC(){
return 0;
}
static get SORT_ORDER_DESC(){
return 1;
}
}
class Shop{
constructor(){
this.products = [];
}
addProduct (product) {
this.products.push(product);
};
deleteProductByName (productName) {
for (let i = 0; i < this.products.length; i++) {
if (this.products[i].name === productName) {
this.products.splice(i, 1);
}
}
};
get totalProductsPrice () {
let totalCost = 0;
for (let i = 0; i < this.products.length; i++) {
totalCost += this.products[i].count * this.products[i].price;
}
return totalCost;
};
sortProductsByPrice (sortOrder) {
let rows = document.querySelectorAll("#shopTable .data");
for(let i = 0; i < rows.length; i++)
{
this.products[i].name = rows.item(i).toString();
console.log(this.products[i].name);
}
if(sortOrder === 0) {
this.products.sort();
this.products.map(t => t.name + " " + t.price).join("\n");
}
else if(sortOrder === 1) {
this.products.sort();
this.products.reverse();
this.products.map(t => t.name + " " + t.price).join("\n");
}
else {
console.log("The parameter is incorrect");
}
};
show() {
let rows = document.querySelectorAll("#shopTable .data");
let tp = document.querySelectorAll("#totalPrice .data");
for (let i = rows.length - 1; i >= 0; i--) {
let e = rows.item(i);
e.parentNode.removeChild(e);
}
if(document.getElementById("totalPrice") !== null){
document.getElementById("totalPrice").remove();
}
//tp.parentNode.removeChild(tp);
let table = document.getElementById("shopTable");
for (let i = 0; i < this.products.length; i++) {
table.innerHTML += `<tbody id="tbProducts"><tr class="data">
<td>${this.products[i].name}</td>
<td>${this.products[i].price}</td>
<td>${this.products[i].count}</td>
</tr></tbody>`;
}
table.innerHTML += `<tfoot><tr><td id="totalPrice">Total price: ${shop.totalProductsPrice}</td></tr></tfoot>`;
}
}
let shop = new Shop();
shop.addProduct(new Product("product1", 200, 10));
shop.addProduct(new Product("product2", 500, 1));
shop.addProduct(new Product("product3", 1000, 1));
shop.show();
let btnAdd = document.getElementById("btnAdd");
btnAdd.addEventListener('click', (e) => {
e.preventDefault();
shop.addProduct(new Product(document.getElementById('_add_name').value,
parseInt(document.getElementById('_price').value),
parseInt(document.getElementById('_count').value)));
//let tmpTotalPrice =
document.getElementById("totalPrice").innerHTML = shop.totalProductsPrice;
shop.show();
}, false);
let btnDlt = document.getElementById("btnDlt");
btnDlt.addEventListener('click', (e) => {
e.preventDefault();
shop.deleteProductByName(document.getElementById('_del_name').value);
shop.show();
}, false);
/**
* Inject hyperlinks, into the column headers of sortable tables, which sort
* the corresponding column when clicked.
*/
var tables = document.querySelectorAll("table.sortable"),
table,
thead,
headers,
i,
j;
for (i = 0; i < tables.length; i++) {
table = tables[i];
if (thead = table.querySelector("thead")) {
headers = thead.querySelectorAll("th");
for (j = 0; j < headers.length; j++) {
headers[j].innerHTML = "<a href='#'>" + headers[j].innerText + "</a>";
}
thead.addEventListener("click", sortTableFunction(table));
}
}
/**
* Create a function to sort the given table.
*/
function sortTableFunction(table) {
return function(ev) {
if (ev.target.tagName.toLowerCase() == 'a') {
sortRows(table, siblingIndex(ev.target.parentNode));
ev.preventDefault();
}
};
}
/**
* Get the index of a node relative to its siblings — the first (eldest) sibling
* has index 0, the next index 1, etc.
*/
function siblingIndex(node) {
var count = 0;
while (node = node.previousElementSibling) {
count++;
}
return count;
}
/**
* Sort the given table by the numbered column (0 is the first column, etc.)
*/
function sortRows(table, columnIndex) {
var rows = table.querySelectorAll("tbody tr"),
sel = "thead th:nth-child(" + (columnIndex + 1) + ")",
sel2 = "td:nth-child(" + (columnIndex + 1) + ")",
classList = table.querySelector(sel).classList,
values = [],
cls = "",
allNum = true,
val,
index,
node;
if (classList) {
if (classList.contains("date")) {
cls = "date";
} else if (classList.contains("number")) {
cls = "number";
}
}
for (index = 0; index < rows.length; index++) {
node = rows[index].querySelector(sel2);
val = node.innerText;
if (isNaN(val)) {
allNum = false;
} else {
val = parseFloat(val);
}
values.push({ value: val, row: rows[index] });
}
if (cls == "" && allNum) {
cls = "number";
}
if (cls == "number") {
values.sort(sortNumberVal);
values = values.reverse();
} else if (cls == "date") {
values.sort(sortDateVal);
} else {
values.sort(sortTextVal);
}
for (var idx = 0; idx < values.length; idx++) {
table.querySelector("tbody").appendChild(values[idx].row);
}
}
/**
* Compare two 'value objects' numerically
*/
function sortNumberVal(a, b) {
return sortNumber(a.value, b.value);
}
/**
* Numeric sort comparison
*/
function sortNumber(a, b) {
return a - b;
}
/**
* Compare two 'value objects' as dates
*/
function sortDateVal(a, b) {
var dateA = Date.parse(a.value),
dateB = Date.parse(b.value);
return sortNumber(dateA, dateB);
}
/**
* Compare two 'value objects' as simple text; case-insensitive
*/
function sortTextVal(a, b) {
var textA = (a.value + "").toUpperCase();
var textB = (b.value + "").toUpperCase();
if (textA < textB) {
return -1;
}
if (textA > textB) {
return 1;
}
return 0;
}
body { margin-top: 4em; }
table, td, th { border: 1px solid black; margin: auto; }
td, th { padding: 0.5em 1em; }
<div id="_shop">
<form id="addForm">
<label for="_add_name">Name </label><input id="_add_name"><br/><br/>
<label for="_price">Price </label><input id="_price"><br/><br/>
<label for="_count">Count </label><input id="_count"><br/><br/>
<input type="button" id="btnAdd" value="Add"><br/><br/>
</form>
<form id="removeForm">
<label for="_del_name">Enter Name </label><input id="_del_name"><br/><br/>
<input type="button" id="btnDlt" value="Delete"><br/><br/>
</form>
<table class="sortable" id="shopTable" align="left">
<thead>
<th>Name:</th>
<th>Price:</th>
<th>Count:</th>
</thead>
</table>
There were few things odd with your code. I think, the sorting functionality wasn't implemented in the code you provided. Maybe you exported an older version?
Anyway, here are the few things, that you needed to change:
In the sortProductsByPrice() method, you were setting the name property of the product (in this.products array) to rows.item(i) which was completely off.
rows.item(i) will be the tr element at given index. What you wanted to do is set corresponding properties to corresponding td's values (rows is array of tr and each tr has three td elements.)
In the same method, where you sort the array, you need to provide a custom function to sort the products based on their price. This is needed, because JavaScript's default sort sorts the elements alphabetically. Moreover, this.products is an array of objects, so you need to sort them based on their price property.
In the event listener of btnAdd, you need to call the sortProductsByPrice method, before calling the show method.
class Product{
constructor(name, price, count){
this.name = name;
this.price = price;
this.count = count;
}
static get SORT_ORDER_ASC(){
return 0;
}
static get SORT_ORDER_DESC(){
return 1;
}
}
class Shop{
constructor(){
this.products = [];
}
addProduct (product) {
this.products.push(product);
};
deleteProductByName (productName) {
for (let i = 0; i < this.products.length; i++) {
if (this.products[i].name === productName) {
this.products.splice(i, 1);
}
}
};
get totalProductsPrice () {
let totalCost = 0;
for (let i = 0; i < this.products.length; i++) {
totalCost += this.products[i].count * this.products[i].price;
}
return totalCost;
};
sortProductsByPrice (sortOrder) {
let rows = document.querySelectorAll("#shopTable .data");
for(let i = 0; i < rows.length; i++)
{
let td = rows[i].querySelectorAll("td")
this.products[i].name = td[0].innerHTML;
this.products[i].price = td[1].innerHTML;
this.products[i].count = td[2].innerHTML;
//console.log(this.products[i].name);
}
if(sortOrder === 0) {
this.products.sort((a,b) => a.price - b.price);
this.products.map(t => t.name + " " + t.price).join("\n");
}
else if(sortOrder === 1) {
this.products.sort((a,b) => a.price - b.price);
this.products.reverse();
this.products.map(t => t.name + " " + t.price).join("\n");
}
else {
console.log("The parameter is incorrect");
}
};
show() {
let rows = document.querySelectorAll("#shopTable .data");
let tp = document.querySelectorAll("#totalPrice .data");
for (let i = rows.length - 1; i >= 0; i--) {
let e = rows.item(i);
e.parentNode.removeChild(e);
}
if(document.getElementById("totalPrice") !== null){
document.getElementById("totalPrice").remove();
}
//tp.parentNode.removeChild(tp);
let table = document.getElementById("shopTable");
for (let i = 0; i < this.products.length; i++) {
table.innerHTML += `<tbody id="tbProducts"><tr class="data">
<td>${this.products[i].name}</td>
<td>${this.products[i].price}</td>
<td>${this.products[i].count}</td>
</tr></tbody>`;
}
table.innerHTML += `<tfoot><tr><td id="totalPrice">Total price: ${shop.totalProductsPrice}</td></tr></tfoot>`;
}
}
let shop = new Shop();
shop.addProduct(new Product("product1", 200, 10));
shop.addProduct(new Product("product2", 500, 1));
shop.addProduct(new Product("product3", 1000, 1));
shop.show();
let btnAdd = document.getElementById("btnAdd");
btnAdd.addEventListener('click', (e) => {
e.preventDefault();
shop.addProduct(new Product(document.getElementById('_add_name').value,
parseInt(document.getElementById('_price').value),
parseInt(document.getElementById('_count').value)));
//let tmpTotalPrice =
document.getElementById("totalPrice").innerHTML = shop.totalProductsPrice;
shop.sortProductsByPrice(0)
shop.show();
}, false);
let btnDlt = document.getElementById("btnDlt");
btnDlt.addEventListener('click', (e) => {
e.preventDefault();
shop.deleteProductByName(document.getElementById('_del_name').value);
shop.show();
}, false);
/**
* Inject hyperlinks, into the column headers of sortable tables, which sort
* the corresponding column when clicked.
*/
var tables = document.querySelectorAll("table.sortable"),
table,
thead,
headers,
i,
j;
for (i = 0; i < tables.length; i++) {
table = tables[i];
if (thead = table.querySelector("thead")) {
headers = thead.querySelectorAll("th");
for (j = 0; j < headers.length; j++) {
headers[j].innerHTML = "<a href='#'>" + headers[j].innerText + "</a>";
}
thead.addEventListener("click", sortTableFunction(table));
}
}
/**
* Create a function to sort the given table.
*/
function sortTableFunction(table) {
return function(ev) {
if (ev.target.tagName.toLowerCase() == 'a') {
sortRows(table, siblingIndex(ev.target.parentNode));
ev.preventDefault();
}
};
}
/**
* Get the index of a node relative to its siblings — the first (eldest) sibling
* has index 0, the next index 1, etc.
*/
function siblingIndex(node) {
var count = 0;
while (node = node.previousElementSibling) {
count++;
}
return count;
}
/**
* Sort the given table by the numbered column (0 is the first column, etc.)
*/
function sortRows(table, columnIndex) {
var rows = table.querySelectorAll("tbody tr"),
sel = "thead th:nth-child(" + (columnIndex + 1) + ")",
sel2 = "td:nth-child(" + (columnIndex + 1) + ")",
classList = table.querySelector(sel).classList,
values = [],
cls = "",
allNum = true,
val,
index,
node;
if (classList) {
if (classList.contains("date")) {
cls = "date";
} else if (classList.contains("number")) {
cls = "number";
}
}
for (index = 0; index < rows.length; index++) {
node = rows[index].querySelector(sel2);
val = node.innerText;
if (isNaN(val)) {
allNum = false;
} else {
val = parseFloat(val);
}
values.push({ value: val, row: rows[index] });
}
if (cls == "" && allNum) {
cls = "number";
}
if (cls == "number") {
values.sort(sortNumberVal);
values = values.reverse();
} else if (cls == "date") {
values.sort(sortDateVal);
} else {
values.sort(sortTextVal);
}
for (var idx = 0; idx < values.length; idx++) {
table.querySelector("tbody").appendChild(values[idx].row);
}
}
/**
* Compare two 'value objects' numerically
*/
function sortNumberVal(a, b) {
return sortNumber(a.value, b.value);
}
/**
* Numeric sort comparison
*/
function sortNumber(a, b) {
return a - b;
}
/**
* Compare two 'value objects' as dates
*/
function sortDateVal(a, b) {
var dateA = Date.parse(a.value),
dateB = Date.parse(b.value);
return sortNumber(dateA, dateB);
}
/**
* Compare two 'value objects' as simple text; case-insensitive
*/
function sortTextVal(a, b) {
var textA = (a.value + "").toUpperCase();
var textB = (b.value + "").toUpperCase();
if (textA < textB) {
return -1;
}
if (textA > textB) {
return 1;
}
return 0;
}
body { margin-top: 4em; }
table, td, th { border: 1px solid black; margin: auto; }
td, th { padding: 0.5em 1em; }
<div id="_shop">
<form id="addForm">
<label for="_add_name">Name </label><input id="_add_name"><br/><br/>
<label for="_price">Price </label><input id="_price"><br/><br/>
<label for="_count">Count </label><input id="_count"><br/><br/>
<input type="button" id="btnAdd" value="Add"><br/><br/>
</form>
<form id="removeForm">
<label for="_del_name">Enter Name </label><input id="_del_name"><br/><br/>
<input type="button" id="btnDlt" value="Delete"><br/><br/>
</form>
<table class="sortable" id="shopTable" align="left">
<thead>
<th>Name:</th>
<th>Price:</th>
<th>Count:</th>
</thead>
</table>
I can place my small parts in the most optimized way for a single large part in my project. The algorithm logic is as follows; The pieces I have are sorted by height from largest to smallest and then placed from left to right. when i have multiple large parts i keep those big parts in a state.
In the first large piece, when there is no suitable place for the small pieces to be added, I want the appropriate region to be queried in the second big piece. here is my code:
index.js
import React, { useContext, useEffect, useRef, useState } from 'react'
import data from '../data'
import Graph from './graph/graph'
import SmallAreaGraph from './graph/small-area-graph';
import { IndexContext } from './IndexContext';
function Index() {
var height = 50;
var width = 50;
const [defaultHeight, setDefaultHeight] = useState(50);
const [defaultWidth, setDefaultWidth] = useState(50);
const [planes, setPlanes] = useState();
const [testState, setTestState] = useState([]);
const [bigBoard, setBigBoard] = useState(new Array(defaultWidth).fill(0).map(() => new Array(defaultHeight).fill(0)));
const [smallPlanes, setSmallPlanes] = useState([]);
const [smallPlanesArea, setSmallPlanesArea] = useState([]);
const [freeSpaceAreas, setFreeSpaceAreas] = useState([]);
const [bigPlanes, setBigPlanes] = useState([{ bigBoard: bigBoard, planes: [], height: defaultHeight, width: defaultWidth, color: "pink" }]);
var totalWidth;
const heightRef = useRef();
const widthRef = useRef();
var smallPlane, totalArea = 0;
function Placement() {
let total = 0;
let totalHeight = 0;
let allArea = [];
for (let i = 0; i < smallPlanes.length; i++) {
if (i === 0) {
smallPlanes[i].x = 1;
} else {
if (allArea !== []) {
} else {
total = total + smallPlanes[i - 1].width + 2;
totalHeight = totalHeight + smallPlanes[i - 1].height + 2;
allArea.push(smallPlanes[i - 1]);
}
if (total + smallPlanes[i].width > Number(width)) {
total = 0;
allArea.push(smallPlanes[i]);
smallPlanes[i].x = 1;
smallPlanes[i].y = allArea[0].height + 2;
return total
} else {
smallPlanes[i].x = total;
}
}
}
}
function Sort() {
let gecici;
for (let i = 0; i <= testState.length - 1; i++) {
for (let j = i; j <= testState.length; j++) {
// >(büyük) işareti <(küçük ) olarak değiştirilirse büyükten küçüğe sıralanır
if (testState[i]?.height < testState[j]?.height) {
gecici = testState[j];
testState[j] = testState[i];
testState[i] = gecici;
setTestState(testState);
}
}
}
// Placement();
}
useEffect(() => {
if (testState !== [] || testState !== undefined) {
Sort();
}
}, [testState]);
function AddBigPlane() {
setBigPlanes([...bigPlanes, { bigBoard: bigBoard, planes: [], height: defaultHeight, width: defaultWidth, color: "pink" }])
}
function Revaluation(w, h, row, col, k) {
totalWidth = totalWidth + Number(w);
if (Number(col + w) <= bigPlanes[k].bigBoard.length) {
if (Number(row + h) <= bigPlanes[k].bigBoard[row].length) {
for (let i = row; i < Number(row + h); i++) {
for (let j = col; j < Number(col + w); j++) {
let bashData = bigPlanes[k];
bashData.bigBoard[i][j] = 1
setBigPlanes(bashData);
}
}
}
}
}
function test(w, h, row, col, index) {
if (Number(row + w) <= bigPlanes[index].width && Number(col + h) <= bigPlanes[index].height) {
for (let i = row; i < Number(row + w); i++) {
for (let j = col; j < Number(col + h); j++) {
if (bigPlanes[index].bigBoard[i][j] === 0) {
if (i === (Number(row + w) - 1) && j === (Number(col + h) - 1)) {
freeSpaceAreas[index] = freeSpaceAreas[index] - smallPlane;
setFreeSpaceAreas([...freeSpaceAreas]);
setTestState([...testState, {
height: Number(heightRef?.current?.value), width: Number(widthRef?.current?.value)
}])
// return Revaluation(Number(widthRef?.current?.value), Number(heightRef?.current?.value), row, col, index);
// let bashData = bigPlanes;
// bashData[k].planes.height = Number(heightRef?.current?.value);
// bashData[k].planes.width = Number(widthRef?.current?.value);
// setBigPlanes(bashData);
}
}
}
}
}
}
function Control(index) {
//ilk 0 değerine sahip row-col (coordinat) değerlri
console.log(index);
for (let row = 0; row < bigPlanes[index].bigBoard.length; row++) {
for (let col = 0; col < bigPlanes[index].bigBoard[row].length; col++) {
if (bigPlanes[index].bigBoard[row][col] === 0) {
//bulunduktan sonra test fonksiyonuna aktarılır.
return test(Number(widthRef.current.value), Number(heightRef.current.value), row, col, index);
}
}
}
}
useEffect(() => {
if (bigPlanes.length !== freeSpaceAreas.length) {
for (let i = 0; i < bigPlanes.length; i++) {
console.log(bigPlanes);
setFreeSpaceAreas([...freeSpaceAreas, bigPlanes[i].width * bigPlanes[i].height])
}
}
}, [bigPlanes]);
function AreaControl() {
// smallPlanesArea?.length && smallPlanesArea.map(area => {
// totalArea = totalArea + area;
// })
console.log("test");
for (let i = 0; i < freeSpaceAreas.length; i++) {
if (smallPlane <= freeSpaceAreas[i]) {
console.log(i);
return Control(i);
}
}
heightRef.current.value = "";
widthRef.current.value = "";
}
function handleKeyDown(e) {
if (e.key === "Enter") {
if (heightRef?.current.value !== "") {
if (widthRef.current.value !== "") {
smallPlane = Number(heightRef?.current.value) * Number(widthRef?.current.value);
AreaControl();
// widthRef.current.value = "";
// heightRef.current.value = "";
} else {
alert("Lütfen bir genişlik değeri giriniz");
}
} else {
alert("Lütfen bir yükseklik değeri giriniz");
}
}
}
useEffect(() => {
console.log(freeSpaceAreas);
}, [freeSpaceAreas]);
function AddAreas() {
// Gerçek zamanlı arr state'i güncelleme.
setPlanes([...smallPlanes]);
ResetSmallPlane();
ResetBigPlane();
for (let i = 0; i < testState.length; i++) {
findCoords(testState[i])
}
}
var totalWidth = 0, totalHeight = 0, totW = 0, totH = 0;
// function RevaluationTwo(w, h, row, col) {
// let bashData;
// for (let i = row; i < Number(row + h); i++) {
// for (let j = col; j < Number(col + w); j++) {
// bashData = bigBoard;
// bashData[i][j] = 1;
// setBigBoard(bashData);
// }
// }
// }
function ResetBigPlane() {
for (let k = 0; k < bigPlanes.length; k++) {
for (let row = 0; row < bigPlanes[k].bigBoard.length; row++) {
for (let col = 0; col < bigPlanes[k].bigBoard[row].length; col++) {
if (bigPlanes[k].bigBoard[row][col] === 1) {
let bashData = bigPlanes;
bashData[k].bigBoard[row][col] = 0
setBigPlanes(bashData);
}
}
}
}
}
function bigPlanesControl() {
for (let i = 0; i < bigPlanes.length; i++) {
}
}
function ResetSmallPlane() {
let arrAttributes = [];
for (let i = 0; i < bigPlanes.length; i++) {
var arr = bigPlanes[i].planes;
arr.length = 0;
arrAttributes.push(arr);
}
setBigPlanes([...arrAttributes]);
}
function createCoords(w, h, row, col, i) {
let bashData = [];
totW = totW + Number(w);
if (Number(col + w) <= bigPlanes[i].width) {
if (Number(row + h) <= bigPlanes[i].height) {
bashData = bigPlanes;
bashData[i].planes.push({ height: h, width: w, x: col + 1, y: row + 1 });
setBigPlanes([...bashData]);
} else {
return;
}
} else {
return;
}
}
function findCoords(test) {
console.log(test);
for (let k = 0; k < bigPlanes.length; k++) {
for (let row = 0; row < bigPlanes[k].bigBoard.length; row++) {
for (let col = 0; col < bigPlanes[k].bigBoard[row].length; col++) {
if (bigPlanes[k].bigBoard[row][col] === 0) {
Revaluation(test.width, test.height, row, col, k);
if (Number(bigPlanes[k].bigBoard[row].length - col) >= test.width) {
return createCoords(test.width, test.height, row, col, k);
}
else
return;
}
}
}
}
}
function Approve() {
ResetSmallPlane();
ResetBigPlane();
for (let i = 0; i < testState.length; i++) {
findCoords(testState[i])
}
}
return (
<div className='container mt-5'>
<div className='big-plane'>
</div>
<div className='d-flex justify-content-between '>
<div></div>
<div className='d-flex'>
<div className='me-4'>
<input className='input form-control ' type="text" ref={heightRef} placeholder="Yükseklik giriniz.." onKeyUp={handleKeyDown} />
</div>
<div className='me-4'>
<input className='input form-control ' type="text" ref={widthRef} placeholder="Genişlik giriniz.." onKeyUp={handleKeyDown} />
</div>
<div className='btn btn-success' onClick={() => Approve()}>
Onayla
</div>
<div className='btn btn-success' onClick={() => AddAreas()}>
Ekle
</div>
</div>
<div className='btn btn-danger d-flex align-items-center'>
<div onClick={() => AddBigPlane()}>Cam Plaka Ekle</div> <b style={{ fontWeight: "bolder", fontSize: "20px", marginLeft: "5px" }}>+</b>
</div>
</div>
{
testState?.length ? testState.map((plane, i) => {
return <SmallAreaGraph color="purple" key={i} data={data} height={Number(plane.height)} width={Number(plane.width)} />
}) : ""
}
<div className='mt-5'>
{/* where large parts are added */}
{
bigPlanes.length ? bigPlanes.map((plane, i) => {
totalWidth = totalWidth + bigPlanes[i].width;
return <Graph smallPlanesProps={plane.planes} data={plane.bigBoard} key={i} color={plane.color} height={plane.height} width={plane.width} x={0} y={0} position="absolute" zIndex="-10" left={totalWidth} />
}
) : ""
}
</div>
</div>
)
}
export default Index
I have function CarFactory, which produce cars and should change color of these cars.
const warehouse = require("./warehouse");
function CarFactory(power = 10) {
this.warehouse = warehouse;
this.produceCar = (color = "red", wheels = 4, engine = false) => {
if (power < 2) {
return null
} else {
let car = { "id": warehouse.nextIdentifier, "color": color, "wheels": wheels, "engine": engine }
warehouse.createdCars.push(car);
warehouse.nextIdentifier++;
}
}
this.addEnergyPower = (value = 0) => {
power += value;
}
this.changeCarColor = (num) => {
if (power < 1) {
return null
} else {
warehouse.createdCars[num].color = 'blue'
}
}
}
module.exports = CarFactory;
But Im getting error Cannot set properties of undefined(setting 'color').
If I hardcode 0 like this to: createdCars[0] it actually works for car indexed 0.
this is warehouse file
let warehouse = {
createdCars: [],
nextIdentifier: 0
};
module.exports = warehouse;
this is where jest tries to change color
for (let i = 0; i < myFactory.warehouse.createdCars.length; i += 2) {
let car = myFactory.warehouse.createdCars[i];
if (myFactory.changeCarColor(car) !== null) {} else {
if (energyBoosts.length > 0) {
myFactory.addEnergyPower(energyBoosts.shift());
i -= 2;
} else {
break
}
}
}
From what I can tell in the line if (myFactory.changeCarColor(car) !== null) {} else{ car would be { "id": warehouse.nextIdentifier, "color": color, "wheels": wheels, "engine": engine } but what it seems like you would want is the id. So change if (myFactory.changeCarColor(car) !== null) {} else{ to if (myFactory.changeCarColor(car.id) !== null) {} else{ and see if that works.
You have this.changeCarColor = (num) but appears you want to pass a car to that and then get the id? I have no idea what this is so I then fails here:
console.log(typeof energyBoosts); with "undefined" for energyBoosts
But that is the NEXT question not the one at hand.
let warehouse = {
createdCars: [],
nextIdentifier: 0
};
function CarFactory(power = 10) {
this.warehouse = warehouse;
this.produceCar = (color = "red", wheels = 4, engine = false) => {
// console.log("here");
if (power < 2) {
return null;
} else {
let car = {
"id": warehouse.nextIdentifier,
"color": color,
"wheels": wheels,
"engine": engine
};
warehouse.createdCars.push(car);
warehouse.nextIdentifier++;
}
}
this.addEnergyPower = (value = 0) => {
power += value;
}
this.changeCarColor = (car) => {
console.log(car.color, car.id, power);
if (power < 1) {
return null;
} else {
warehouse.createdCars[car.id].color = 'blue';
}
}
}
let myFactory = new CarFactory();
//console.log(myFactory);
for (let c = 0; c < 10; c++) {
//console.log(c);
myFactory.produceCar("red", 4, false);
}
//console.log("GO!", myFactory.warehouse);
for (let i = 1; i < myFactory.warehouse.createdCars.length; i += 2) {
//console.log(i);
let car = myFactory.warehouse.createdCars[i];
console.log("Car:", car);
if (myFactory.changeCarColor(car) == null) {
console.log(typeof energyBoosts);
if (energyBoosts.length > 0) {
myFactory.addEnergyPower(energyBoosts.shift());
i -= 2;
} else {
break;
}
}
}
I’m beginner in JavaScript and I’m trying to make a quiz that calculates the score of object(type) in the array. So the total score should count how much the user get in each part(ex:2/2 in math, 1/2 in science. Total= 3/4).
Is there any possible way to do that using jquery ?
help me please, thank you
var all_questions = [{
type:"math",
question_string: "4 + 4",
choices: {
correct: "8",
wrong: ["2", "3", "9"]
}
}, {
type:"math",
question_string: "4 * 4",
choices: {
correct: "16",
wrong: ["24", "13", "4"]
}
}, {
type:"sience",
question_string: "What part of the body helps you move?",
choices: {
correct: "Muscles",
wrong: ["Eyes", "Pancreas", "Lungs"]
}
}, {
type:"sience",
question_string: 'What star shines in the day and provides light?',
choices: {
correct: "Sun",
wrong: ["Moon", "Venus", "Mars"]
}
}];
var Quiz = function(quiz_name) {
this.quiz_name = quiz_name;
this.questions = [];
}
Quiz.prototype.add_question = function(question) {
var index_to_add_question = Math.floor(Math.random() * this.questions.length);
this.questions.splice(index_to_add_question, 0, question);
}
Quiz.prototype.render = function(container) {
var self = this;
$('#quiz-results').hide();
$('#quiz-name').text(this.quiz_name);
var question_container = $('<div>').attr('id', 'question').insertAfter('#quiz-name');
function change_question() {
self.questions[current_question_index].render(question_container);
$('#prev-question-button').prop('disabled', current_question_index === 0);
$('#next-question-button').prop('disabled', current_question_index === self.questions.length - 1);
var all_questions_answered = true;
for (var i = 0; i < self.questions.length; i++) {
if (self.questions[i].user_choice_index === null) {
all_questions_answered = false;
break;
}
}
$('#submit-button').prop('disabled', !all_questions_answered);
}
var current_question_index = 0;
change_question();
$('#prev-question-button').click(function() {
if (current_question_index > 0) {
current_question_index--;
change_question();
}
});
$('#next-question-button').click(function() {
if (current_question_index < self.questions.length - 1) {
current_question_index++;
change_question();
}
});
$('#submit-button').click(function() {
var score = 0;
for (var i = 0; i < self.questions.length; i++) {
if (self.questions[i].user_choice_index === self.questions[i].correct_choice_index) {
score++;
}
}
var percentage = score / self.questions.length;
console.log(percentage);
var message;
if (percentage === 1) {
message = 'Great job!'
} else if (percentage >= .75) {
message = 'You did alright.'
} else if (percentage >= .5) {
message = 'Better luck next time.'
} else {
message = 'Maybe you should try a little harder.'
}
$('#quiz-results-message').text(message);
$('#quiz-results-score').html('You got <b>' + score + '/' + self.questions.length + '</b> questions correct.');
$('#quiz-results').slideDown();
$('#quiz button').slideUp();
});
question_container.bind('user-select-change', function() {
var all_questions_answered = true;
for (var i = 0; i < self.questions.length; i++) {
if (self.questions[i].user_choice_index === null) {
all_questions_answered = false;
break;
}
}
$('#submit-button').prop('disabled', !all_questions_answered);
});
}
var Question = function(question_string, correct_choice, wrong_choices) {
// Private fields for an instance of a Question object.
this.question_string = question_string;
this.choices = [];
this.user_choice_index = null; // Index of the user's choice selection
// Random assign the correct choice an index
this.correct_choice_index = Math.floor(Math.random() * wrong_choices.length + 1);
// Fill in this.choices with the choices
var number_of_choices = wrong_choices.length + 1;
for (var i = 0; i < number_of_choices; i++) {
if (i === this.correct_choice_index) {
this.choices[i] = correct_choice;
} else {
// Randomly pick a wrong choice to put in this index
var wrong_choice_index = Math.floor(Math.random(0, wrong_choices.length));
this.choices[i] = wrong_choices[wrong_choice_index];
// Remove the wrong choice from the wrong choice array so that we don't pick it again
wrong_choices.splice(wrong_choice_index, 1);
}
}
}
Question.prototype.render = function(container) {
var self = this;
var question_string_h2;
if (container.children('h2').length === 0) {
question_string_h2 = $('<h2>').appendTo(container);
} else {
question_string_h2 = container.children('h2').first();
}
question_string_h2.text(this.question_string);
if (container.children('input[type=radio]').length > 0) {
container.children('input[type=radio]').each(function() {
var radio_button_id = $(this).attr('id');
$(this).remove();
container.children('label[for=' + radio_button_id + ']').remove();
});
}
for (var i = 0; i < this.choices.length; i++) {
var choice_radio_button = $('<input>')
.attr('id', 'choices-' + i)
.attr('type', 'radio')
.attr('name', 'choices')
.attr('value', 'choices-' + i)
.attr('checked', i === this.user_choice_index)
.appendTo(container);
var choice_label = $('<label>')
.text(this.choices[i])
.attr('for', 'choices-' + i)
.appendTo(container);
}
$('input[name=choices]').change(function(index) {
var selected_radio_button_value = $('input[name=choices]:checked').val();
self.user_choice_index = parseInt(selected_radio_button_value.substr(selected_radio_button_value.length - 1, 1));
container.trigger('user-select-change');
});
}
$(document).ready(function() {
var quiz = new Quiz('');
for (var i = 0; i < all_questions.length; i++) {
var question = new Question(all_questions[i].question_string, all_questions[i].choices.correct, all_questions[i].choices.wrong);
quiz.add_question(question);
}
var quiz_container = $('#quiz');
quiz.render(quiz_container);
});
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>CodePen - Multiple Choice Quiz</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- partial:index.partial.html -->
<div id="quiz">
<h1 id="quiz-name"></h1>
<button id="submit-button">Submit</button>
<button id="next-question-button">Next</button>
<button id="prev-question-button">Back</button>
<div id="quiz-results">
<p id="quiz-results-message"></p>
<p id="quiz-results-score"></p>
</div>
</div>
<!-- partial -->
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script><script src="./script.js"></script>
</body>
</html>
Basically you're looking for a group by logic - you want to group the answers by the question type. In order to solve this:
Add question_type to Question (not mandatory, we can take it from the original array of question. I'll keep it for readability).
In order to implement the group by logic, we can reduce to filter the right answers and convert the Questions array into a score dictionary. The keys are the questions type, the value is the score.
For every right answer, we either adding plus one if the category already exists or initiating as 1 if not.
I'm using a shorter version yet does exactly the same:
acc.set(curr.question_type, (acc.get(curr.question_type) || 0) + 1);
// |-- add / update --| |- current score if exists -| 0 if not, plus one
Here is the full reduce
// global counter for total answers
let totalScore = 0;
const result = a.reduce((acc, curr) => {
// if it's the right answer
if (curr.user_choice_index === curr.correct_choice_index) {
// add / update the entity with 1 if's the first right answer in the category so far or add 1 if it exists
acc.set(curr.question_type, (acc.get(curr.question_type) || 0) + 1);
totalScore++;
}
return acc;
}, new Map());
The second part is to render the results:
// convert the Map back to array
const scoreText = Array.from(score.entries())
// render each type in a different line
.map(([type, scoreByType]) => `<b>${type}</b>: ${scoreByType}`)
.join('<br />');
Read more about
Map
Map.entries
Array.from
Array.reduce
Full working example:
var all_questions = [{
type:"math",
question_string: "4 + 4",
choices: {
correct: "8",
wrong: ["2", "3", "9"]
}
}, {
type:"math",
question_string: "4 * 4",
choices: {
correct: "16",
wrong: ["24", "13", "4"]
}
}, {
type:"sience",
question_string: "What part of the body helps you move?",
choices: {
correct: "Muscles",
wrong: ["Eyes", "Pancreas", "Lungs"]
}
}, {
type:"sience",
question_string: 'What star shines in the day and provides light?',
choices: {
correct: "Sun",
wrong: ["Moon", "Venus", "Mars"]
}
}];
var Quiz = function(quiz_name) {
this.quiz_name = quiz_name;
this.questions = [];
}
Quiz.prototype.add_question = function(question) {
var index_to_add_question = Math.floor(Math.random() * this.questions.length);
this.questions.splice(index_to_add_question, 0, question);
}
Quiz.prototype.render = function(container) {
var self = this;
$('#quiz-results').hide();
$('#quiz-name').text(this.quiz_name);
var question_container = $('<div>').attr('id', 'question').insertAfter('#quiz-name');
function change_question() {
self.questions[current_question_index].render(question_container);
$('#prev-question-button').prop('disabled', current_question_index === 0);
$('#next-question-button').prop('disabled', current_question_index === self.questions.length - 1);
var all_questions_answered = true;
for (var i = 0; i < self.questions.length; i++) {
if (self.questions[i].user_choice_index === null) {
all_questions_answered = false;
break;
}
}
$('#submit-button').prop('disabled', !all_questions_answered);
}
var current_question_index = 0;
change_question();
$('#prev-question-button').click(function() {
if (current_question_index > 0) {
current_question_index--;
change_question();
}
});
$('#next-question-button').click(function() {
if (current_question_index < self.questions.length - 1) {
current_question_index++;
change_question();
}
});
$('#submit-button').click(function() {
let totalScore = 0;
const score = self.questions.reduce((acc, curr) => {
if (curr.user_choice_index === curr.correct_choice_index) {
acc.set(curr.question_type, (acc.get(curr.question_type) || 0) + 1);
totalScore++;
}
return acc;
}, new Map());
var percentage = score / self.questions.length;
console.log(percentage);
var message;
if (percentage === 1) {
message = 'Great job!'
} else if (percentage >= .75) {
message = 'You did alright.'
} else if (percentage >= .5) {
message = 'Better luck next time.'
} else {
message = 'Maybe you should try a little harder.'
}
$('#quiz-results-message').text(message);
const scoreText = Array.from(score.entries())
.map(([type, scoreByType]) => `<b>${type}</b>: ${scoreByType}`)
.join('\n');
$('#quiz-results-score').html('You got <b>' + totalScore + '/' + self.questions.length + '</b> questions correct.\n' + scoreText);
$('#quiz-results').slideDown();
$('#quiz button').slideUp();
});
question_container.bind('user-select-change', function() {
var all_questions_answered = true;
for (var i = 0; i < self.questions.length; i++) {
if (self.questions[i].user_choice_index === null) {
all_questions_answered = false;
break;
}
}
$('#submit-button').prop('disabled', !all_questions_answered);
});
}
var Question = function(question_string, correct_choice, wrong_choices, question_type) {
// Private fields for an instance of a Question object.
this.question_string = question_string;
this.question_type = question_type;
this.choices = [];
this.user_choice_index = null; // Index of the user's choice selection
// Random assign the correct choice an index
this.correct_choice_index = Math.floor(Math.random() * wrong_choices.length + 1);
// Fill in this.choices with the choices
var number_of_choices = wrong_choices.length + 1;
for (var i = 0; i < number_of_choices; i++) {
if (i === this.correct_choice_index) {
this.choices[i] = correct_choice;
} else {
// Randomly pick a wrong choice to put in this index
var wrong_choice_index = Math.floor(Math.random(0, wrong_choices.length));
this.choices[i] = wrong_choices[wrong_choice_index];
// Remove the wrong choice from the wrong choice array so that we don't pick it again
wrong_choices.splice(wrong_choice_index, 1);
}
}
}
Question.prototype.render = function(container) {
var self = this;
var question_string_h2;
if (container.children('h2').length === 0) {
question_string_h2 = $('<h2>').appendTo(container);
} else {
question_string_h2 = container.children('h2').first();
}
question_string_h2.text(this.question_string);
if (container.children('input[type=radio]').length > 0) {
container.children('input[type=radio]').each(function() {
var radio_button_id = $(this).attr('id');
$(this).remove();
container.children('label[for=' + radio_button_id + ']').remove();
});
}
for (var i = 0; i < this.choices.length; i++) {
var choice_radio_button = $('<input>')
.attr('id', 'choices-' + i)
.attr('type', 'radio')
.attr('name', 'choices')
.attr('value', 'choices-' + i)
.attr('checked', i === this.user_choice_index)
.appendTo(container);
var choice_label = $('<label>')
.text(this.choices[i])
.attr('for', 'choices-' + i)
.appendTo(container);
}
$('input[name=choices]').change(function(index) {
var selected_radio_button_value = $('input[name=choices]:checked').val();
self.user_choice_index = parseInt(selected_radio_button_value.substr(selected_radio_button_value.length - 1, 1));
container.trigger('user-select-change');
});
}
$(document).ready(function() {
var quiz = new Quiz('');
for (var i = 0; i < all_questions.length; i++) {
var question = new Question(all_questions[i].question_string, all_questions[i].choices.correct, all_questions[i].choices.wrong, all_questions[i].type);
quiz.add_question(question);
}
var quiz_container = $('#quiz');
quiz.render(quiz_container);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CodePen - Multiple Choice Quiz</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- partial:index.partial.html -->
<div id="quiz">
<h1 id="quiz-name"></h1>
<button id="submit-button">Submit</button>
<button id="next-question-button">Next</button>
<button id="prev-question-button">Back</button>
<div id="quiz-results">
<p id="quiz-results-message"></p>
<p id="quiz-results-score"></p>
</div>
</div>
<!-- partial -->
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src="./script.js"></script>
</body>
</html>
I've encountered an error - "Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'" on line 113. As far as I understand (I'm a beginner), the problem is that the variable "shoppingListItem" isn't a Node, but a String. How can I fix this?
var shoppingList = {
list: [{
item: 'milk',
isBought: false,
itemCounter: 1
}, {
item: 'beer',
isBought: false,
itemCounter: 1
}, {
item: 'sugar',
isBought: false,
itemCounter: 1
}],
displayShoppingList: function() {
//debugger;
if (this.list.length > 0) {
for (var x = 0; x < this.list.length; x++) {
if (this.list[x].isBought === true) {
console.log('(x)' + this.list[x].item);
} else {
console.log('( )' + this.list[x].item);
}
}
} else {
console.log('Your shopping list is empty');
}
},
addToShoppingList: function(item) {
this.list.push({
item: item,
isBought: false,
itemCounter: 1
});
this.displayShoppingList();
},
changeShoppingList: function(place, newItem) {
this.list[place].item = newItem;
this.displayShoppingList();
},
changeCounter: function(place, newCounter) {
this.list[place].itemCounter = newCounter;
this.displayShoppingList();
},
makeItemBought: function(place) {
this.list[place].isBought = !this.list[place].isBought;
this.displayShoppingList();
},
deleteFromShoppingList: function(place) {
this.list.splice(place, 1);
this.displayShoppingList();
},
toggleAllItems: function() {
var allItems = this.list.length;
var boughtItems = 0;
for (var y = 0; y < allItems; y++) {
if (this.list[y].isBought === true) {
boughtItems++;
}
}
if (boughtItems === allItems) {
for (var z = 0; z < allItems; z++) {
this.list[z].isBought = false;
}
} else {
for (var a = 0; a < this.list.length; a++) {
this.list[a].isBought = true;
}
}
this.displayShoppingList();
}
};
var handlers = {
showAll: function() {
shoppingList.displayShoppingList();
},
toggleAll: function() {
shoppingList.toggleAllItems();
showOnScreen.displayShoppingList();
},
addToShoppingList: function() {
var addToShoppingListInput = document.getElementById('addToShoppingListText');
shoppingList.addToShoppingList(addToShoppingListInput.value);
addToShoppingListInput.value = "";
showOnScreen.displayShoppingList();
},
changeShoppingList: function() {
var changeShoppingListInputNumber = document.getElementById('changeShoppingListNumber');
var changeShoppingListInputText = document.getElementById('changeShoppingListText');
shoppingList.changeShoppingList(changeShoppingListInputNumber.valueAsNumber, changeShoppingListInputText.value);
changeShoppingListInputNumber.value = "";
changeShoppingListInputText.value = "";
showOnScreen.displayShoppingList();
},
};
var showOnScreen = {
displayShoppingList: function() {
var shoppingUnorderedList = document.querySelector('ul');
shoppingUnorderedList.innerHTML = '';
for (var x = 0; x < shoppingList.list.length; x++) {
var shoppingListItem = document.createElement('li');
var isBoughtDisplay = '';
if (shoppingList.list[x].isBought === true) {
isBoughtDisplay = '(x)' + shoppingList.list[x].item + ' ' + shoppingList.list[x].itemCounter;
} else {
isBoughtDisplay = '( )' + shoppingList.list[x].item + ' ' + shoppingList.list[x].itemCounter;
}
shoppingListItem.textContent = isBoughtDisplay;
shoppingListItem.appendChild(this.createDeleteButton); // error is here
shoppingUnorderedList.appendChild(shoppingListItem);
}
},
createDeleteButton: function() {
var deleteButton = document.createElement('button');
deleteButton.textContent = 'Delete item';
deleteButton.className = 'deleteButtonClass';
return deleteButton;
}
};
//shoppingList.addToShoppingList('muffin');
//shoppingList.toggleAllItems();
//add multiple items at the same time - divide them by “,” and push one by one(?)
//counter on each item - add ‘counter’ property to item/isBought, increase by one (tap) or manually by counter (how? - figure out!)
//swipe movements and mobile devices adaptation (read docs)
<!DOCTYPE html>
<html>
<body>
<h1>Список покупок</h1>
<button onclick='showOnScreen.displayShoppingList()'>Show Shopping List</button>
<button onclick='handlers.toggleAll()'>Toggle all on/off</button>
<div>
<input type='text' id='addToShoppingListText'>
<button onclick='handlers.addToShoppingList()'>Add to shopping list</button>
</div>
<div>
<input type='number' id='changeShoppingListNumber'>
<input type='text' id='changeShoppingListText'>
<button onclick='handlers.changeShoppingList()'>Change Shopping List Item</button>
</div>
<div>
<input type='number' id='changeCounterPlace'>
<input type='number' id='changeCounterValue'>
<button onclick='handlers.changeCounter()'>Change number of items</button>
</div>
<ul>
</ul>
<script src="script.js"></script>
</body>
</html>
The "createDeleteButton" is a function but you are not call it. Just change to :
shoppingListItem.appendChild(this.createDeleteButton());
And it should work