Having a mare with this one...
I have a function, which displays pagination ( 1, 2, 3 etc) buttons, for each page of my todo app results.
Specifically for example, if you click on button 2, you'll see page 2 of the results. Here's the full function and the buttons are being inserted via template literals:
// CREATE BUTTONS FOR EACH PAGE THAT EXISTS
function displayNumberedButtons(bookMarksArray) {
for (let x = 0; x < bookMarksArray.length; x++)
listArray.push(x);
numberOfPages = Math.ceil(listArray.length / numberPerPage);
let individualPagesArray = [];
for (var i = 1; i <= numberOfPages; i++) {
individualPagesArray.push(i);
}
// BUTTONS ARE ADDED HERE
for (var i = 0; i < individualPagesArray.length; i++) {
document.getElementById("numbers").innerHTML += `<button onclick=showCurrentPage(${i+1})>` + individualPagesArray[i] + `</button>`;
}
}
However, my onclick function, does not seem to register in my JavaScript:
// PAGINGATION CTAS
window.showCurrentPage = (i) => {
currentPage = i;
paginationCountLogic(bookMarksArray);
}
If I click on any button, I get the following error. And I have no idea why, as I can see the buttons in my DOM.
index.html:1 Uncaught ReferenceError: showCurrentPage is not defined
at HTMLButtonElement.onclick (index.html:1)
This only happens when I compiled my JS files in advanced mode, using google closure compiler. Otherwise, this works fine if the files are not compiled.
Not sure how to resolve this.
Here is the full order the code appears as in my script:
function Pagination() {
let listArray = new Array(); //store the collection of data to be sorted.
let pageList = new Array(); //keep track of the items to display on the current page only
const numberPerPage = 3;
let currentPage = 1; //keep track of where we are in the pagination
let numberOfPages = 1; // calculates the total number of pages
const list = document.querySelector('.url-list');
let nextButton = document.getElementById("next");
const previousButton = document.getElementById("previous");
let bookMarksArray = window.localStorage.getItem('bookMarksArray') ? JSON.parse(window.localStorage.getItem('bookMarksArray')) : [];
// CREATE BUTTONS FOR EACH PAGE THAT EXISTS
function displayNumberedButtons(bookMarksArray) {
for (let x = 0; x < bookMarksArray.length; x++)
listArray.push(x);
numberOfPages = Math.ceil(listArray.length / numberPerPage);
let individualPagesArray = [];
for (var i = 1; i <= numberOfPages; i++) {
individualPagesArray.push(i);
}
for (var i = 0; i < individualPagesArray.length; i++) {
document.getElementById("numbers").innerHTML += `<button id="${i+1}" onclick=showCurrentPage(${i+1})>` + individualPagesArray[i] + `</button>`;
}
}
// CALCULATE WHEN PAGINATION SHOULD BEGIN AND STOP
function paginationCountLogic(bookMarksArray) {
let begin = ((currentPage - 1) * numberPerPage);
let end = begin + numberPerPage;
pageList = bookMarksArray.slice(begin, end);
nextButton.disabled = currentPage === numberOfPages ? true : false;
previousButton.disabled = currentPage === 1 ? true : false;
displayBookmarks(pageList);
}
// DISPLAY BOOKMARKS
function displayBookmarks(pageList) {
list.innerHTML = "";
for (let r = 0; r < pageList.length; r++) {
list.innerHTML +=
`<div>
<form class="text animated slideInDown bookmarksForm" id=${pageList[r].name}>
<input class="nameItem" type="text" name="name" value=${pageList[r].name} id="name" placeholder="Name">
<input class="urlItem" type="url" name="url" value=${pageList[r].url} id="url" placeholder="https://example.com">
<button type="button" class="js-edit-url" id="edit">edit</button>
<button type="button" class="js-delete-url" id="delete">delete</button>
</form>
</div>`;
}
}
// PAGINGATION CTAS
window.showCurrentPage = (i) => {
currentPage = i;
paginationCountLogic(bookMarksArray);
}
window.nextPage = () => {
currentPage += 1;
paginationCountLogic(bookMarksArray);
}
window.previousPage = () => {
currentPage -= 1;
paginationCountLogic(bookMarksArray);
}
return {
displayNumberedButtons,
displayBookmarks,
paginationCountLogic
};
}
The cause is probably that the compiler doesn't see the function being called. Part of the advanced compilation is removing unused code and renaming the methods/variables.
Within your js or html it is never called because the function call is only defined in a string value here :
for (var i = 0; i < individualPagesArray.length; i++) {
document.getElementById("numbers").innerHTML += `<button onclick=showCurrentPage(${i+1})>` + individualPagesArray[i] + `</button>`;
}
you can solve this pretty simply by rewriting this:
window.showCurrentPage = (i) => {
to this:
window['showCurrentPage'] = (i) => {
See : https://developers.google.com/closure/compiler/docs/api-tutorial3#removal
Related
The code gets the values of the input and sends it to the textarea, but when you add more than one title the values are repeated in the result of the titles, for example, the DESCRIPTIONS of title 1 are the same as in title 2, why does this happen? and how to make it work without changing the purpose?
Run the code in codepen.io or jsfiddle.net
This is what happens:
This is what should happen:
function result() {
var inp2 = document.getElementsByName("inp2");
var titu = document.getElementsByName("titu");
var res = document.getElementById("result");
res.value = "";
if (titu[0]) {
for (var k = 0; k < titu.length; k++) {
if (titu[k].value.trim() != '') {
res.value += `<div>
<span>${titu[k].value.trim()}</span>
</div>
<ul>\n`;
for (var j = 0; j < inp2.length; j++) {
if (inp2[j].value.trim() != '') {
res.value += `<li>${inp2[j].value.trim()}</li>\n`;
}
}
}
}
}else {
console.log("test")
res.value += `<ul>\n`;
for (var l = 0; l < inp2.length; l++) {
if (inp2[l].value.trim() != '') {
res.value += `<li>${inp2[l].value.trim()}</li>\n`;
}
}
}
};
// -----------------------------------------
if (document.getElementById("add2")) {
let cont2 = 1;
document.getElementById("add2").onclick = function clone2() {
let container2 = document.getElementById("output2");
let tempLinha2 = document.querySelector('#template2');
let clone2 = document.importNode(tempLinha2.content, true);
const label2 = clone2.querySelector("label");
label2.htmlFor = cont2;
clone2.querySelector("input").className = cont2;
container2.appendChild(clone2);
cont2++;
};
document.getElementById("del2").onclick = function del2() {
document.querySelector('#output2 #linha2:last-child').remove();
};
}
// ---------------------------------------
if (document.getElementById("addtit")) {
let cont3 = 1;
document.getElementById("addtit").onclick = function clone3() {
let container3 = document.getElementById("output2");
let tempLinha3 = document.querySelector('#template3');
let clone3 = document.importNode(tempLinha3.content, true);
const label3 = clone3.querySelector("label");
label3.htmlFor = cont3;
clone3.querySelector("input").className = cont3;
container3.appendChild(clone3);
cont3++;
document.getElementById('add2').id = 'add3';
document.getElementById('del2').id = 'del3';
};
document.getElementById("deltit").onclick = function deltit() {
document.querySelector('#output2 #alg:last-child').remove();
document.getElementById('add3').id = 'add2';
document.getElementById('del3').id = 'del2';
};
}
// -----------------------------------------
if (document.getElementById("add3")) {
let cont4 = 1;
document.getElementById("add3").onclick = function clone4() {
let container4 = document.getElementById("output3");
let tempLinha4 = document.querySelector('#template2');
let clone4 = document.importNode(tempLinha4.content, true);
const label4 = clone4.querySelector("label");
label4.htmlFor = cont4;
clone4.querySelector("input").className = cont4;
container4.appendChild(clone4);
cont4++;
};
document.getElementById("del3").onclick = function del4() {
document.querySelector('#output3 #linha2:last-child').remove();
};
}
<div class="container">
<button id="addtit">+ TITLE</button>
<button id="deltit">- TITLE</button>
<button id="add2">+ DESCRIPTION</button>
<button id="del2">- DESCRIPTION</button>
<div id="output2"></div>
<div class='botoes'>
<button onclick="result()" id='done'>DONE</button>
</div>
<div class="header"><span class="title">RESULT</span>
</div>
<div class="linha"><textarea id="result"></textarea>
</div>
</div>
<!-- template 2 -->
<template id="template2">
<div class="linha" id="linha2"><div class="coluna1"><label for="0">DESCRIPTION:</label></div><div class="coluna2"><input name="inp2" class="0" type="text"/></div>
</div>
</template>
<!-- template 3 -->
<template id="template3">
<div id="alg">
<div class="linha"><div class="coluna1"><label for="0">TITLE:</label></div><div class="coluna2"><input name="titu" class="0" type="text"/></div>
</div>
<div class="linha" id="linha3"><div class="coluna1"><label for="0">DESCRIPTION:</label></div><div class="coluna2"><input name="inp2" class="0" type="text"/></div>
</div>
<div id="output3"></div>
</div>
</template>
Ok. it's because this part of code in function result:
if (titu[0]) {
for (var k = 0; k < titu.length; k++) {
if (titu[k].value.trim() != '') {
res.value += `<div>
<span>${titu[k].value.trim()}</span>
</div>
<ul>\n`;
for (var j = 0; j < inp2.length; j++) {
if (inp2[j].value.trim() != '') {
res.value += `<li>${inp2[j].value.trim()}</li>\n`;
}
}
}
}
}
your titles have the same names : 'titu' , and your descriptions have same names : 'inp2', and you have two nested loops, for each title, loop on description, and it results as you see.
it's better to change your code and make different names and ids
by the way. if you persist to do not change your code, you should use one loop for both of them, like this code
if (titu[0]) {
for (var k = 0; k < titu.length; k++) {
if (titu[k].value.trim() != '') {
res.value += `<div>
<span>${titu[k].value.trim()}</span>
</div>
<ul>\n`;
if (inp2[k].value.trim() != '') {
res.value += `<li>${inp2[k].value.trim()}</li>\n`;
}
}
}
}
UPDATE
for the case of more description for each title, you have to change the code of onClick methods of Title+ and Description+, the added title and all of its description must have same parent, and after doing that, it's possible to solve the problem like this . (assuming the parent that I already have said has class name 'parent')
function result() {
var parents = document.querySelectorAll(".parent")
parents.forEach(function(parent){
var title = parent.querySelector("titu");
var descriptions = parent.querySelectorAll("inp2");
var res = document.getElementById("result");
if (title.value.trim() != '') {
res.value += `<div>
<span>${title.value.trim()}</span>
</div>
<ul>\n`;
}
descriptions.forEach(function(inp2){
if (inp2.value.trim() != '') {
res.value += `<li>${inp2.value.trim()}</li>\n`;
}
});
});
}
notice that this code could work after modifying Title+ and Description+ events and add same parent with class name parent to title and descriptions inputs
I'm trying to add the numbers of pagination using Javascript. The arrows navigation is working fine but when I try to add the numbers of pages my code doesn't work. I have 2 pages with 10 results each. When I click in the number 1 the console print the number 3. The problem is inside the function createPagination when I create the loop for the page numbers. Any help?
var arrFull = [];
var pageSize = 10;
var pages = -1;
var actualPage = 0;
function changePagination(pagination) {
if(Number(pagination) !== actualPage && pagination > 0 && pagination <= pages) {
var start = ((pagination - 1) * pageSize) + 1;
if(pagination === 1) {
ini = 0;
}
var end = pagination * pageSize;
if(end > arrFull.length) {
end = arrFull.length;
}
var arr = arrFull.slice(start,end);
for(var i = 0; i < arr.length; i++) {
createObject(arr[i]);
}
actualPage = Number(pagination);
createPagination();
}
}
function createPagination() {
var paginator = document.getElementById('pagination');
paginator.innerHTML = "";
var arrowLeft = document.createElement('a');
arrowLeft.setAttribute('href', '');
var arrowRight = document.createElement('a');
arrowRight.setAttribute('href', '');
arrowLeft.innerHTML = '<span class="arrow"></span>';
arrowLeft.addEventListener('click', function(event) {
event.preventDefault();
changePagination(actualPage - 1);
});
arrowRight.innerHTML = '<span class="arrow"></span>';
arrowRight.addEventListener('click', function(event) {
event.preventDefault();
changePagination(actualPage + 1);
});
paginator.appendChild(arrowLeft);
for(var pagination = 1; pagination <= pages; pagination++) {
var number = document.createElement('a');
number.setAttribute('href', '');
number.innerHTML = pagination;
number.addEventListener('click', function(event) {
event.preventDefault();
changePagination(pagination);
console.log(pagination);
});
paginator.appendChild(number);
}
paginator.appendChild(arrowRight);
}
When you pass on your pagination variable it passes the last value set to it in that context (the 3 because of its last iteration in the loop).
You should declare a variable inside the click event and assign to it the value of pagination and then pass your local variable to your method:
number.addEventListener('click', function(event)
{
let currentPage = pagination;
event.preventDefault();
changePagination(currentPage);
console.log(currentPage);
});
That should do the trick.
Edit
This is the actual solution:
number.setAttribute("page", pagination);
number.addEventListener('click', function(event) {
let currentPage = +event.target.getAttribute("page");
event.preventDefault();
changePagination(currentPage);
console.log(currentPage);
});
The reason why the number 3 is being returned is because the let currentPage = pagination; line is being executed when the event triggers; by that time the value of the variable pagination is equal to 3, so you need to save its value through every iteration (it can be saving it inside a property within your element outside of the event scope like so: number._pageNumber = pagination;; or as the given example: number.setAttribute("page", pagination);).
Full implementation
<html>
<body>
<!--Element to simulate the pagination-->
<div id="pagination"></div>
<script>
var arrFull = [];
var pageSize = 10;
var pages = 2; // Change to simulate your case (changed the '-1' to '2')
var actualPage = 0;
function changePagination(pagination) {
if(Number(pagination) !== actualPage && pagination > 0 && pagination <= pages) {
var start = ((pagination - 1) * pageSize) + 1;
if(pagination === 1) {
ini = 0;
}
var end = pagination * pageSize;
if(end > arrFull.length) {
end = arrFull.length;
}
var arr = arrFull.slice(start,end);
for(var i = 0; i < arr.length; i++) {
createObject(arr[i]);
}
actualPage = Number(pagination);
createPagination();
}
}
function createPagination() {
var paginator = document.getElementById('pagination');
paginator.innerHTML = "";
var arrowLeft = document.createElement('a');
arrowLeft.setAttribute('href', '');
var arrowRight = document.createElement('a');
arrowRight.setAttribute('href', '');
arrowLeft.innerHTML = '<span class="arrow"></span>';
arrowLeft.addEventListener('click', function(event) {
event.preventDefault();
changePagination(actualPage - 1);
});
arrowRight.innerHTML = '<span class="arrow"></span>';
arrowRight.addEventListener('click', function(event) {
event.preventDefault();
changePagination(actualPage + 1);
});
paginator.appendChild(arrowLeft);
for(var pagination = 1; pagination <= pages; pagination++) {
var number = document.createElement('a');
number.setAttribute('href', '');
number.innerHTML = pagination;
// <Here_is_the_sugested_code> //
number.setAttribute("page", pagination);
number.addEventListener('click', function(event) {
let currentPage = +event.target.getAttribute("page");
event.preventDefault();
changePagination(currentPage);
console.log(currentPage);
});
// </Here_is_the_sugested_code> //
paginator.appendChild(number);
}
paginator.appendChild(arrowRight);
}
createPagination(); // Call to the function to simulate the generation
</script>
</body>
</html>
I need to return a total IR for each table cell. This is not working And I am not sure why. How
$scope.getTotalb = function () {
var totalb = 0;
for (var i = 0; i < $scope.items.length; i++) {
if (120 > $scope.items[i].product && $scope.items[i].product> 90) {
var product = $scope.items[i].IR;
totalb += ($scope.items[i].IR);
}
return totalb;
}
}
$scope.getTotalc = function () {
var totalc = 0;
for (var i = 0; i < $scope.items.length; i++) {
if (90 > $scope.items[i].product&& $scope.items[i].product> 60) {
var product = $scope.items[i].IR;
totalc += ($scope.items[i].IR);
}
return totalc;
}
}
For Each table data cell, call the function to get total.
<td><b>Total:</b></td>
<td><b>{{Totala()}}</b></td>
<td><b></b>{{Totalb()}}</td>
There are multiple errors in your code.
First, you should put the return statement at the end of your function instead of within your for loop.
Second, the names of the functions are different in your template. In your controller you use getTotalb but in the template you use Totalb.
You should put your return statement outside of for loop
remove the "return ...." from your 2 "for" loops and make your totals available through the scope.
$scope.getTotalb = function () {
var totalb = 0;
for (var i = 0; i < $scope.items.length; i++) {
if (120 > $scope.items[i].product && $scope.items[i].product> 90) {
var product = $scope.items[i].IR;
totalb += ($scope.items[i].IR);
}
}
$scope.totalb=totalb ;
}
$scope.getTotalc = function () {
var totalc = 0;
for (var i = 0; i < $scope.items.length; i++) {
if (90 > $scope.items[i].product&& $scope.items[i].product> 60) {
var product = $scope.items[i].IR;
totalc += ($scope.items[i].IR);
}
}
$scope.totalc=totalc ;
}
I have the following applied as a library to a CRM 2013 form
function calcServicePriceTotal() {
alert("Start");//----------HERE
if (document.getElementById("Services")) {
alert("InsideIf"); //----------HERE
var grid = document.getElementById("Services").control;
alert("ThisFar?");//----------HERE
var ids = grid.Control.get_allRecordIds()
alert("ThisFar2?");//----------HERE
for (i = 0; i < ids.length; i++) {
alert("InsideFor");//----------HERE
var cellValue = grid.control.getCellValue('iss_salesprice', ids[i]);
var number = Number(cellValue.replace(/[^0-9\.]+/g, ""));
sum = sum + number;
}
Xrm.Page.data.entity.attributes.get("ava_tempgrossvalue").setValue(sum);
alert("Done");//----------HERE
}
else {
alert("Else");//----------HERE
setTimeout("calcServicePriceTotal();", 2500);
}
}
For some reason I get as far as the alert("ThisFar?") line but then nothing else happens.
Does that mean that there is a problem with var ids = grid.Control.get_allRecordIds()? I don't know why I'm not at least seeing "ThisFar2".
Can anyone see anything obvious?
function calcServicePriceTotal() {
if (document.getElementById("Services")) {
var grid = document.getElementById("Services").control;
var ids = grid.get_allRecordIds()
var sum = 0
for (i = 0; i < ids.length; i++) {
var cellValue = grid.getCellValue('iss_salesprice', ids[i]);
var number = Number(cellValue.replace(/\D/g, ''));
number = number/100;
sum = sum + number;
}
Xrm.Page.data.entity.attributes.get("iss_value").setValue(sum);
}
else {
setTimeout("calcServicePriceTotal();", 1500);
}
}
Final working solution
I'm fairly new to JavaScript and trying to build a simple photoviewer, slideshow application. I probably have errors/wrong practices in code that I don't know about yet. The event on slideshow button fires and I can see the output in the console, however the event on the random slide show button does not fire.
HTML5 snippet
<form>
<div id="controls">
<input type="button" id="slideshow" value="Slide Show" />
<input type="button" id="randomSlideshow" value="Random Slide Show" />
</div>
</form>
<script src="js/PhotoViewer.js"></script>
</body>
JS snippet
var photosArrayGlobal = new Array();
var photoIndexGlobal = 0;
var displayGlobal;
window.onload = main;
function main() {
"use strict";
document.getElementById("slideshow").onclick = getArrayPhotosNames;
document.getElementById("randomSlideshow").onclick = randomize(photosArrayGlobal);
displayGlobal = document.getElementById("myImage");
document.getElementById("nextSlide").onclick = function () {
displayGlobal.setAttribute("src", photosArrayGlobal[1]); //Test value, image 2
};
}
function getArrayPhotosNames() {
var folderName = document.getElementById("photoFolder").value;
var commonName = document.getElementById("commonName").value;
var startNum = document.getElementById("startNum").value;
var endNum = document.getElementById("endNum").value;
var j = 0;
if (startNum > endNum) {
alert("Invalid Numbers");
}
var nameArray = new Array();
for (var i = startNum; i <= endNum; i++) {
nameArray[j] = folderName + commonName + i + ".jpg";
j++;
}
photosArrayGlobal = nameArray.slice();
console.log(photosArrayGlobal);
return nameArray;
}
function randomize(dataArray) {
var i = dataArray.length;
var j, tempi, tempj;
if (i === 0) {
return false;
}
while (--i) {
j = Math.floor(Math.random() * (i + 1));
tempi = dataArray[i];
tempj = dataArray[j];
dataArray[i] = tempj;
dataArray[j] = tempi;
}
console.log(dataArray);
}
The onclick handler is expecting a function, but you're passing it the value returned from the randomize() function (which happens to be undefined). Change it to the following:
document.getElementById("randomSlideshow").onclick = function() {
randomize(photosArrayGlobal);
};