Messing up the dynamic dropdown. What am I doing wrong? - javascript

I am trying to add dropdown list dynamically to a WebApp using google appscript. I wrote a few lines of javascript code in the client side to communicate the server side to fetch the data from google-sheets. After a lot of trying, I'm somewhat successful. However, it looks like, whenever I click on the "Add Product" button, for first 1-2 times the array from which the dropdown is generated is empty. As a result the dropdown remains blank. However after 1 or 2 blank dropdowns the it starts working as it's suppose to.
What am I doing wrong ?
I have 3 files-
form.html
code.gs
js_script.html
Link to the google sheet
Content of form.html-
<body>
<div class="container">
<div class = "row">
<h1>Order Form</h2>
</div> <!-- end of row -->
<div class = "row">
<input id="orderno" type="text" class="validate">
<label for="orderno">Order Number</label>
</div> <!-- end of row -->
<div class = "row">
<input id="clientname" type="text" class="validate">
<label for="clientname">Client Name</label>
</div> <!-- end of row -->
<div class = "row">
<input id="clientaddr" type="text" class="validate">
<label for="clientaddr">Client Address</label>
</div> <!-- end of row -->
<div class = "row">
<input id="clientphone" type="text" class="validate">
<label for="clientphone">Client Phone Number</label>
</div> <!-- end of row -->
<div class = "row">
<input id="ordertype" type="text" class="validate">
<label for="ordertype">Order Type</label>
</div> <!-- end of row -->
<div id="productsection"></div>
<div class = "row">
<button id="addproduct">Add Product</button>
</div> <!-- end of row -->
<div class = "row">
<button id="submitBtn">Submit</button>
</div> <!-- end of row -->
</div> <!-- End of "container" class -->
<?!= include("js_script"); ?>
</body>
Content of code.gs
const ssID = "1YKZYgKctsXU3DKTidVVPUhmPXUkzjjocaiMz1S76JAE";
const ss = SpreadsheetApp.openById(ssID);
function doGet(e){
Logger.log(e);
return HtmlService.createTemplateFromFile("form").evaluate();
}
function include(fileName){
return HtmlService.createHtmlOutputFromFile(fileName).getContent();
}
function appendDataToSheet(userData){
const ws = ss.getSheetByName("orders");
ws.appendRow([new Date(), userData.orderNumber, userData.clientName, userData.clientAddress, userData.clientPhone, userData.orderType, userData.products].flat());
}
function getOptionArray(){
const ws = ss.getSheetByName("product_list");
const optionList = ws.getRange(2, 1, ws.getRange("A2").getDataRegion().getLastRow() - 1).getValues()
.map(item => item[0]);
return optionList;
}
function logVal(data){
Logger.log(data);
}
Content of js_script.html
<script>
let counter = 0;
let optionList = [];
document.getElementById("submitBtn").addEventListener("click", writeDataToSheet);
document.getElementById("addproduct").addEventListener("click", addInputField);
function addInputField(){
counter++;
// The idea is, everytime when "add product" button is clicked, the following element must be added to the "<div id="productoption></div>" tag.
// <div class="row">
// <select id="productX">
// <option>option-X</option>
// </select>
// </div>
const newDivTag = document.createElement('div');
const newSelectTag = document.createElement('select');
newDivTag.class = "row";
newSelectTag.id = "product" + counter.toString();
google.script.run.withSuccessHandler(updateOptionList).getOptionArray();
google.script.run.logVal(optionList); // This is just to test the optionList array if it's updated or not
for(let i = 0; i < optionList.length; i++){
const newOptionTag = document.createElement('option');
newOptionTag.textContent = optionList[i];
newOptionTag.value = optionList[i];
newSelectTag.appendChild(newOptionTag);
}
newDivTag.appendChild(newSelectTag);
document.getElementById('productsection').appendChild(newDivTag);
}
function writeDataToSheet(){
const userData = {};
userData.orderNumber = document.getElementById("orderno").value;
userData.clientName = document.getElementById("clientname").value;
userData.clientAddress = document.getElementById("clientaddr").value;
userData.clientPhone = document.getElementById("clientphone").value;
userData.orderType = document.getElementById("ordertype").value;
userData.products = [];
for(let i = 0; i < counter; i++) {
let input_id = "product" + (i+1).toString();
userData.products.push(document.getElementById(input_id).value);
}
google.script.run.appendDataToSheet(userData);
}
function updateOptionList(arr){
optionList = arr.map(el => el);
}
</script>

