Unable to call Javascript function from another file - javascript

I'm trying to call the game.LeftOrRightRow function from another file, main.js, yet it isn't working. I'd like to export the object game instead of just the particular function.
I know the function itself works because when it was in the same file it did exactly what it was meant to do (return newRow). I'm also pretty sure that I've specified the right directory.
It's my first time writing Javascript so this may come down to a silly error.
The 2048.js file who's function I want to export:
const game = Object.create(null);
game.LeftOrRightRow = function (i, direction){
let totalOne = squares[i].innerHTML;
let totalTwo = squares[i+1].innerHTML;
let totalThree = squares[i+2].innerHTML;
let totalFour = squares[i+3].innerHTML;
//the above stores the inner value of each square
//on that row, starting from the left
let row = [parseInt(totalOne), parseInt(totalTwo), parseInt(totalThree), parseInt(totalFour)]
//create an array storing the entire row
let filterRow = row.filter(num => num)
//filter out numbers from rows and store the numbers
//as a new array.
let missing = 4 - filterRow.length
//checking how many 0s there are now in the row
let zeros = Array(missing).fill(0)
//creating a new array filled with these 0s
if(direction == "right"){
let newRow = zeros.concat(filterRow)
//If we are wanting to swipe right, the zeros
//will be placed before the twos in our array.
return newRow
}else if (direction == "left"){
let newRow = filterRow.concat(zeros)
//If we are wanting to swipe left, the twos
//will be placed before the zeros in our array.
return newRow
}
}
export default Object.freeze(game);
The main.js file where I want to call the function:
import R from "../common/ramda.js";
import Json_rpc from "./Json_rpc.js";
import game from "../common/2048.js";
document.addEventListener("DOMContentLoaded", () => {
...
function moveLeftOrRight(direction){
for(let i=0; i <16; i++){
//loops over all of grid
if(i%4 === 0){
//define rows using modulus. If i MOD 4 = 0,
//this means that the square is the start of each row.
let newRow = game.LeftOrRightRow(i, direction)
//newRow = game.swipeRightRow(i)
//document.write(newRow)
squares[i].innerHTML = newRow[0]
squares[i+1].innerHTML = newRow[1]
squares[i+2].innerHTML = newRow[2]
squares[i+3].innerHTML = newRow[3]
//replaces each value with the new array
}
}
}
}

Related

How do I make less calls to sheet.getRange and reduce the execution time in a double loop

I want to reduce the calls to sheet.getRange in the following function, because the execution times out.
I've tried re-arranging the loops and parsing the data as a double array, however the size of my spreadsheet changes every day and I need to be able to reference the columns by name only.
function runDuplicateRemover() {
var sheet= SpreadsheetApp.getActive().getSheetByName('Sheet 1');
var rangeData = sheet.getDataRange();
var lastRow = rangeData.getLastRow();
var Cdata = sheet.getDataRange().getValues();
// here I am accessing the column which is used to find duplicates
var colCRM = Cdata[0].indexOf("CRM ID")+1;
var arrayOfDuplicates = [];
for(i=1; i<lastRow; i++){
var cellToCompare = sheet.getRange(i+1,colCRM);
// I am just changing all the colors to see the execution
cellToCompare.setBackground("#88b4fc");
var crmToCompare =cellToCompare.getValue();
//checks to see that this value is not already contained in the rows to delete
if (!cellToCompare.isBlank() && (arrayOfDuplicates.indexOf(i)+1)==0 ){
arrayOfDuplicates.push(i);
cellToCompare.setBackground("#f9d9f9");
for (j = i+1; j<lastRow; j++) {
var cellCurrent = sheet.getRange(j+1,colCRM);
cellCurrent.setBackground("#f2fc88");
var crmCurrent = cellCurrent.getValue();
if (crmToCompare == crmCurrent) {
arrayOfDuplicates.push(j);
cellCurrent.setBackground("#fc92f1");
}
}
//pops last value since that's the only one I want to keep
sheet.getRange(arrayOfDuplicates.pop()+1,colCRM).setBackground("#dbf7d4");
}
}
for (t = arrayOfDuplicates.length-1; t>=0; t--) {
sheet.deleteRow(arrayOfDuplicates[t]+1);
}
}
I'd like to reduce the calls to the sheet.getRange, however I don't know how to delete the rows and then return the data back to the sheet without messing all the column order up.

createElement creates infinite loop

I'm really new to javascript, and coding in general, and I can't understand why this causes an infinite loop:
let newTr = document.createElement('tr');
If I take it out, the webpage loads fine, but if I leave it in, the webpage never fully loads and my browser uses 50% of my CPU.
Here's the rest of my code:
// client-side js
// run by the browser each time your view template referencing it is loaded
console.log('hello world :o');
let arrPfcCases = [];
// define variables that reference elements on our page
const tablePfcCases = document.getElementById("tablePfcCases");
const formNewPfcCase = document.forms[0];
const caseTitle = formNewPfcCase.elements['caseTitle'];
const caseMOI = formNewPfcCase.elements['caseMOI'];
const caseInjuries = formNewPfcCase.elements['caseInjuries'];
// a helper function to call when our request for case is done
const getPfcCaseListener = function() {
// parse our response to convert to JSON
arrPfcCases = JSON.parse(this.responseText);
// iterate through every case and add it to our page
for (var i = 0; i = arrPfcCases.length-1;i++) {
appendNewCase(arrPfcCases[i]);
};
}
// request the dreams from our app's sqlite database
const pfcCaseRequest = new XMLHttpRequest();
pfcCaseRequest.onload = getPfcCaseListener;
pfcCaseRequest.open('get', '/getDreams');
pfcCaseRequest.send();
// a helper function that creates a list item for a given dream
const appendNewCase = function(pfcCase) {
if (pfcCase != null) {
tablePfcCases.insertRow();
let newTr = document.createElement('tr');
for (var i = 0; i = pfcCase.length - 1; i++) {
let newTd = document.createElement('td');
let newText = document.createTextNode(i.value);
console.log(i.value);
newTd.appendChild(newText);
newTr.appendChild(newTd);
}
tablePfcCases.appendChild(newTr);
}
}
// listen for the form to be submitted and add a new dream when it is
formNewPfcCase.onsubmit = function(event) {
// stop our form submission from refreshing the page
event.preventDefault();
let newPfcCase = [caseTitle, caseMOI, caseInjuries];
// get dream value and add it to the list
arrPfcCases.push(newPfcCase);
appendNewCase(newPfcCase);
// reset form
formNewPfcCase.reset;
};
Thanks!
P.S. There are probably a ton of other things wrong with the code, I just can't do anything else until I figure this out!
As an explanation, in your code
i = pfcCase.length - 1
assigned the value of pfcCase.length - 1 to i. The syntax of that part of the loop should be
an expression to be evaluated before each loop iteration. If this expression evaluates to true, statement is executed.
The evaluation of your code made no sense.
Evaluating
i < pfCase.length
before each iteration to check that the current index is less than the length of the array, however, works correctly.
Here is no conditional statement here. In this statement you are assigning pfcCase length minus 1 to the I variable.
for (var i = 0; i = pfcCase.length - 1; i++) {
You have to compare the i variable to the length of the pfcCase minus 1.
This should work.
for (var i = 0; i < pfcCase.length - 1; i++) {
noticed something else
This line does not do what you think it dose.
let newText = document.createTextNode(i.value);
i is just the index i.e. a number. It does not have the value property.
This is what you are looking to do.
let newText = document.createTextNode(pfcCase[i].value);
my preference (forEach)
I prefer using the array forEach method. It’s cleaner and less prone to mistakes.
pfcCase.forEach( function(val){
let newTd = document.createElement('td');
let newText = document.createTextNode(val.value);
console.log('The array element is. '. val.value, ' The value is. ', val.value);
newTd.appendChild(newText);
newTr.appendChild(newTd);
});

JS - setAttribute (a function with 2 parameters) to a bidimensional array

I'm trying to make a mini-calculator for my form. My html-form is based on data-prototype, so it renders an unlimited amount of forms with 2 inputs : date and duration.
This inputs are rendered with ID-s like loan_charge_0_date , loan_charge_1_duration ; next one : loan_charge_1_date, loan_charge_1_duration` and so on.
I already wrote a code that with regex creates an array with all ids of date, and an another array with all ids of durations. So, when I click on + button that adds a new form, my dateIdsArray = [loan_charge_0_date] and durationIdArray = [loan_charge_0_duration]. When I click it again, it pushed one more element to each array, the loan_charge_1_date in dateIdsArray and loan_charge_1_duration to durationIdsArray`.
Now, I need to each pair (form) to bind a function with 2 parameters like date.value and duration.value ... and in this function to make my endingDateCalculator.
In this order, I made some easy statements that first...concat this 2 arrays, and after that make them as a pair ... so, result array is a bidimensional array :
pairValuesArray = [
[loan_charge_0_date, loan_charge_0_duration],
[loan_charge_1_date, loan_charge_1_duration],
[loan_charge_2_date, loan_charge_2_duration]
];
How can I append an function to every this pair, so when I onkeyup the duration of input, it will call the endingDateCalculator function with 2 parameters (this.date, this.duration) and perform calculations?
I tried smth like :
pairArray.forEach( x => document.getElementById(x).setAttribute('onkeyup', 'endingDateCalculator(this.value, this.value);'));
but it show me ... can not run setAttribute to a null :/
My entire script is here :
<script>
var bodyText = document.getElementsByClassName('panel-group')[0].innerHTML;
var durationIds = bodyText.match(/id="(.*duration)"/g);
var durationIdArray = durationIds.map(y => y = y.split('\"')[1]);
var dateIds = bodyText.match(/id="(.*date)"/g);
var dateIdArray = dateIds.map(x => x = x.split('\"')[1]);
var concatArray = new Array();
for (var i = 0; i < durationIds.length; i++) {
concatArray.push(dateIdArray[i]);
concatArray.push(durationIdArray[i]);
}
var pairArray = new Array ();
var i,j,temparray,chunk = 2;
for (i=0,j=concatArray.length; i<j; i+=chunk) {
temparray = concatArray.slice(i,i+chunk);
pairArray.push(temparray);
}
console.debug(pairArray);
pairArray.forEach( x => document.getElementById(x).setAttribute('onkeyup', 'endingDateCalculator(this.value, this.value);'));
//dateIdArray.forEach( x => document.getElementById(x).setAttribute('onkeyup', 'endingDateCalculator(this.value);'));
function endingDateCalculator(valueOfDate, valueOfDuration) {
alert(valueOfDate + valueOfDuration);
}
</script>

How to iterate through javascript object and run a function on each value

I am new to JS.
I set up a Saved Search in NetSuite that gives us the image fields (containing URLs) of our items. I am now setting up a script in NS which tests these fields to see what item fields return 404 (i.e. need to be fixed).
My question is, how to set up function imageURLValidator to iterate through the field values of function searchItems?
Below is my start to the process but obviously has much incorrect syntax.
function imageURLValidator() {
var searchResults = searchItems('inventoryitem','customsearch529');
var url = '';
var item = '';
var field = '';
//insert loop here to iterate over items in searchResults array
//loop through items
for (var i = 0, i > searchResults[inventoryObject].length, i++) {
item = searchResults.[inventoryObject].[i];
//loop through fields in item
for (var f = 2, f > item.length, f++) {
field = item[f];
//check URL via item field's value
var code = checkURL(item[field].getvalue([field]));
//generate error based on code variable
createErrorRecord(code,item,field)
}
}
}
function searchItems(type, searchid) {
//defining some useful variables that we will use later
var inventoryArray = [];
var count = 0;
//loading the saved search, replace the id with the id of the search you would like to use
var inventoryItemSearch = nlapiLoadSearch(type, searchid);
//run the search
var inventoryItemResults = inventoryItemSearch.runSearch();
//returns a js array of the various columns specified in the saved search
var columns = inventoryItemResults.getColumns();
//use a do...while loop to iterate through all of the search results and read what we need into one single js object
do {
//remember the first time through the loop count starts at 0
var results = inventoryItemResults.getResults(count, count + 1000.0);
//we will now increment the count variable by the number of results, it is now no longer 0 but (assuming there are more than 1000 total results) will be 1000
count = count + results.length;
//now for each item row that we are on we will loop through the columns and copy them to the inventoryObject js object
for (var i=0; i<results.length; i++){
var inventoryObject = {};
for (var j=0; j<columns.length; j++){
inventoryObject[columns[j].getLabel()] = results[i].getValue(columns[j]);
}
//then we add the inventoryObject to the overall list of inventory items, called inventoryArray
inventoryArray.push(inventoryObject);
}
//we do all of this so long as the while condition is true. Here we are assuming that if the [number of results]/1000 has no remainder then there are no more results
} while (results.length != 0 && count != 0 && count % 1000 == 0);
return inventoryArray;
}
function checkURL(url) {
var response = nlapiRequestURL(url);
var code = response.getCode();
return code;
}
function createErrorRecord(code,item,field) {
if (code == 404){
//create error record
var errorRecord = nlapiCreateRecord('customrecord_item_url_error');
errorRecord.setFieldValue('custrecord_url_error_item', item);
errorRecord.setFieldValue('custrecord_url_error_image_field', field);
}
}
Here I can see searchResults variable will be empty while looping. As your call to searchItems function is async. Which will take some time to execute because I guess it will fetch data from API. By the time it returns value, your loop also would have bee executed. You can test this by putting an alert(searchResults.length) or console.log(searchResults.length). For that you need to use callback function
Also even if you get the results in searchResults. The loop you are doing is wrong. The array you will get is like [{},{},{}] i.e. array of objects.
To access you'll need
for (var i = 0, i > searchResults.length, i++) {
var inventoryObject = searchResults[i] // your inventoryObject
for(var key in inventoryObject){
item = inventoryObject[key]; // here you will get each item from inventoryObject
//loop through fields in item
for (var f = 2, f > item.length, f++) {
field = item[f];
//check URL via item field's value
var code = checkURL(item[field].getvalue([field]));
//generate error based on code variable
createErrorRecord(code,item,field)
}
}
}
And yes welcome to Javascript

Array.push.setAnyFormatting('red')?

Description:
Stack Overflow user mhawksey recently did some fantastic optimization of my code, and in doing so, introduced me to super efficient array pushes. But working with arrays is kind of difficult, because I can't seem to be able to use functions I can when using the traditional .getRange/.setValue approach.
Problem:
I need to integrate .setFontColors('red') and .setBackgroundColors('white').
Code and Images:
First, I will post the code. Second, an image of what the currently code does. Third, an image of what the code needs to do.
function format() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var lastRow = s.getLastRow();
var row;
//gets a [][] of all values in the column
var data = s.getRange("A:A").getValues();
//we are going to build a [][] to output result
var output = [];
//loop through all cells in column A
for (row = 0; row < lastRow; row++) {
var cellValue = data[row][0];
var dash = false;
if (typeof cellValue === 'string') {
dash = cellValue.substring(0, 1);
//if a number copy to our output array
} else {
output.push([cellValue]);
}
//if -dash
if (dash === "-") {
//build first + last name
var name = (data[(row+1)][0]+" "+data[(row+2)][0]).trim();
//add row for the -state (e.g. -MI)
output.push([cellValue]);
output.push([name]);
output.push(["Order complete"]);
//add a blank row
output.push([""]);
//jump an extra row to speed things up
row++;
}
}
//set the values we've made in our output [][] array
s.getRange(1, 1, output.length).setValues(output);
}
This is what the code does:
This is what I'm trying to achieve:
Update:
I've appended a simple, working formatting loop. The problem is, when I run it on a longer column of data, it takes too long to process. From what I understand of the comments, I cannot quickly format a spreadsheet. Am I wrong?
Appended formatting code:
//other variables
var range1;
//loop through column A
for (var row = 0; row < lastRow; row++) {
range1 = s.getRange(row + 1, 1);
//define offsets for if statement
var offset1 = range1.offset(1, 0);
var offset2 = range1.offset(2, 0);
//substring cannot run on numbers, so...
cellValue = range1.getValue();
if (typeof cellValue === 'number') {continue;};
dash = cellValue.substring(0, 1);
//if -
if (dash === "-") {
offset1.setFontColor('red');
offset2.setBackground('green');
};
};
You can use all the various spreadsheet methods to get and set colors, font sizes, font weights, etc. to and from distinct arrays but you can not mix these "attributes" in one single item. See the doc here.
Or even handier, in your script editor write a script that defines a range and play with the auto complete to see everything you can do with it...
(control+space keys)
edit following your code update.
You should create a second array that holds all the background colors of your range and fill it according to your needs.
In the code below I build the array in parrallels with your output array, not very elegantly but rather systematically to show how it works.
Note that null value means "no background color" while #0F0 is the hexadecimal code for green but you can also use the 'green' string if you prefer...
...
var output = [];
var backGrounds=[]
//loop through all cells in column A
for (row = 0; row < lastRow; row++) {
var cellValue = data[row][0];
var dash = false;
if (typeof cellValue === 'string') {
dash = cellValue.substring(0, 1);
//if a number copy to our output array
} else {
output.push([cellValue]);
backGrounds.push([null]);
}
//if -dash
if (dash === "-") {
//build first + last name
var name = (data[(row+1)][0]+" "+data[(row+2)][0]).trim();
//add row for the -state (e.g. -MI)
output.push([cellValue]);
backGrounds.push([null]);
output.push([name]);
backGrounds.push([null]);
output.push(["Order complete"]);
backGrounds.push(['#0F0']);
//add a blank row
output.push([""]);
backGrounds.push([null]);
//jump an extra row to speed things up
row++;
}
}
s.getRange(1, 1, output.length).setBackgrounds(backGrounds);
...
REMARK: The OP did a huge change from revision 1 to revision 3. Following is the content taken from the source of the revision 1.
Is it possible to push text to a spreadsheet with formatting such
as .setFontColor, .setBackgroundColor or .setBorder? I've been
monkeying around with code but never get an error message. It just
doesn't do anything. I'm working with something like this:
if (cell === "This should be red") {
var redCell = (data[(row)][0]).setFontColor('red');
array.push([redCell]);
}
Following is my answer to the revision 1.
To copy the value and format from one cell or range to another use copyTo(destination).
From the above link
// The code below will copy the first 5 columns over to the 6th column.
var sheet = SpreadsheetApp.getActiveSheet();
var rangeToCopy = sheet.getRange(1, 1, sheet.getMaxRows(), 5);
rangeToCopy.copyTo(sheet.getRange(1, 6));
}

Categories

Resources