I have a div that is displaying the contents of an order. Currently this is how I am implementing adding items to this div using JQuery
$(document).ready(function(){
//if cookie exists, show the panel
if($.cookie('order_cookie') != undefined){
productArray = JSON.parse($.cookie('order_cookie'));
$(".order-alert").show();
for(var i = 0; i < productArray.length; i++){
console.log(productArray[i]);
var obj = productArray[i];
$(".order-alert").append("<p> StockCode: " + obj.stockCode + " Qty: " + obj.quantity + "</p>");
console.log("Object code: " + obj.stockCode + " Qty: " + obj.quantity);
}
$('#order_counter').html(productArray.length);
}
});
I have it working so that when the user adds an item to the order the counter increments without reloading the browser window.
$('#order_counter').html(productArray.length);
I'm just wondering how I could implement the same thing with my loop to output the items in the order as the user adds them to the array
Any help is greatly appreciated.
This script adds items to array, the cookie is also set in the script
var productArray = []; // Will hold order Items
$(".orderBtn").click(function(event){
//Check to ensure quantity > 0
if(quantity == 0){
console.log("Quantity must be greater than 0")
}else{//It is so continue
//Show the order Box
$(".order-alert").show();
event.preventDefault();
//Get reference to the product clicked
var stockCode = $(this).closest('li').find('.stock_code').html();
//Get reference to the quantity selected
var quantity = $(this).closest('li').find('.order_amount').val();
//Order Item (contains stockCode and Quantity) - Can add whatever data I like here
var orderItem = {
'stockCode' : stockCode,
'quantity' : quantity
};
//Check if cookie exists
if($.cookie('order_cookie') === undefined){
console.log("Creating new cookie");
//Add object to the Array
productArray.push(orderItem);
}else{//Already exists
console.log("Updating the cookie")
productArray = JSON.parse($.cookie('order_cookie'));
//Check if the item already exists in the Cookie and update qty
var found = false;
for(var i =0; i < productArray.length; i++){
if(productArray[i].stockCode == stockCode){
console.log("OBJECT EXISTS")
var index = i;
found = true;
}
}
//If it exists update the old quantity
if(found){
//update
console.log("Match found at: " + index);
var oldQty = (productArray[index].quantity)
var newQty = parseInt(quantity) + parseInt(oldQty);
productArray[index].quantity = newQty;
}else{// It doesn't exist so add new item to array
productArray.push(orderItem);
}
}
}
//Update the Cookie
$.cookie('order_cookie', JSON.stringify(productArray), { expires: 1, path: '/' });
//Testing output of Cookie
console.log($.cookie('order_cookie'));
//Update the order tracker
$('#order_counter').html(productArray.length);
});
I can think of two options:
1) Create another field for the order to print them in which you update when a user adds something to their order.
2) Implement the move to front heuristic on your product array so that when a product is incremented it's moved to the front of the array and the products originally in front of it are pushed back one space. As an example if you start with
"orange" => 1
"pear" => 1
and then the user adds a pear followed by an apple, the result would be:
"apple" => 1
"pear" => 2
"orange" => 1
Both have issues when the array gets massive, but if you won't be getting orders containing hundreds of unique products, it shouldn't be an issue.
Regardless of which method you use, you can update the list presented to the user by just using $('.order-alert').prepend()
Related
The Problem: I am able to retrieve the HTMLOptionsCollection object from the select element, but unable to get an accurate length or array from it.
For context, I am trying to make an array from the HTMLOptionsCollection object so I can loop through the options to add the selected attribute to one of the option elements. Also, I'm doing this for a chrome extension so I'm not sure if there would be any odd compatibility issues because of that.
Right now, I have this code:
var dropdown = document.getElementById("clients"); // Initially empty
fillDropdown(); // This does in fact fill the select element with option elements
console.log(dropdown) // Returns select element
console.log(dropdown.options); // Returns filled HTMLOptionsCollection object
console.log(dropdown.options.length); // Returns 0
// Make an array out of HTMLOptionsCollection object (taken from https://stackoverflow.com/questions/6138042/javascript-selecbox-options-to-array)
var arr = Array.apply(null, dropdown.options).map(function(el) { return el.value; });
console.log(arr); // Returns Array[0]
Here are the console.log results:
I did not expect the length to be inaccurate at all and can't figure out why this is. Any help is greatly appreciated!
EDIT: Here is my fillDropdown() function. It's ultimate goal is to append option elements to the select element. The extra jargon is to prevent options from getting too long word wise.
// Input: None
// Output: None
// Proceeds to fill the clients dropdown with clients from local storage
function fillDropdown() {
chrome.storage.local.get(function(data) {
if (typeof data.lastClientName !== "undefined") {
for (var i = 0; i < clients.length; i++) {
// Create an option element to add to the dropdown.
var clientOption = document.createElement("option");
// cutoff is an array which holds whole words. This is done to cleanly cut off a name.
var cutoff = clients[i].split(" ");
// A clients name may have no more than 4 words to its name.
if (cutoff.length > 4) {
cutoff = cutoff[0] + " " + cutoff[1] + " " + cutoff[2] + " " + cutoff[3] + " ...";
// The full name attribute is used to store the actual name.
clientOption.setAttribute("fullName", clients[i]);
// The value and innerHTML are both the same and are user visible.
clientOption.setAttribute("value", cutoff);
if (data.lastClientName === cutoff) {
dropdown.value = clientOption.value;
}
clientOption.innerHTML = cutoff;
}
else {
// fullName is added here for consistency
clientOption.setAttribute("fullName", clients[i]);
clientOption.setAttribute("value", clients[i]);
if (data.lastClientName === clients[i]) {
dropdown.value = cutoff;
}
clientOption.innerHTML = clients[i];
}
dropdown.appendChild(clientOption);
}
}
else {
for (var i = 0; i < clients.length; i++) {
// Create an option element to add to the dropdown.
var clientOption = document.createElement("option");
// cutoff is an array which holds whole words. This is done to cleanly cut off a name.
var cutoff = clients[i].split(" ");
// A clients name may have no more than 4 words to its name.
if (cutoff.length > 4) {
cutoff = cutoff[0] + " " + cutoff[1] + " " + cutoff[2] + " " + cutoff[3] + " ...";
// The full name attribute is used to store the actual name.
clientOption.setAttribute("fullName", clients[i]);
// The value and innerHTML are both the same and are user visible.
clientOption.setAttribute("value", cutoff);
clientOption.innerHTML = cutoff;
}
else {
// fullName is added here for consistency
clientOption.setAttribute("fullName", clients[i]);
clientOption.setAttribute("value", clients[i]);
clientOption.innerHTML = clients[i];
}
dropdown.appendChild(clientOption);
}
}
});
}
Also the only html to be concerned with here is
<select name="clients" id="clients"></select>
Try this:
const newArr = Array.from(dropdown.options);
console.log(newArr.length)
You can find other ways to do this here: https://hackernoon.com/htmlcollection-nodelist-and-array-of-objects-da42737181f9
I'm so sorry, I just realized that clients in fillDropdown() was not defined. Clients is supposed to be an array of business names that I would use to actually fill the dropdown. Now I'm curious as to why I didn't get an error for that in my console. I thought any undefined variable would show in the console.
On top of clients not being defined, I also had to make fillDropdown a callback function.
Thank you everyone for helping!
i have 5 items in my page with 3 information. (for example, name and price and number )
i want when i click on them (for example item 1) for first time, create an object and save items information to localStorage and for another times increase the number of item in localstorage.
function() {
items.forEach(function(btn) {
btn.addEventListener('click', function(event) {
let exist = localStorage.getItem('name');
var name =
event.target.parentElement.parentElement.parentElement.parentElement.children[1].children[0].textContent;
localStorage.setItem('name', name);
var price =
event.target.parentElement.parentElement.parentElement.parentElement.children[1].children[2].textContent;
localStorage.setItem('price', price);
var number = localStorage.getItem('number');
number = parseInt(number);
if (number) {
localStorage.setItem('number', number + 1);
} else {
localStorage.setItem('number', 1)
}
});
});
})();
its my code, but when i click on any item, previeos details in localstorage will be lost and information of new item replaced.
how i can resolve it?
When you are calling localStorage.setItem('name', name) you are overwriting the previous value of name. To store all names, prices, and numbers you have to use array. But, localStorage supports nothing but string. So before writing, you have to convert the array to a string, and upon reading you have to revert the string back to an array.
function() {
items.forEach(function(btn) {
btn.addEventListener('click', function(event) {
let names = localStorage.getItem('name');
const exists = !!names;
names = exists ? JSON.parse(names) : [];
let prices = exists ? JSON.parse(localStorage.getItem('price')): [];
let numbers = exists ? JSON.parse(localStorage.getItem('number')) : [];
var name =
event.target.parentElement.parentElement.parentElement.parentElement.children[1].children[0].textContent;
const nI = names.indexOf(name);
if (nI === -1) {
names.push(name);
localStorage.setItem('name', JSON.stringify(names));
var price =
event.target.parentElement.parentElement.parentElement.parentElement.children[1].children[2].textContent;
prices.push(price);
localStorage.setItem('price', JSON.stringify(prices));
numbers.push(1);
} else {
// else they are already in localStorage, just increase number
numbers[nI]++;
}
localStorage.setItem('number', JSON.stringify(numbers));
});
});
})();
This was difficult to title without examples and context. Here goes...
I have a Google app script which searches through a column of student ids (column A on the compiledDATA sheet) and then sets a value (an award) in column B of the same row. This works fine for a single student id, but I need the script to loop and set the same award value for all of the students in the GroupAwardIDs range which is located on a separate sheet called Group Awards.
Here's a link to my sample spreadsheet.
The values to be set are nonconsecutive, and in actual use there may be over a thousand to be set at a time.
How can I achieve this in a quick and efficient way without running into quota issues?
Here's the script (please excuse all the comments - it helps me keep track):
function AwardGroup() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var StarLog = sheet.getSheetByName("compiledDATA");
var GroupAward = sheet.getRangeByName("GroupAward").getValue();
var GroupAwardIDs = sheet.getRangeByName("GroupAwardIDs").getValue(); // THESE ARE THE IDS OF STUDENTS WHO WILL RECEIVE THE AWARD. HOW DO SET VALUES FOR ALL AND ONLY THESE IDS?
var IDs = sheet.getRangeByName("StudentIDs").getValues(); // all of the student IDs
for (var i = 0; i < IDs.length; i++) {
if (IDs[i] == "123461") { // THIS WORKS IF HARDCODE A SINGLE ID
var rowNumber = i+3; // find row and add 3 to compensate for GroupAward range staring at row 3
var StarLogCurrent = StarLog.getRange("B"+rowNumber).getValue(); // locates students award log cell using A1 notation
var appendAward = GroupAward.concat(StarLogCurrent); // prepends new award to previous awards
StarLog.getRange("B"+rowNumber).setValue(appendAward); //write new star log
}
}
}
You want to put GroupAward ("'Group Awards'!B3") to the column "B" of "compiledDATA" with the same row, when StudentIDs ("compiledDATA!A3:A1000") and GroupAwardIDs ("'Group Awards'!B7:B1002") are the same. If my understanding is correct, how about this modification? I think that there are several solutions for your situation. So please think of this as one of them.
Modification points :
Retrieve all GroupAwardIDs.
Remove empty elements in GroupAwardIDs.
Search IDs using GroupAwardIDs and put GroupAward when the IDs is the same with GroupAwardIDs.
Put the values with GroupAward.
Modified script :
Please modify as follows.
From :
var GroupAwardIDs = sheet.getRangeByName("GroupAwardIDs").getValue(); // THESE ARE THE IDS OF STUDENTS WHO WILL RECEIVE THE AWARD. HOW DO SET VALUES FOR ALL AND ONLY THESE IDS?
var IDs = sheet.getRangeByName("StudentIDs").getValues(); // all of the student IDs
for (var i = 0; i < IDs.length; i++) {
if (IDs[i] == "123461") { // THIS WORKS IF HARDCODE A SINGLE ID
var rowNumber = i+3; // find row and add 3 to compensate for GroupAward range staring at row 3
var StarLogCurrent = StarLog.getRange("B"+rowNumber).getValue(); // locates students award log cell using A1 notation
var appendAward = GroupAward.concat(StarLogCurrent); // prepends new award to previous awards
StarLog.getRange("B"+rowNumber).setValue(appendAward); //write new star log
}
}
To :
var GroupAwardIDs = sheet.getRangeByName("GroupAwardIDs").getValues(); // Modified
var IDs = sheet.getRangeByName("StudentIDs").getValues();
// I modified below script.
GroupAwardIDs = GroupAwardIDs.filter(String);
var res = IDs.map(function(e){
return GroupAwardIDs.filter(function(f){
return f[0] == e[0]
}).length > 0 ? [GroupAward] : [""];
});
sheet.getRange("compiledDATA!B3:B1000").setValues(res);
If I misunderstand your question, please tell me. I would like to modify it.
Edit :
You want to add GroupAward to the original values at column B. I understood what you want to do like this. If my understanding is correct, please modify to as follows. In this sample, I used ", " as the delimiter.
var GroupAwardIDs = sheet.getRangeByName("GroupAwardIDs").getValues(); // Modified
var IDs = sheet.getRangeByName("StudentIDs").getValues();
// I modified below script.
var columnB = sheet.getRange("compiledDATA!B3:B1000");
var valColB = columnB.getValues();
GroupAwardIDs = GroupAwardIDs.filter(String);
var res = IDs.map(function(e, i){
return GroupAwardIDs.filter(function(f){
return f[0] == e[0]
}).length > 0 ? [valColB[i][0] ? GroupAward + ", " + valColB[i][0] : GroupAward] : [valColB[i][0]]; // Modified
});
columnB.setValues(res);
I've created a custom menu with multiple items in it, however I'm having difficulties determining which item was clicked by the user. I want to use the same function for every item in this menu but I can't figure out how to pass on the info of which item was pressed into my function. Multiple ideas that I've had but haven't been able to implement are: trying to pass a parameter when pressing a button (the parameter could be the name of the button or its index), or trying to somehow determine which item was clicked by index (i.e. "item 3 was clicked") and passing that info on to the function.
var ui = SpreadsheetApp.getUi(); //shortcut to access ui methods
var ps = PropertiesService.getScriptProperties(); //shortcut to access properties methods
var ss = SpreadsheetApp.getActiveSpreadsheet() //shortcut to access spreadsheet methods
function onOpen() {
var menu = ui.createMenu('Scripts') //create a menu with this name
var subMenu = ui.createMenu('Timestamps')
for (var n = 0; n < ss.getNumSheets(); n++){
var sheets = ss.getSheets();
var sheetName = sheets[n].getName();
Logger.log(sheetName)
subMenu.addItem(sheetName, 'sheets')
}
menu.addSubMenu(subMenu).addToUi(); //add it to the UI
}
function sheets(sheet){
var response = ui.alert(sheet, 'Add to timestamps?', ui.ButtonSet.YES_NO_CANCEL) //create a button and store the user value in response
if(response == ui.Button.YES){ //if the user pressed YES (add this item to timestamp list)
if(sheets.indexOf(sheet) != -1){ //check if item is already in the array. If it is, do nothing
//item is aleady in array
}else if(sheets.indexOf(sheet) == -1){ //check if it is NOT in the array. If it isn't, add it
//item isn't in array, but needs to be added
sheets.push(sheet) //add the item to the array
}
}else if(response == ui.Button.NO){ //if the user pressed NO (remove item from the list)
if(sheets.indexOf(sheet) != -1){ //if the item already exists but needs to be removed)
//item exists in array, but needs to be removed
var index = sheets.indexOf(sheet); //find where the item is stored
sheets.splice(index, 1); //splice that item out of the array
}else if(sheets.indexOf(sheet) == -1){ //if the item already doesn't exist in the array, do nothing
//item already isn't in array
}
}
ps.setProperty('updatedSheets', JSON.stringify(sheets)) //storing the new value of sheets so that we can view it in the properties screen (only for debugging purposes)
}
What this code currently does is when the spreadsheet is opened, a menu is created named Scripts with a sub-menu inside of it named Timestamps. Inside of the sub-menu timestamps, I have one item for each sheet. The purpose is that when the user clicks on one of the items, a pop-up appears with 3 buttons: Yes, No, and Cancel. If they press Yes, that item is supposed to be added to the array sheets. If they press No, that item is supposed to be removed. If they press Cancel, nothing happens. I have it working so far to add and remove the items if they specify in the code a specific sheet, but how could I get it so that I could use the same function for every item and pass the parameter sheet (depending on which item was clicked) into the function sheets.
Example of the functionality of the code if I hard-code the sheet name without passing a parameter to the function:
function sheets(){
var response = ui.alert('Sheet1', 'Add to timestamps?', ui.ButtonSet.YES_NO_CANCEL) //create a button and store the user value in response
if(response == ui.Button.YES){ //if the user pressed YES (add this item to timestamp list)
if(sheets.indexOf('Sheet1') != -1){ //check if item is already in the array. If it is, do nothing
//item is aleady in array
}else if(sheets.indexOf('Sheet1') == -1){ //check if it is NOT in the array. If it isn't, add it
//item isn't in array, but needs to be added
sheets.push('Sheet1') //add the item to the array
}
}else if(response == ui.Button.NO){ //if the user pressed NO (remove item from the list)
if(sheets.indexOf('Sheet1') != -1){ //if the item already exists but needs to be removed)
//item exists in array, but needs to be removed
var index = sheets.indexOf('Sheet1'); //find where the item is stored
sheets.splice(index, 1); //splice that item out of the array
}else if(sheets.indexOf('Sheet1') == -1){ //if the item already doesn't exist in the array, do nothing
//item already isn't in array
}
}
ps.setProperty('updatedSheets', JSON.stringify(sheets)) //storing the new value of sheets so that we can view it in the properties screen (only for debugging purposes)
}
I know eval is evil but I cannot help using it. Yes, if you make a bunch of functions dynamically via eval then the rest is trivial.
var FUNC_STR = 'sheets'; //the real function name (global constant)
function onOpen() {
//...
for(var n = 0; n < ss.getNumSheets(); n++){
var sheets = ss.getSheets();
var sheetName = sheets[n].getName();
subMenu.addItem(sheetName, FUNC_STR + n); //note here
}
menu.addSubMenu(subMenu).addToUi();
}
//dynamically make functions
var evalString = '';
for(var n = 0; n < ss.getNumSheets(); n++) {
evalString += 'function ' + FUNC_STR + n + '() { ' +
FUNC_STR + '(' + n + ') }';
}
eval(evalString);
//now you can take a argument.
//function name should be the same as FUNC_STR.
function sheets(sheet) {
SpreadsheetApp.getUi().alert(sheet);
//...
}
I am creating a web page where the user can add an item into a dropbox buy clicking a button. The sessionstorage store the partnum and quantity of the item. The dropbox will display the details (quantity would be 1)of the item selected. How do I update the quantity to 2 if the same item is selected?
$("#btnBuy0").click(function()
{
$("#dropbox").append('<span><img class = "thumb" src="../images/21_metoyou.jpg" />' + teddy[0].desc + ", Price £"
+ teddy[0].price + ", Quantity: " + quantity + "</span><br/>");
if (Modernizr.sessionstorage)
{ // check if the browser supports sessionStorage
myids.push(teddy[0].partnum + quantity); // add the current username to the myids array
sessionStorage["ids"]=JSON.stringify(myids); // convert it to a string and put into sessionStorage
}
else
{
// use cookies instead of sessionStorage
}
for (var item =0; item<sessionStroage.length; item++)
{
var key = sessionStorage.key(teddy[0].partum);
if (teddy[0].partnum == teddy[item].partnum)
{
var q = sesstionStorage.getItem(quantity, quantity++);
}
I would suggest you make use of a differnt data structure for storing the user's basket. Instead of using an Array (myids), you could make use of an Associative Array (by using a JavaScript object) to map the partnum against a quantity, eg:
// Basket is initially empty.
basket = {};
function saveOrder(teddy, quantity) {
var partnum = teddy[0].partnum;
// Create a mapping between the partnum and the quantity
basket[partnum] = quantity;
// Write the basket to sessionStorage.
sessionStorage.basket = JSON.stringify(basket);
}
Using a map would allow you to create helper methods to read and write the basket object from SessionStorage, eg:
function fetchBasketFromSession() {
return JSON.parse(sessionStorage.basket);
}
function writeBasketToSession(basket) {
sessionStorage.basket = JSON.stringify(basket)
}
function getPartNumOf(teddy) {
return teddy[0].partnum;
}
function getQuantityInSessionBasketOf(teddy) {
// Fetch the basket from sessionStorage
var sessionBasket = fetchBasketFromSession(),
partnum = getPartNumOf(teddy);
// Return the quantity mapped to the partnum in the basket, or 0 if nothing
// is mapped.
return sessionBasket[partnum] || 0;
}
// Combining these functions would allow you to update the users basket.
function addToBasket(teddy, quantityToAdd) {
var sessionBasket = fetchBasketFromSession(),
currentQuantity = getQuantityInSessionBasketOf(teddy),
partnum = getPartNumOf(teddy);
// Update the quantity for this partnum and write it back out.
sessionBasket[partnum] = currentQuantity + quantityToAdd;
writeBasketToSession(sessionBasket);
}
Hope that helps :)