About your current issue of However, it looks like, whenever I click on the "Add Product" button, for first 1-2 times the array form which the dropdown is generated is empty. As a result the dropdown remains blank. However after 1 or 2 blank dropdowns the it starts working as it's suppose to., when I saw your script, I thought that the reason for your issue might be due to that google.script.run is run with the asynchronous process. If my understanding is correct, how about the following modification?
In this case, your js_script.html is modified.
Modified script:
<script>
let counter = 0;
// let optionList = []; // Removed
document.getElementById("submitBtn").addEventListener("click", writeDataToSheet);
document.getElementById("addproduct").addEventListener("click", addInputField);
// Modified
function addInputField(){
counter++;
const newDivTag = document.createElement('div');
const newSelectTag = document.createElement('select');
newDivTag.class = "row";
newSelectTag.id = "product" + counter.toString();
google.script.run.withSuccessHandler(arr => {
const optionList = updateOptionList(arr);
google.script.run.logVal(optionList);
for(let i = 0; i < optionList.length; i++){
const newOptionTag = document.createElement('option');
newOptionTag.textContent = optionList[i];
newOptionTag.value = optionList[i];
newSelectTag.appendChild(newOptionTag);
}
newDivTag.appendChild(newSelectTag);
document.getElementById('productsection').appendChild(newDivTag);
}).getOptionArray();
}
function writeDataToSheet(){
const userData = {};
userData.orderNumber = document.getElementById("orderno").value;
userData.clientName = document.getElementById("clientname").value;
userData.clientAddress = document.getElementById("clientaddr").value;
userData.clientPhone = document.getElementById("clientphone").value;
userData.orderType = document.getElementById("ordertype").value;
userData.products = [];
for(let i = 0; i < counter; i++) {
let input_id = "product" + (i+1).toString();
userData.products.push(document.getElementById(input_id).value);
}
google.script.run.appendDataToSheet(userData);
}
// Modified
function updateOptionList(arr){
return arr.map(el => el); // I cannot understand this mean.
}
</script>
or, in this case, updateOptionList might not be required to be used as follows.
<script>
let counter = 0;
// let optionList = []; // Removed
document.getElementById("submitBtn").addEventListener("click", writeDataToSheet);
document.getElementById("addproduct").addEventListener("click", addInputField);
// Modified
function addInputField(){
counter++;
const newDivTag = document.createElement('div');
const newSelectTag = document.createElement('select');
newDivTag.class = "row";
newSelectTag.id = "product" + counter.toString();
google.script.run.withSuccessHandler(optionList => {
google.script.run.logVal(optionList);
for(let i = 0; i < optionList.length; i++){
const newOptionTag = document.createElement('option');
newOptionTag.textContent = optionList[i];
newOptionTag.value = optionList[i];
newSelectTag.appendChild(newOptionTag);
}
newDivTag.appendChild(newSelectTag);
document.getElementById('productsection').appendChild(newDivTag);
}).getOptionArray();
}
function writeDataToSheet(){
const userData = {};
userData.orderNumber = document.getElementById("orderno").value;
userData.clientName = document.getElementById("clientname").value;
userData.clientAddress = document.getElementById("clientaddr").value;
userData.clientPhone = document.getElementById("clientphone").value;
userData.orderType = document.getElementById("ordertype").value;
userData.products = [];
for(let i = 0; i < counter; i++) {
let input_id = "product" + (i+1).toString();
userData.products.push(document.getElementById(input_id).value);
}
google.script.run.appendDataToSheet(userData);
}
</script>
Note:
When you modified the Google Apps Script of Web Apps, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in my report "Redeploying Web Apps without Changing URL of Web Apps for new IDE (Author: me)".
Reference:
Class google.script.run (Client-side API)

Related

