wants to know about some Javascript function explanation - javascript

Hy,this is my first post here
I am following a front end dev. class
Recent task was to create a pixel art page,was my first ever bigger task with javascript,i asked around and solved parts what I didn't know how,but now I do not understand everything,would appreciate if any experienced user could help me.
// Select color input
// Select size input
// When size is submitted by the user, call makeGrid()
//function makeGrid(row,colm) {
function makeGrid() {
let gridRows, cell;
let rows = $("#inputHeight").val();
let cols = $("#inputWidth").val();
let table = $("#pixelCanvas");
table.children().remove();
for (let i = 0; i < rows; i++) {
table.append("<tr></tr>");
}
gridRows = $("tr");
for (let j = 0; j < cols; j++){
gridRows.append("<td></td>");
}
cell = table.find("td");
table.on("click", "td", function() {
var color = $("input[type='color']").val();
$(this).attr("bgcolor", color);
});
}
//when size is submitted call makeGrid()
$("input[type='submit']").click(function(e) {
e.preventDefault();
makeGrid();
});
This is my code,parts which I do not understand:
table.children().remove();-removes tables child element(?what exactly removes,why this needed to be implemented?
cell = table.find("td");-I know that .find is a jquery element which allows us to search trough descendant but I do not understand why I needed this here.
The project is also uploaded on my codepen
https://codepen.io/MelindaB/pen/xWgJqY
Thank you for the help

table.children().remove(); is used to clear the current generated table to make it possible to create a new one.
You can test this by removing the line, generating a 1x1 table, and generate another 1x1 after that. You will see the grid now actually consists of 3 cells instead of the specified 1.
As far as I can see cell = table.find("td"); has no use since cell is not used anywhere and this line can be removed.

Related

How does this repeat() function work? Help me understand

I'm learning Javascript and found this solution on how to make a 16X16 grid. so far i've used example.repeat(number) with a an integer value. I somewhat get the flow of the code but I cant grasp how repeat works here exactly, kindly help.
Result on codepen: https://codepen.io/shogunhermit15/pen/mdxyqMN?editors=1010
function buildGrid(x, y, cellSize, gridElement) {
gridElement.style.display = "grid";
gridElement.style.gridTemplateColumns = `repeat(${x}, ${cellSize}px)`;
gridElement.style.gridTemplateRows = `repeat(${y}, ${cellSize}px)`;
let squares = new DocumentFragment();
for (let i = 0; i < x * y; i++) {
let square = document.createElement('div');
square.className = 'square';
squares.appendChild(square);
}
gridElement.appendChild(squares);
}
buildGrid(16, 16, 25, document.querySelector(".grid"));
I think your question is not related to javascript.
It is related to the CSS repeat function.
The repeat() CSS function represents a repeated fragment of the track list, allowing a large number of columns or rows that exhibit a recurring pattern to be written in a more compact form.
Here is Mdn refrence where You can learn more:
https://developer.mozilla.org/en-US/docs/Web/CSS/repeat
You will find here your code with each line commented, hoping that it helps you to understand your code correctly.
function buildGrid(x, y, cellSize, gridElement) { // declaration of the buildGrid function which takes as parameters the location of the grid, the size of the cell, and the element of the grid
gridElement.style.display = "grid"; // grid display is set to grid
gridElement.style.gridTemplateColumns = `repeat(${x}, ${cellSize}px)`; // set grid size based on cell size
gridElement.style.gridTemplateRows = `repeat(${y}, ${cellSize}px)`; // set grid size based on cell size
let squares = new DocumentFragment(); // creating the squares object which contains the grid elements
for (let i = 0; i < x * y; i++) { // loop that creates grid cells
let square = document.createElement('div'); // creating a div element
square.className = 'square'; // adding square class to cell
squares.appendChild(square); // adding the cell to the grid
}
gridElement.appendChild(squares); // adding grid to page element
}
buildGrid(16, 16, 25, document.querySelector(".grid")); // call buildGrid function with defined parameters

jquery.sheet trigger formula calculation on cell

So I am loading csv files from a server an inserting js function calls that create tables/sheets with jquery.sheet. Everything works thus far but when I put functions into the list they do not calculate.
The sheets (simplified)data object for the td has this before I modify anything:
Object {td: x.fn.x.init[1], dependencies: Array[0], formula: "", cellType: null, value: "=A2+B2+C2"…}
When I set the formula value it changes to:
Object {td: x.fn.x.init[1], dependencies: Array[0], formula: "=A2+B2+C2", cellType: null, value: "=A2+B2+C2"…}
So I understand how to set formula and value but what i wish to do is trigger an event to auto calculate a cell hopefully based on an "X,Y" co-ordinate, or find out if I am taking the wrong approach.
I dont know if this helps but when I go to edit a cell it will appear as ==A2+B2+C2 not =A2+B2+C2
I would supply my code but because of the C# asp and js interaction it is not short I don't think it would help.
Solved:
Two things are essential to load a formula from a csv file to a jquery.sheet instance and then have it calculate. First is to manually set the objects ["formula"] property, while leaving off the '=' in the beginning because it adds its own. then you must trigger the "calc(s,true)" function with s as the sheets index and in my case I put true as the second parameter because I believe it forces calculations on cells with a function.
var sheets = jQuery.sheet.instance[0];
for (var s = 0 ; s < names.length; s++) {
var sheet = sheets.spreadsheets[s];
for (var k = 1; k < sheet.length; k++) {
var row = sheet[k];
for (var j = 1; j < row.length; j++) {
var col = row[j];
//alert(cell.value);
if (col.value.startsWith("=")) {
col["formula"] = col.value.substring(1, col.value.length);
}
}
}
sheets.calc(s, true);
}
If a better way is found please let me know. I do not think this is very scalable as it is O(n^3).

How to delete all items from an FormApp object?

I recently asked a question about how to add items to a Google Form from a Google Spreadsheet. And it works great. Instead of using FormApp.create(), though, I'll have to use .openByUrl() because the ID has to stay the same. The problem is that if I run my script again, it'll open the existing form (great) and then append more items to the existing form.
This behaviour makes perfect sense but is not quite what I want. So I thought I'd just remove all existing items before I add new ones from my spreadsheet. I consulted the Google dev site for Form Services and feel like I should have all the pieces. I can't quite put them together, though.
I am now doing this following:
var form = FormApp.openByUrl('https://docs.google.com/forms/d/.../edit');
var items = form.getItems();
for (var i in items) {
form.deleteItem(i);
}
However, that'll give me an out of range error. Can someone point me in the right direction?
The problem is with how you're iterating over the array.
Try this:
var form = FormApp.openByUrl('https://docs.google.com/forms/d/.../edit');
var items = form.getItems();
for (var i=0; i<items.length; i++) {
form.deleteItem(i);
}
function clearForm(){
var items = form.getItems();
while(items.length > 0){
form.deleteItem(items.pop());
}
}
This worked for me when I ran into the same issue:
for (var i=0; i<items.length; i++) {
if (items[i] != null){
form.deleteItem(i);
}
}
Start by deleting the last item and repeat it until all items are deleted. This could be done by a reverse for loop:
function deleteAllItems(){
var form = FormApp.openById(/*put here your form id*/);
var items = form.getItems();
var end = items.length - 1;
for(var i = end ; i >= 0; i--){
form.deleteItem(i);
}
}
Another alternative is avoid of a variable index by using 0, so the first item will be deleted, no matter if a regular or a reverse loop is used. Note: This was already mentioned in a comment to another answer.
I also ran into the same problem. This one worked for me:
function deleteItems(){
var form = FormApp.openById('ID');
var items = form.getItems();
items.forEach(function(e){form.deleteItem(e)})
}
var form = FormApp.openByUrl('https://docs.google.com/forms/.../edit');
var items = form.getItems();
while(items.length > 0)
{
form.deleteItem(items.pop());
}
This works for me.
When you are checking the length of a variable=form.getItems() in a loop, its going to through some error because the length of that is not changing and the loops end up being infinite and throughing error.
So, heres my solution to the problem:
for(;form.getItems().length>0;)
{
form.deleteItem(0);
}
I ran into the same problem. However, I have fixed it by iterating in the reverse order.
var form=FormApp.openByUrl('form url here');
var Items=form.getItems();
var len=Items.length;
for (var i=Items.length-1;i>2;i--){ //Delete every item except first three items
form.deleteItem(i)
}
There are many options for looping over all form items and removing each, the most succinct being:
With Chrome V8 runtime
form.getItems().forEach(form.deleteItem)
Without Chrome V8 runtime
for each (var item in form.getItems()) {
form.deleteItem(item);
}

An error occur when I use appendChild ("<br>") in a genuine exist reference

This is a beginner's question...
I want to write some code to initialize a bunch of seats picture in my web page,
create and set attribute to them,
and make them change line every 9 seats (4 rows, and for every row it has 9 seats), here is the code
function initSeats() {
var seatsDiv = document.getElementById("seats");
//Initialize the appearence of all seats
for (var i = 0; i < seats.length; i++) {
for (var j = 0; j < seats[i].length; j++) {
var currentSeatIndex = i * seats[i].length + j;
if (seats[i][j]) {
//if current seat is available(true), create a new IMG element and set some attributes;
} else {
//if current seat is unavailable(true), create a new IMG element and set some attributes;
}
}
seatsDiv.appendChild("<br>");//here is the problem
}
}
what I want to do is when one of the outer loop finished, add a at the end,
But then I got a "NotFoundError" in Chrome that looks like the node seatsDiv doesn't exist
so after all only one row of seats were successfully initialized.
Is appendChild supposed to append anything at the position? Or should I use some other method?
appendChild expects an HTMLElement rather than a string, try switching to:
seatsDiv.appendChild(document.createElement("br"));

Google Apps Script double deleting rows in spreadsheet

function onEdit() {
var openRequests = SpreadsheetApp.getActive().getSheetByName('Open Requests');
var lastRowOpen = openRequests.getLastRow();
var closedRequests = SpreadsheetApp.getActive().getSheetByName('Closed Requests');
var lastRowClose = closedRequests.getLastRow();
var closed = openRequests.getRange(2,8,lastRowOpen,1).getValues();
for (var i = 0; i < lastRowOpen; i++)
{
if (closed[i][0].toString() == 'Yes')
{
var line = i+2;
if (closedRequests.getLastRow() == 1)
{
openRequests.getRange(line,1,1,9).copyTo(closedRequests.getRange(2,1,1,9));
closedRequests.getRange(2,9,1,1).setValue(new Date());
openRequests.deleteRow(line);
}
else
{
openRequests.getRange(line,1,1,9).copyTo(closedRequests.getRange(lastRowClose+1,1,1,9));
closedRequests.getRange(lastRowClose+1,9,1,1).setValue(new Date());
openRequests.deleteRow(line);
}
}
}
}
I have set up a trigger to run onEdit. What it does is check a column called Closed to see if it says Yes. The Closed column has a data validation drop down menu with the value Yes in it.
So when I click on the drop down menu and select Yes, it should copy the whole row to another sheet called Closed Requests then delete that row from the spreadsheet called Open Requests.
The issue I am having is that about 50% of the time, it deletes the row I select Yes to but it ALSO deletes the row below it (and about 50% of the time when this happens, only some times does the second deleted row show up in Closed Requests, the other times the whole row just disappears forever unless I undo).
From what I can tell, the deleteRow() function deletes the whole row and shifts all rows below it up a row to fill in the blank. So the row below the one meant to be deleted gets shifted up to the same row and also gets deleted. I don't know why the function is getting called twice though.
I tried adding some delays but it does not seem to be working.
function onEdit(e) {
var eRange = e.source.getActiveRange();
var openRequests = SpreadsheetApp.getActive().getSheetByName('Open Requests');
var closedRequests = SpreadsheetApp.getActive().getSheetByName('Closed Requests');
var nextRowClose = (closedRequests.getLastRow()?closedRequests.getLastRow()+1:2);
if(eRange.getSheet().getName()=="Open Requests" && eRange.getColumn()==8 && eRange.getValue()=="Yes") {
openRequests.getRange(eRange.getRow(), 1, 1, 9)
.copyTo(closedRequests.getRange(nextRowClose, 1));
closedRequests.getRange(nextRowClose, 9).setValue(new Date());
openRequests.deleteRow(eRange.getRow());
}
}
Could try iterating backwards as it was mentioned to me. Throwing in a SpreadsheetApp.flush() after the delete may help too.
#Jack, I have a similar use case to you. My code is the backwards one that BryanP discusses. My code is more or less here: "Batch removal of task items where status = 'Done'". It is because I remove them in a batch that I use the backwards method whereby the removal of a row with a higher row number will not disturb the row number of any rows with a lower row number.
But you are not removing rows in batch mode, so maybe backwards shouldn't make a difference (perhaps unless two users use the sheet and delete at the same time?)
So thought I'd try your code. I shoe horned your code into the onedit() function that is already present on my spreadsheet (which is used to colour rows red after a period of inactivity, and to put in a timestamp once the task is actually attended).
Then to test I used a copy of one of our spreadsheet which had already 50 rows/tasks in it. I manually filled in the required cells in a row and selected Done from the cell with the dropdown (I changed your code to expect "Done" rather than "Yes"). I repeated this for 20 rows.
The Result: Your code succeeded as you had expected it to every one of the 20 times ... no double deletes, always copying data across. It worked for me without introducing delays nor SpreadsheetApp.flush().
I don't have a solid suggestion I am afraid. In passing I mention the known fault where the spreadsheet has not properly refreshed itself, so does not show the deleted rows; this can be checked for by manually refreshing the spreadsheet when this fault appears. (However, the indications of this fault does not seem to logically fit with your report about the double copying over of two sequential rows.)
Thread lock? Sounds like a thread lock problem. Try:
function onEdit() {
// ****** add lock code
var lock = LockService.getPublicLock();
var hasMutex = lock.tryLock(100);
if(hasMutex==false) {
return;
}
// *** end
var openRequests = SpreadsheetApp.getActive().getSheetByName('Open Requests');
var lastRowOpen = openRequests.getLastRow();
var closedRequests = SpreadsheetApp.getActive().getSheetByName('Closed Requests');
var lastRowClose = closedRequests.getLastRow();
var closed = openRequests.getRange(2,8,lastRowOpen,1).getValues();
for (var i = 0; i < lastRowOpen; i++)
{
if (closed[i][0].toString() == 'Yes')
{
var line = i+2;
if (closedRequests.getLastRow() == 1)
{
openRequests.getRange(line,1,1,9).copyTo(closedRequests.getRange(2,1,1,9));
closedRequests.getRange(2,9,1,1).setValue(new Date());
openRequests.deleteRow(line);
}
else
{
openRequests.getRange(line,1,1,9).copyTo(closedRequests.getRange(lastRowClose+1,1,1,9));
closedRequests.getRange(lastRowClose+1,9,1,1).setValue(new Date());
openRequests.deleteRow(line);
}
}
}
// ****** add lock code
lock.releaseLock();
// *** end
}
Questions:
1) how many people were using the spreadsheet at the time.
2) how often does it happen.

Categories