I am looking for a way to add and remove an image in a cell.
I have the button assigned to this function but I can't seem to add it to the dynamic range. If I hardcode the column and row for testing it adds the image fine but then I can't figure out how to delete it.
function test() {
var sheet = SpreadsheetApp.getActiveSheet();
var selection = sheet.getSelection();
var ranges = selection.getActiveRangeList().getRanges();
for (var i in ranges) {
var data = ranges[i].getValues();
for (var row in data) for (var col in data[row]) {
var cell = data[row][col];
if (cell == '') continue; // if empty --> go to next cell
IF CELL CONTAINS IMAGE REMOVE IT
continue; // --> go to next cell
} else {
sheet.insertImage("URL", [col], [row], 125, 2); //Add image at col/row
}
}
ranges[i].setValues(data);
}
}
Before button click
After button click
Select new cells
After button click
I believe your goal is as follows.
When the script is run after the cells are selected, you want to put the image on the cell.
When the image is not put on the cell, you want to put the image on the cell.
When the image has already been put on the cell, you want to remove the image.
When the cell value is empty, you don't want to do anything.
In this case, how about the following modified script?
Modified script:
function test() {
const url = "###"; // Please set your URL.
const sheet = SpreadsheetApp.getActiveSheet();
const ranges = sheet.getActiveRangeList().getRanges();
let images = sheet.getImages();
ranges.forEach(r => {
const row = r.getRow();
const col = r.getColumn();
const numRows = r.getNumRows();
const numCols = r.getNumColumns();
for (let i = 0; i < numRows; i++) {
for (let j = 0; j < numCols; j++) {
if (sheet.getRange(row + i, col + j).isBlank()) continue;
const image = images.filter(e => {
const anchor = e.getAnchorCell();
return anchor.getRow() == row + i && anchor.getColumn() == col + j;
});
if (image.length > 0) {
image.forEach(e => e.remove());
images = sheet.getImages();
} else {
sheet.insertImage(url, col + j, row + i, 125, 2);
}
}
}
});
}
At first, please set your URL.
When you use this script, please select the cells and run the script.
When you run this script for the selected cells, the images are put on the cells which have no images, and the images are removed from the cells which have the images.
In this case, the image on the cells can be checked using the method of getAnchorCell() of Class OverGridImage.
References:
getImages() of Class Sheet
getAnchorCell() of Class OverGridImage
Related
I need to display unique elements of already binded data in that html table by using JQuery or JavaScript. Displaying unique value means that mearging the cells having same value in the rows. The table data is dynamic but the structure is fix.
So, here is given table:
Here, I need to merge the Red colored cells as shown below.
And the required table is:
So, I need to achieve this cell merging through Jquery or javascript. As this table is created with HTML table and the data is already binded in it. By using this binded data I need to achieve the reqiured table. I need to merge more columns like this.
I have tried some coding but it is not working correctly. The code is:
jQuery('tr.tblRow').each(function(i, obj)
{
current_name = jQuery(obj).text();
var current_name_arr = current_name.split(/\t|\n| /);
/* check for repeated names */
if (current_name_arr[22] == last_selected_compNo)
{
jQuery("td.headingSpas:contains('" + current_name_arr[22] + "')").each(function(index, object)
{
if (index == 0)
{
/* check if already has rowspan attribtue */
row_span = jQuery(object).attr('rowspan') ? jQuery(object).attr('rowspan') : 1;
/* add one */
row_span++;
/* include the new rowspan number */
jQuery(object).prop('rowspan', row_span);
}
else if(index < 2)
{
/* delete the other first name cells */
jQuery(object).remove();
}
});
}
}
Please help me.
I have written my own solution for this problem. It work for me..
/*Merging rows Start (updated by Suraj)*/
/*Some changes are made in HTML table's body like adding 'id' property in each column of the table.*/
var row = 0;
var col = 0;
jQuery('tr.tblRow').each(function(n, obj) {
/*Getting the first row as text*/
current_name = jQuery(obj).text();
/*Splitting the above text value into an array using 'Regex' by '/t' and '/n'*/
var current_name_arr = current_name.split(/\t|\n/);
/*Now storing the element into an array for getting the values easily.*/
var current_name_arr1 = [];
var j = 0;
for(var i = 0; i < current_name_arr.length; i++) {
if(current_name_arr[i] == ""){}
else {
current_name_arr1[j] = current_name_arr[i];
j++;
}
}
/*Setting column*/
if(n == 0) {
col = current_name_arr1.length;
}
});
jQuery('tr.tblRow').each(function(n, obj) {
var ele = ""
var removingEle = "";
/*Merging the cells by spaning the cells and removing the duplicate cells*/
for(var l = 0; l < col - 1; l++) {
if(l == 4 || l == 5) {
continue;
}
/*Getting the element by id*/
ele = $("#pdtDetail" + row + l);
/*Getting the removing element by id*/
removingEle = $("#pdtDetail" + (row + 1) + l);
if(ele.text() == removingEle.text()) {
/* check if already has rowspan attribtue */
row_span = ele.attr('rowspan') ? ele.attr('rowspan') : 1;
/* add one */
row_span++;
/* include the new rowspan number */
ele.prop('rowspan', row_span);
/* delete the other first name cells */
removingEle.remove();
}
}
/*If element get matched then increasing row by two because we have to leave the just after commming row.*/
if(ele.text() == removingEle.text()) {
row = row + 2;
}
else {
row++;
}
});
/*Merging rows End*/
The Final Table looks like as:
I apologize in advance for having little to no knowledge on this matter. I am familiar enough to utilize VBA but have recently made the switch to Sheets and I am lost.
I was originally looking for a way to prompt a drop down menu when double clicking a cell in a range that will then add the selected information as a prefix to the text.
Example: cell contains "First Last", upon double clicking you get a drop down to select "Mr., Mrs." when selecting "Mr." the cell now says "Mr. First Last" but it doesn't appear that you can set a double click event.
So now I am trying to come up with another solution where you select desired cells and 'apply' the function.
Example: Select cells A1 B1 C3 D9, click a button that applies "Mr. " as a prefix. Selecting it again will remove it.
Please help me get this moving.
Try this:
// menu
function onOpen() {
SpreadsheetApp.getUi().createMenu('⚡ Scripts')
.addItem('🎩 Add Mr', 'add_Mr')
.addItem('Remove Mr', 'remove_Mr')
.addToUi();
}
// functions
function add_Mr() {
var sheet = SpreadsheetApp.getActiveSheet();
var selection = sheet.getSelection();
var ranges = selection.getActiveRangeList().getRanges();
for (var i in ranges) {
var data = ranges[i].getValues();
for (var row in data) for (var col in data[row])
if (data[row][col] != '') data[row][col] = 'Mr. ' + data[row][col];
ranges[i].setValues(data);
}
}
function remove_Mr() {
var sheet = SpreadsheetApp.getActiveSheet();
var selection = sheet.getSelection();
var ranges = selection.getActiveRangeList().getRanges();
for (var i in ranges) {
var data = ranges[i].getValues();
for (var row in data) for (var col in data[row])
if (data[row][col] != '') data[row][col] = data[row][col].replace(/^Mr\. /,'');
ranges[i].setValues(data);
}
}
It will add menu Scripts and two commands 'Add Mr' and 'Remove Mrs' for selected cells.
And as a homework you can try to add add_Mrs() and remove_Mrs() functions.
If you need to toggle 'Mr' here you go:
function toggle_Mr() {
var sheet = SpreadsheetApp.getActiveSheet();
var selection = sheet.getSelection();
var ranges = selection.getActiveRangeList().getRanges();
for (var i in ranges) {
var data = ranges[i].getValues();
for (var row in data) for (var col in data[row]) {
var cell = data[row][col];
if (cell == '') continue; // if empty --> go to next cell
if (cell.match(/^Mr\. /)) { // if contains 'Mr.'
data[row][col] = cell.replace(/^Mr\. /,''); // --> remove 'Mr.'
continue; // --> go to next cell
} else {
data[row][col] = 'Mr. ' + data[row][col]; // else --> add 'Mr.'
}
}
ranges[i].setValues(data);
}
}
Update
Here is the same function toggle_Mr() with example how you can get the 'coordinates' of all processed cells:
function toggle_Mr() {
var sheet = SpreadsheetApp.getActiveSheet();
var selection = sheet.getSelection();
var ranges = selection.getActiveRangeList().getRanges();
for (var i in ranges) {
// get 'coordinates' (col, row) of first (left-top) cell of selected range
var start_col = ranges[i].getColumn();
var start_row = ranges[i].getRow();
var data = ranges[i].getValues();
for (var row in data) for (var col in data[row]) {
var cell = data[row][col];
// calculate the real 'coordinates' of processed cells
var real_col = +start_col + +col;
var real_row = +start_row + +row
console.log('Process the cell [' + real_col + '][' + real_row + ']');
if (cell == '') continue;
if (cell.match(/^Mr\. /)) {
data[row][col] = cell.replace(/^Mr\. /,'');
continue;
} else {
data[row][col] = 'Mr. ' + data[row][col];
}
}
ranges[i].setValues(data);
}
}
You can see the cell 'coordinates' in console if you run the function from the Script Editor.
I'm working on a script which takes text and places each paragraph in a numbered table cell. I'm running into a problem where each line break is counted as a paragraph by the script, which means my table either has empty cells or is numbered incorrectly.
Here's the working script (minus row numbering):
function formatArticle() {
var doc = DocumentApp.getActiveDocument()
var body = doc.getBody();
// Get the paragraphs
var paras = body.getParagraphs();
// Add a table to fill in with copied content
var addTable = body.appendTable();
for (var i=0;i<paras.length;++i) {
// If the paragraph is text, add a table row and insert the content.
if(i % 2 == 0) {
var tr = addTable.appendTableRow();
var text = paras[i].getText();
// Number the table rows as they're added in a cell to the left.
for(var j=0;j<2;j++) {
if(j == 0) {
var td = tr.appendTableCell(i);
} else {
var td = tr.appendTableCell(text);
}
}
}
// Shrink left column.
addTable.setColumnWidth(0, 65);
// Delete the original text from the document.
paras[i].removeFromParent();
}
}
Here's a demo Google Doc so you can see how text formats without setting a new one up yourself if that helps.
Logic
What you should do is to iterate each paragraph and check if that paragraph contains text. If yes, then add a row and put the text in it, else skip that paragraph and jump to the next one.
Implementation
function formatArticle(){
var doc = DocumentApp.getActiveDocument()
var body = doc.getBody();
// Get the paragraphs
var paras = body.getParagraphs();
var addTable = body.appendTable();
//paragraph index
var pIndex = 0;
for(var i = 0 ; i < paras.length ; i++){
var para = paras[i];
var paraStr = para.editAsText().getText();
// if there is string content in paragraph
if(paraStr.length){
var tr = addTable.appendTableRow();
var td1 = tr.appendTableCell(pIndex);
var td2 = tr.appendTableCell(paraStr);
pIndex ++;
}
para.removeFromParent();
}
// Shrink left column.
addTable.setColumnWidth(0, 65);
}
Here You get the string from paragraph var paraStr = para.editAsText().getText(); and check if the content exists if(paraStr.length) If yes then create a row, insert paragraph index and paragraph's text in it.
Try this: tr.appendTableCell(i/2 +1)
// Number the table rows as they're added in a cell to the left.
for(var j=0;j<2;j++) {
if(j == 0) {
var td = tr.appendTableCell(i/2 +1);
} else {
var td = tr.appendTableCell(text);
}
}
}
//loops through all rows and cells and saves them into local storage as objects
window.onbeforeunload = function() {
var rows = document.getElementById('firsttable').tBodies[0].rows;
for (var i = 0; i < rows.length; i += 1) {
localStorage.setItem(i, JSON.stringify({
Item: rows[i].cells[0].innerHTML,
filling1: rows[i].cells[1].innerHTML,
filling2: rows[i].cells[2].innerHTML,
filling3: rows[i].cells[3].innerHTML,
Stock: rows[i].cells[4].innerHTML,
min: rows[i].cells[5].innerHTML,
sold: rows[i].cells[6].innerHTML,
closeAcc: rows[i].cells[7].innerHTML,
sell: rows[i].cells[8].innerHTML,
dltButton: rows[i].cells[9].innerHTML
}));
};
};
//loads the objects into rows with the values in their cells
window.onload = function() {
var r = 0,
c = 0;
//load the actual data from localstorage into html rows
for (x in localStorage) {
var row = table.insertRow(r),
obj = JSON.parse(localStorage.getItem(x));
for (i in obj) {
var cell = row.insertCell(c);
cell.innerHTML = obj[i];
c += 1
}
r += 1;
c = 0;
}
};
//where the problem is
$(function() {
$('table td').click(function(e) {
if (e.target.id === "Sellbtn") {
var sell = prompt("Enter the amount");
for (var i = 0; i < table.length; i += 1) {};
this.parentNode.parentNode.cells[4].innerHTML = parseInt(this.parentNode.parentNode.cells[4].innerHTML) - sell; //not working and no when put inside the for loop it doesn't work idk why
} else if (e.target.id === "Deletebtn") {
return false;
} else {
var ask = prompt("Input");
$(this).html(ask);
}
});
});
So i insert a row and add the details to the cells and such then as explained in the snippet the first function saves available the rows and cells into a JSON stringified object in the localstorage when the user is closing the browser and then loads them up during onload the problem is with the buttons idk how to make them function after the onload(user closes and opens again). So imagine this you have your HTML table with several rows and their cells and each row has the two buttons(sell and delete) how do i make them function when the user opens up the application again? and btw the buttons are both dynamically added using createElement() when the row is originally added
Try delegating the click event you have on your table rows since they're being created after the DOM loads:
$('table').on("click", "td", function(e) {
I think that the title is self-explanatory. I am retrieving data using XMLHttpRequest and the data is getting appended into columns of a table. I decided to only allow a row to have only 4 columns inside it and if another item exists then it should be appended into another row. This is what I have done:
//...
//unneccessary
//...
var album_photos = JSON.parse(xhr2.responseText);
for(var i = 0; i < album_photos.length; i++) {
if(!isInArray(album_photos[i].Image_ID, image_ids)) {
var tr = document.getElementById("tiare");
if(i % 4 == 0) {
tr = document.createElement("tr");
document.getElementById("images").appendChild(tr);
}
//...
//creating elements to be append
//...
tr.appendChild(td);
td.appendChild(imagewrap);
imagewrap.appendChild(imagemenu);
imagemenu.appendChild(imagemenuimg1);
imagemenu.appendChild(imagemenuimg2);
imagewrap.appendChild(imagewrapimg);
image_ids.push(album_photos[i].Image_ID);
//...![enter image description here][1]
//unneccessary
//...
And this is the markup:
<table width="80%" id="images">
<tr id="tiare">
</tr>
</table>
See how it's not getting splitted correctly:
How can I achieve this, my logic is not working at all! What should I do?
P.S: No jQuery solution allowed. :)
Any help would be appreciated. Thanks in advance. :)
UPDATE: I changed my code into this:
function getAlbumImages() {
var xhr2 = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
xhr2.open('GET', 'admin/images_data.php');
xhr2.onreadystatechange = function(e) {
if(xhr2.readyState == 4 && xhr2.status == 200) {
var oldtable = document.getElementById("images");
var newtable = oldtable.cloneNode();
var tr = document.createElement("tr");
var album_photos = JSON.parse(xhr2.responseText);
for(var i = 0; i < album_photos.length; i++) {
if(!isInArray(album_photos[i].Image_ID, image_ids)) {
if(i%4 == 0 && i != 0){
newtable.appendChild(tr);
tr = document.createElement('tr');
}
var td = document.createElement('td');
var imagewrap = document.createElement('div');
imagewrap.className = "image-wrap";
var imagemenu = document.createElement('div');
imagemenu.className = "image-menu";
var imagemenuimg1 = document.createElement('img');
imagemenuimg1.src = "img/edit_img.png";
var imagemenuimg2 = document.createElement('img');
imagemenuimg2.src = "img/close.png";
var imagewrapimg = document.createElement('img');
imagewrapimg.className = "thumbnail";
imagewrapimg.src = "admin/album_photos/" + album_photos[i].Image_Path;
imagewrapimg.onclick = function() { showBigImage(this); };
tr.appendChild(td);
td.appendChild(imagewrap);
imagewrap.appendChild(imagemenu);
imagemenu.appendChild(imagemenuimg1);
imagemenu.appendChild(imagemenuimg2);
imagewrap.appendChild(imagewrapimg);
image_ids.push(album_photos[i].Image_ID);
} else {
continue;
}
}
newtable.appendChild(tr);
oldtable.parentNode.replaceChild(newtable, oldtable);
}
}
xhr2.send(null);
}
This function is called inside an setInterval with 5000 milliseconds break.
The problem coming now is that it disappears after 5 seconds. How can I resolve that?
The first problem I see is that i and i % 4 is not the images in your table, it's the images in the returned data. The two will differ as soon as you encounter an image already in your array. You need to use an index for the i % 4 that is the actual number of images in the table. You could use a separate count of how many images are in the table that you intialize with:
var imageCnt = document.getElementById("images").getElementsByTagName("td").length
And, the increment that any time you add an image to the table and then check %imageCnt % 4 to decide when to add a new row.
Then, don't you want to be adding images to the LAST row in the table, not the first row in the table because that's where the extra slots will be and where the new empty row goes. You will be adding images to the last row when you've just created a new row, but not when your last row is partially filled when you start. In that case, you'll be adding images to the first row. You can start with the last row
var table = document.getElementById("images");
var lastRow = table.rows[table.rows.length - 1];
Applying these to your first example of code would work like this:
//...
//unneccessary
//...
var album_photos = JSON.parse(xhr2.responseText);
var table = document.getElementById("images");
var tableBody = table.getElementsByTagName("tbody")[0];
var lastRow = table.rows[table.rows.length - 1];
// initialize cell count
var cellCount = table.getElementsByTagName("td").length;
for(var i = 0; i < album_photos.length; i++) {
if(!isInArray(album_photos[i].Image_ID, image_ids)) {
if (cellCount % 4 == 0 && cellCount !== 0) {
// make new row and append it to the table body
lastRow = document.createElement("tr");
tableBody.appendChild(lastRow);
}
//...
//creating elements to be append
//...
td.appendChild(imagewrap);
imagewrap.appendChild(imagemenu);
imagemenu.appendChild(imagemenuimg1);
imagemenu.appendChild(imagemenuimg2);
imagewrap.appendChild(imagewrapimg);
// best to append the new cell when it's fully formed
lastRow.appendChild(td);
++cellCount;
image_ids.push(album_photos[i].Image_ID);
//...![enter image description here][1]
//unneccessary