Getting an Uncaught TypeError: Cannot set property 'onclick' of null with <script> at the end

I've looked at previous questions like this and cannot find the answer to my problem. I am working in javascript creating a checkout screen and I have two onclicks for two different html files but when I go to the html file for both it says that the other onclick is null. I have tried window.load and moving the script to the bottom of the
var cart = [];
var search = document.getElementById("addItem");
let placement = 0;
var cartElement = document.getElementById("showCart");
var cartTotal = document.getElementById("totalCart");
search.onclick = function(e) {
var userInput = document.getElementById("query").value;
var cartHTML = "";
e.preventDefault();
placement = 0;
for (i = 0; i < menu.length; i++) {
if (menu[i][0].includes(userInput)) {
cart.push(menu[i]);
placement++;
}
}
if (placement == 0) {
alert("Menu option not included. Please try again.");
}
cart.forEach((item, Order) => {
var cartItem = document.createElement("span");
cartItem.textContent = item[0] + " (" + item[1] + ")";
cartHTML += cartItem.outerHTML;
});
cartElement.innerHTML = cartHTML;
}
window.onload = function() {
var checkout = document.getElementById("addCartButton");
checkout.onclick = function(event) {
cart.forEach()
var cartTotalHTML = "";
event.preventDefault();
cart.forEach(Item, Order => {
var totalInCart = 0;
var writeCart = document.createElement("span");
totalInCart += Order[1];
});
writeCart.textContent = cartTotal += item[1];
cartTotalHTML = writeCart.outerHTML;
cartTotal.innerHTML = cartTotalHTML;
console.log(cartTotal);
}
}
<h3>Search for items in the menu below to add to cart</h3>
<form id="searchMenu">
<input type="search" id="query" name="q" placeholder="Search Menu..."></inpuut>
<input type = "Submit" name= "search" id="addItem" ></input>
</form>
<h4>Your cart: </h4>
<div class="Cart">
<div id="showCart"></div>
</div>
<script src="Script.js"></script>
<h4>Cart</h4>
<button id='addCartButton' class="Cart">Add Cart</button>
<div class="ShowCart">
<div id="totalCart"></div>
</div>
<script src="Script.js"></script>

Need help updating dropdowns in HTML Web Apps using Google Apps Script

This is my first time posting here so please let me know if I need to edit anything.
I am working on a program that runs through data that is imported in google sheets, displays one "row" of data in an HTML web app where the user can then assign an account number (found in a dropdown list) to the item that is displayed, and move on to the next row in the data. Each item in the data has a ID number and based on this ID number and the description of the data, the user selects the appropriate account number in the list to assign to the data.
The problem is that there are hundreds of these account numbers and having the users scroll/search through these to find the correct account will be very tedious.
The good news is that only certain accounts can be assigned to an ID number. I can effectively sort the dropdown list to only show accounts that can be assigned to the current ID therefore making the user's job much easier and much quicker.
However, I have no idea how to update the dropdown after the item loads on the html page. I am able to get the current ID number and sort through the accounts, I just am not able to update the drop down.
I have pasted the code.gs and the html/javascript code.
I did not include all of the code in code.gs file as some of it has nothing to do with my problem.
I am using Materialize CSS.
Code.gs:
var url = "hidden";
var ss = SpreadsheetApp.openByUrl(url);
var masterWS = ss.getSheetByName("Master List");
var items = [];
var Route = {};
Route.path = function (route, callback){
Route[route] = callback;
}
function doGet(e) {
Route.path("summary", summaryPage);
Route.path("edit", editPage);
if(Route[e.parameters.v]){
return Route[e.parameters.v]();
} else {
return editPage();
}
}
function summaryPage(){
var tmp = HtmlService.createTemplateFromFile("summary");
var sumList = showSummary();
tmp.summaryList = sumList;
return tmp.evaluate();
}
function include(fileName){
return HtmlService.createHtmlOutputFromFile(fileName).getContent();
}
function editPage(){
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("GLAccounts");
// Create drop down and populate with all account options
var SSassetList = ws.getRange(2,1, getLastRowSpecial("A", "GLAccounts"),1).getValues();
var htmlAssetList = SSassetList.map(function (r){return '<option>' + r[0] + '</option>';}).join('');
var tmp = HtmlService.createTemplateFromFile("page");
tmp.assetList = htmlAssetList;
return tmp.evaluate();
}
function calculateTotalEntries(){
//Logger.log("Done: " + done);
var lastRow = masterWS.getLastRow();
var totalEntries = 0;
var i = lastRow;
while (masterWS.getRange(i, 1).getValue() != "Transaction Date"){
i--;
totalEntries++;
}
masterWS.getRange("R1").setValue(totalEntries);
masterWS.getRange("R2").setValue(lastRow);
}
function userClicked(userInfo){
var r = masterWS.getRange("P1").getValue();
var GLAccount = userInfo.act;
var lastRow = masterWS.getRange("R2").getValue();
var totalEntries = masterWS.getRange("R1").getValue();
if(!(masterWS.getRange("P3").getValue())){
//Logger.log("Done parsing. Items length: " + items.length);
if(r <= totalEntries - 1 ){
masterWS.getRange("P4").setValue(lastRow - totalEntries + 1 + r);
if(masterWS.getRange("P1").getValue() != 0){
masterWS.getRange(lastRow - totalEntries + r, 8).setValue(GLAccount);
}
r = r + 1;
masterWS.getRange("P1").setValue(r);
} else {
//Logger.log("Last one");
masterWS.getRange("P3").setValue(true);
masterWS.getRange(lastRow, 8).setValue(GLAccount);
//return Error;
resetCounters();
calculateChange();
}
}
}
function showItem(){
var row = masterWS.getRange("P4").getValue();
return "Item: " + masterWS.getRange(row,5).getValue() + "; Date: " + slice(masterWS.getRange(row,1).getValue(), 13) + "; ID: "+ masterWS.getRange(row,6).getValue();
}
function getData(){
var row = masterWS.getRange("P4").getValue();
var id = "";
id = masterWS.getRange(row,6).getValue().toString();
var availAccounts = [];
var IDSheet = ss.getSheetByName("MerchantCodes");
var lastIDRow = IDSheet.getLastRow();
var lastIDCol = 0;
var currentRow = 0;
for(var i = 6; i < lastIDRow; i++){
if(IDSheet.getRange(i, 1).getValue().toString() == id){
currentRow = i;
break;
}
}
//Logger.log("ID: " + id + " # row " + i);
for( var j = 1; j < 10; j++){
if(IDSheet.getRange(currentRow,j).getValue() != ""){
lastIDCol = j;
}
}
//Logger.log("Last Column for row " + i + ": " + lastIDCol);
for(var r = lastIDCol - (lastIDCol - 3) + 1; r < lastIDCol+1; r++){
//Logger.log("Account: " + IDSheet.getRange(currentRow,r).getValue());
availAccounts.push(IDSheet.getRange(currentRow,r).getValue());
}
return availAccounts;
}
function resetCounters(){
masterWS.getRange("P1").setValue(0);
masterWS.getRange("P3").setValue(false);
masterWS.getRange("P4").setValue("");
masterWS.getRange("P5").setValue("");
masterWS.getRange("P6").setValue("");
}
function getLastRowSpecial(col, sheetName){
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName(sheetName);
var data = ws.getRange(col + "2:" + col).getValues();
var lastRowData = data.filter(String).length;
return lastRowData;
}
}
HTML:
The item that is displayed in the web app, which changes based on the data, is in the tags.
The dropdown list is populated using the tags. The data in those tags comes from the doGet()and editPage() functions in the code.gs file.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<?!= include("page-css"); ?>
</head>
<body>
<div class = "container"> <!-- Open container -->
<div> <!-- Open row -->
<label>Item</label>
<p><span id="current"></span></p>
</div> <!-- Close row -->
<div class ="row"> <!-- Open row -->
<button id="btn2" class="btn waves-effect waves-light red darken-3" type="submit" name="action">Start</button>
</div> <!-- Close row -->
<div class ="row"> <!-- Open row -->
<div class="input-field col s6">
<select id="glAcc">
<option disabled selected>Choose your GL Account</option>
<?!= assetList; ?>
</select>
<label>GL Account</label>
</div>
</div> <!-- Close row -->
<div class ="row"> <!-- Open row -->
<button id="updDrop" class="btn waves-effect waves-light red darken-3" type="submit" name="action">Update Dropdown
<i class="material-icons right">send</i>
</button>
</div> <!-- Close row -->
<div class ="row"> <!-- Open row -->
<button id="btn" class="btn waves-effect waves-light red darken-3" type="submit" name="action">Submit
<i class="material-icons right">send</i>
</button>
</div> <!-- Close row -->
<div class ="row"> <!-- Open row -->
<a href="<?= ScriptApp.getService().getUrl(); ?>?v=summary" id="summary" class="btn waves-effect waves-light red darken-3" type="submit" name="action">Go to Summary Page
<i class="material-icons right">arrow_forward</i>
</a>
</div> <!-- Close row -->
</div> <!-- Close container -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<?!= include("page-js"); ?>
</body>
</html>
HTML JS Code:
<script>
document.addEventListener('DOMContentLoaded', function(){
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems);
});
document.addEventListener('DOMContentLoaded', reset);
document.getElementById("btn").addEventListener("click",doStuff);
document.getElementById("btn2").addEventListener("click",doStuff);
document.getElementById("sumBtn").addEventListener("click", summary);
document.getElementById("updDrop").addEventListener("click", updateDropdown);
function doStuff(){
var userInfo = {};
userInfo.act = document.getElementById("glAcc").value;
google.script.run.withSuccessHandler(findItem).userClicked(userInfo);
//findItem();
//google.script.run.getLength();
// Reset dropdown
var myApp = document.getElementById("glAcc");
myApp.selectedIndex = 0;
M.FormSelect.init(myApp);
}
function reset(){
google.script.run.resetCounters();
google.script.run.calculateTotalEntries();
document.getElementById("current").textContent = "Click the Start Button";
}
function updateDropdown(){
google.script.run.withSuccessHandler(updateSelect).getData();
}
function updateSelect(vA){
var select = document.getElementById("glAcc");
select.options.length = 0;
vA.unshift("");
for(var i = 1; i < vA.length; i++){
select.options[i] = new Option(vA[i], vA[i]);
}
}
function findItem(){
google.script.run.withSuccessHandler(changeItem).showItem();
}
function changeItem(item){
document.getElementById("current").textContent = item;
//document.getElementById("options"). = "<option>1</option><option>2</option>";
}
function summary(){
google.script.run.withSuccessHandler(findSummary).calculateChange();
}
function findSummary(){
google.script.run.withSuccessHandler(changeSummary).showSummary();
}
function changeSummary(summary){
document.getElementById("sumText").textContent = summary;
}
</script>
Basically to summarize, I want the dropdown options to update as the item displayed also updates. If it is not possible to update at the same time, I can add a button which will update the dropdown once clicked.
I do not want to share the whole code/spreadsheet to everyone, but if you want access please message me and I can share it to you.
Thank you.
welcome to the SO community.
I believe the problem is not in the Apps Script.
When you use Materialize Select you need to re-init it.
This is the function I found in my codebase, it should help you:
function fillMaterializeSelect(elSelect, data) {
elSelect.options.length = 0;
for (let i = 0; i < data.length; i++) {
const dataElement = data[i];
const option = document.createElement("option");
option.value = dataElement.value;
option.text = dataElement.text;
elSelect.add(option);
}
M.FormSelect.init(elSelect);
}
Here is a JavaScript function I use a lot for updating <select>.
function updateSelect(vA,id){
var id=id || 'sel1';
var select = document.getElementById(id);
select.options.length = 0;
vA.unshift("");
for(var i=1;i<vA.length;i++)
{
select.options[i] = new Option(vA[i],vA[i]);//one is the value and the other is the display value
}
}
You retrieve the data with a
gooogle.script.run
.withSuccessHandler(updateSelect)
.getData();

Removing a class and adding another class (Appending the HTML tag onclick)

Would I be able to add a remove button to replace the add button as of the image below and remove the values in that row from the array object that I have declared whenever I remove a certain row?
Image of the html (Partly)
Before Clone
After Clone
Desired Result
Html page
<div id="selections">
<div class="form-group row controls selection">
<label for="selection01" class="col-sm-2 col-form-label">Selection Pair</label>
<div class="col-sm-2">
<select class="form-control selection01" id="selection010" placeholder="Selection 01" onchange="addNewSelection()"></select>
</div>
<div class="col-sm-2">
<select class="form-control selection02" id="selection020" placeholder="Selection 02" onchange="addNewSelection()"></select>
</div>
<div class="col-sm-2">
<input type="number" min="0.00" max="10000.00" step="1.00" class="form-control" id="productQuantity0" placeholder="Quantity">
</div>
<div class="col-sm-2">
<input type="button" class="btn btn-success" id="addSelection" value="Add Selection" onclick="addNewSelectionPair()"></button>
</div>
</div>
</div>
Script
function addNewSelectionPair() {
// Get all selections by class
var selection = document.getElementsByClassName('selection');
// Get the last one
var lastSelection = selection[selection.length - 1];
// Clone it
var newSelection = lastSelection.cloneNode(true);
// Update the id values for the input
newSelection.children[1].children[0].id = 'selection01' + selection.length;
newSelection.children[2].childrne[0].id = 'selection02' + selection.length;
newSelection.children[3].children[0].id = 'productQuantity' + selection.length;
// Add it to selectionss
document.getElementById('selections').appendChild(newSelection)
}
function getValues() {
// Get all selections by class
var selections = document.getElementsByClassName('selection');
var values = [];
for(var i = 0; i < selections.length; i++) {
// Add the values into the array
values.push([
document.getElementById('selection01' + i).value,
document.getElementById('selection02' + i).value
document.getElementById('productQuantity' + i).value
]);
}
return values;
}
This script will duplicate the last row of inputs. It will also collect the inputs and store their values in a 3d array to process.
function addSection() {
//Get all sections by class
var sections = document.getElementsByClassName('section');
//Get the last one
var lastSection = sections[sections.length - 1];
//Clone it
var newSection = lastSection.cloneNode(true);
//Add it do sections
document.getElementById('sections').appendChild(newSection);
//Recalucate the Ids for the removal
//Ids all get shifted after adding or removing a section
calcRemovalIds();
}
function getValues() {
//Get all inputs by class
var sectionsOne = document.getElementsByClassName('section01');
var sectionsTwo = document.getElementsByClassName('section02');
var values = [];
//Loop the inputs
for(var i = 0; i < sectionsOne.length; i++) {
//Add the values to the array
values.push([
sectionsOne[i].value,
sectionsTwo[i].value
]);
}
return values;
}
function removeSection(id = undefined) {
//Get all sections by class
var sections = document.getElementsByClassName('section');
//If there is only one row left, just skip
if (sections.length == 1) return true;
//If not id was given, remove the last row
if (id == undefined) id = sections.length - 1;
//Get the last one
var lastSection = sections[id];
//Remove it
lastSection.parentNode.removeChild(lastSection);
//Recalucate the Ids for the removal
//Ids all get shifted after adding or removing a section
calcRemovalIds();
}
function calcRemovalIds() {
var btns = document.getElementsByClassName('button');
for (var i = 0; i < btns.length; i++) {
//Check if its the last button
if (i + 1 == btns.length) {
//Make it a addSection button
btns[i].innerHTML = '+';
btns[i].setAttribute('onclick', 'addSection()');
} else {
//Make is a removeSection button
btns[i].innerHTML = '-';
btns[i].setAttribute('onclick',
'removeSection(' + i +')'
);
}
}
}
<div>
<div>
<h2>Product</h2>
<input id="product" placeholder="Product" />
</div>
<div id="sections">
<div class="section">
<input class="section01" placeholder="Section One" />
<input class="section02" placeholder="Section Two" />
<button class="button" onclick="addSection()">+</button>
</div>
</div>
</div>
<button onclick="
document.getElementById('values').innerHTML = JSON.stringify(getValues());
">Get Values</button>
<div id="values"></div>

Limiting Pagination using Javascript

I have a web app that uses OMDB API which fetches all the related results that matches the title of a Movie searched by the user.
So for example the user searched for "Star Wars" the API will then return 483 results, I managed to make a pagination for it but it shows all the pages from 1-48 and what I'm trying to figure out is how can I only show pages [1,2,3,4,5,6,7...49(ending page)], then change that pagination to [2,3,4,5,6,7,8...49] and so on.
Heres the code for it:
<input type="text" class="form-control" id="title" name="title" placeholder="Movie Title...">
<button onclick="callOMDB(document.getElementById('title').value)" class="btn btn-primary">Search</button>
<div id="page" class="page">
<nav aria-label="Page navigation example">
<ul class="pagination" id="pagination">
</ul>
</nav>
</div>
<div id="info">
</div>
function callOMDB(x){
var poster = document.getElementById("info");
var page = document.getElementById("pagination");
var search = x;
var searchLink = 'https://www.omdbapi.com/?i=tt3896198&apikey=123456&s='+encodeURI(x);
$.getJSON(searchLink).then(function(response){
poster.innerHTML = '';
page.innerHTML = '';
var length = response.Search.length;
for(var i = 0; i < length; i++){
var yr = response.Search[i].Year;
var title = response.Search[i].Title;
poster.innerHTML += "<p>Year: "+yr+"</p><p>Title: "+title+"</p>";
}
var pageNo = response.totalResults/10;
var i = 0;
for(i = 1; i < pageNo; i++){
page.innerHTML += '<li class="page-item"><a onclick="nextPage('+i+',\''+search+'\')" class="page-link" href="#">'+i+'</a></li>';
}
});
}
You can use slice to get slice of the entire result and display that. For the purpose of demo I just shown you only. and results are just numbers. The array can be anything. Important things is slice to get parts of results you want and display them.
After as you click through you move the start and end positions
const resultsList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // This could be results / or page numbers
const maxResults = 9;
let upperPageIndex = maxResults;
let currentPageIndex = 0;
let resultsToDisplay = resultsList.slice(currentPageIndex , upperPageIndex); // slice(startIndex, endIndex);
console.log(resultsToDisplay)
// if currentPageIndex = 2 then show 2 more as you go through
upperPageIndex += 1; // You can make 2 a constant if needed
currentPageIndex += 1;
resultsToDisplay = resultsList.slice(currentPageIndex , upperPageIndex);
console.log(resultsToDisplay)
I used the paramter page in the omdbapi and that is my code
JS
window.addEventListener('DOMContentLoaded', function () {
const posterContainer = document.getElementById("info");
const pageContainer = document.getElementById("pagination");
const titleInput = document.getElementById('title');
const searchBtn = document.getElementById('searchBtn');
const searchLink = 'https://www.omdbapi.com/?i=tt3896198&apikey=56fbcd03';
searchBtn.addEventListener('click', () => {
getData(titleInput.value);
});
// event delegation
$('body').on('click', '.page-link', function (e) {
e.preventDefault();
getData(titleInput.value, this.id);
});
function getData(keyword, page = 1) {
$.getJSON(`${searchLink}&page=${page}&s=${keyword}`).then(function (response) {
posterContainer.innerHTML = '';
pageContainer.innerHTML = '';
var length = response.Search.length;
for (var i = 0; i < length; i++) {
var yr = response.Search[i].Year;
var title = response.Search[i].Title;
posterContainer.innerHTML += "<p>Year: " + yr + "</p><p>Title: " + title + "</p>";
}
var pageNo = response.totalResults / 10;
var i = 0;
for (i = 1; i < pageNo; i++) {
pageContainer.innerHTML += `<li class="page-item" ><a class="page-link" id="${i}" href="#">${i}</a></li>`;
}
});
}
});
HTML
<input type="text" class="form-control" id="title" name="title" placeholder="Movie Title...">
<button id="searchBtn" class="btn btn-primary">Search</button>
<div id="page" class="page">
<nav aria-label="Page navigation example">
<ul class="pagination" id="pagination">
</ul>
</nav>
</div>
<div id="info">
</div>

Why does my value keep returning as "NaN"?

Here is the link to the jsbin.
I was almost finished with my project (I thought I was) and then I tested it out. It is supposed to add buttons with the chosen title of the task and the number of points it awards. Every time the button is clicked the points would be added on to the "Points" section and every 500 points my "Level" would increase.
Upon finishing it, it worked. Then I went to clear the localStorage since that's what I used to save the information, but I wanted to start over. When I did that, the 'Points' section, or 'results' value, keeps returning as "NaN". The code is exactly the same as it was when it worked. Can someone please tell me how to fix this problem, thank you in advance.
Here is the code. (Used bootstrap for CSS)
HTML
<center>
<br>
<h2> Add task </h2>
<div class='well' style='width:500px' id="addc">
<div id="addc">
<input class='form-control' style='width:450px' id="btnName" type="text" placeholder="New Task" /><br>
<input class='form-control' style='width:450px' id="btnPoints" type="text" placeholder="Points" /><br>
<button id="addBtn">Add</button>
</div> </div>
<div class='well' style='width:230px' id="container">
</div>
<hr style="width:400px;">
<h3>Points </h3>
<div id="result">0</div>
</div>
<hr style="width:400px;">
<div style="width:400px;">
<h3>Level
<p id='lvl'>0</p>
</div>
<hr style="width:400px;">
</center>
JavaScript
var res = document.getElementById('result');
res.innerText = localStorage.getItem('myResult');
var level = document.getElementById('lvl');
level.textContent = localStorage.getItem('myLevel');
var btns = document.querySelectorAll('.btn');
for(var i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function() {
addToResult(this.getAttribute('data-points'));
this.parentNode.removeChild(this.nextElementSibling);
this.parentNode.removeChild(this);
});
}
var addBtn = document.getElementById('addBtn');
addBtn.className = "btn btn-default";
addBtn.addEventListener('click', function() {
var container = document.getElementById('container');
var btnName = document.getElementById('btnName').value;
var btnPoints = parseInt(document.getElementById('btnPoints').value);
if(!btnName)
btnName = "Button ?";
if(!btnPoints)
btnPoints = 50;
var newBtn = document.createElement('button');
var newPnt = document.createElement('span');
newBtn.className = 'btn btn-danger';
newBtn.innerText = btnName;
newBtn.setAttribute('data-points', btnPoints);
newBtn.addEventListener('click', function() {
addToResult(this.getAttribute('data-points'));
this.parentNode.removeChild(this.nextElementSibling);
this.parentNode.removeChild(this);
});
newPnt.className = 'label';
newPnt.innerText = "+" + btnPoints;
container.appendChild(newBtn);
container.appendChild(newPnt);
});
function addToResult(pts) {
var result = document.getElementById('result');
result.innerText = parseInt(result.innerText) + parseInt(pts);
var lvl = 0;
var a = 100;
while (result.innerText > 5*a) {
lvl+=1;
a+=100;
}
document.getElementById('lvl').innerText = lvl;
var res = document.getElementById('result');
localStorage.setItem("myResult", res.innerText);
var level = document.getElementById('lvl');
localStorage.setItem("myLevel", level.textContent);
}
You were parsing result.innerText as a number, but its value, initially, was actually either NaN or nothing, both which end up being NaN. One fix is to just check if it parsed to a number, and if it didn't, fall back to 0.
I just basically changed that and removed some getElementByIds that, in my opinion, were redundant, check the addToResult function:
http://jsfiddle.net/owc26a0p/1/
function addToResult(pts) {
// NaN is falsy, so you can just use || to make a fallback to 0
var result = parseInt(resDiv.innerText, 10) || 0,
lvl = 0,
a = 100;
result = result + parseInt(pts, 10) || 0;
while (result > 5 * a) {
lvl += 1;
a += 100;
}
resDiv.innerText = result;
levelDiv.innerText = lvl;
localStorage.setItem("myResult", result);
localStorage.setItem("myLevel", levelDiv.textContent);
}
I ended up using jsFiddle since I couldn't always get jsBin to save my changes. Good luck.

Categories