I am trying to add text to each cell in particular column via Javascript. Like every 8th TD would be processed for adding text.
Tell me what I have done wrong here/why it doesn't appear in my table:
<script type="text/javascript">
window.onload = function inventorytable() {
var tableRows = document.getElementById
("inventorytable").getElementsByTagName("tbody")[0].getElementsByTagName("tr");
for(var i = 0, l = tableRows.length; i < l; i++) {
tds = tableRows.getElementsByTagName("td");
var processor = tds[8].innerHTML += " Ghz"
var ram = tds[9].innerHTML += " GB"
var rspeed = tds[11].innerHTML += " Mhz"
}}
</script>
You've forgotten to refer to the i-th row:
tds = tableRows[i].getElementsByTagName("td");
I recommend to use:
window.onload = function inventorytable() {
var tableRows = document.getElementById("inventorytable").rows;
//or .tBodies[0].rows
for(var i=0, l=tableRows.length; i < l; i++) {
var tds = tableRows[i].cells;
/*processor*/ tds[8].innerHTML += " Ghz"
/*ram */ tds[9].innerHTML += " GB"
/* rspeed */ tds[11].innerHTML += " Mhz"
}
}
Do not define unused variables. If you want to clarify their use, use comments.
Also, I have replaced .getElementsByTagName by .rows and .cells.
Update
JavaScript sets are zero-based. So, if you want to refer to the 4th cell, use .cells[3].
At your previous answer, you've showed a fiddle. see http://jsfiddle.net/ndfh2/.
As you can see, the first row is also getting postfixes. To not add postfixes to these cells in the first row, initiate the counter at one: for( var i=1; .. ; .. )
Your current code does probably not work, because your rows don't have twelve (12) rows. Remember, the number at tds[ number ] equals the index of a cell within a row, starting at zero.
Related
I want to take a string from a cell and examine it for keywords. These keywords should then be marked Bold and the complete string should be returned with the Bold marked keywords. Here is an example:
=boldKeywords("I am an example text", "text")
Result: I am an example text.
The script works so far. I am just not possible to make the keywords bold. This should happen here: "//splitString[i] should be set bold". Here is the script:
function boldKeywords(text, keywords) {
// Split the test and the keywords into an Array with single Strings
var splitString = text.split(" ");
var splitKeywords = keywords.toUpperCase().split(", ");
//Go through the array and compare each word to the keywords
for(var i = 0; i < splitString.length; i++){
for(var j = 0; j < keywords.length; j++){
if(splitString[i].toUpperCase().localeCompare(splitKeywords[j]) == 0){
//splitString[i] should be set bold
}
}
}
//Concatenate Array Sting to one String
var retunString = "";
for(var j = 0; j < splitString.length; j++) {
retunString = retunString + " " + splitString[j];
}
//return String
return retunString;
}
To make parts of a cell content bold, you need to use RichText
As mentioned by Marios, you cannot use RichText in a custom formula, so you have to modify your set-up a bit.
for example, you can write your key word(s) into a free cell (e.g. A1) and create a custom button to which you can assign the following script:
function boldKeywords() {
var cell = SpreadsheetApp.getActive().getActiveSheet().getActiveCell();
var text = cell.getValue();
var keywords = SpreadsheetApp.getActive().getActiveSheet().getRange("A1").getValue();
// Split the test and the keywords into an Array with single Strings
var splitString = text.split(" ");
var splitKeywords = keywords.toUpperCase().split(", ");
var value = SpreadsheetApp.newRichTextValue();
value.setText(text);
var position = 0;
for(var i = 0; i < splitString.length; i++){
for(var j = 0; j < splitKeywords.length; j++){
if(splitString[i].toUpperCase().localeCompare(splitKeywords[j]) == 0){
var start = text.indexOf(splitString[i], position)-1;
var end = start + splitString[i].length+1;
var bold = SpreadsheetApp.newTextStyle().setBold(true).build();
value.setTextStyle(start, end, bold);
}
}
position += splitString[i].length+1;
}
var values = value.build();
cell.setRichTextValue(values);
}
This script will mark all the keywords bold for the cell that is being selected at the moment you press on the button.
Note that if you expect to encounter more than once in a cell, it is important to define position to correctly highlight all instances of a keyword as bold.
Unfortunately, custom functions can not return formatted data.
This issue has been reported already in the IssueTracker. You can click on the star button to the top left of the page to increase the chances of this feature to be implemented by Google.
Potential workarounds:
You can create a button/menu to execute a regular function that will be able to set the format and the value of the selected cell.
You can use an onEdit() trigger to set the format and the value of the cell when you edit that cell or when you click on a checkbox for example.
You can set up a time-driven trigger to change the format of the cell when the cell hasn't been formatted properly.
I have a script that creates a table with specifications given by the user.
The issue is that when the table is printed more than once, it prints below the other table. Turning a 10x10 table into a 10x20 table. (if that makes sense)
In previous assignments I used:
//Clean grid
while(grid.firstChild)
grid.removeChild(grid.firstChild);
to clear the grid, but this assignment is using jQuery and I am not sure how to do it. I've tried:
var divBlock = document.getElementById('my_table');
while (divBlock.firstChild) {
divBlock.removeChild(divBlock.firstChild);
and
$("#my_table").empty();
and
$("#my_table").remove();
and
$('#my_table').remove('table');
but neither seem to work, here is the full code:
// TODO: clear table
var $rows = $("#rows");
var $cols = $("#cols");
var $print_button = $("#print");
var $my_table = $("#my_table");
var $stats = $("#stats");
var arr = [];
var $table_obj = $('<table>'); //Create an element
var $row_obj;
var $col_obj;
var counter = 0;
$print_button.on('click', function() {print_pattern();});
function print_pattern()
{
// Clear table
// var divBlock = document.getElementById('my_table');
// while (divBlock.firstChild) {
// divBlock.removeChild(divBlock.firstChild);
// }
// $("#my_table").empty();
$('#my_table').remove('table');
// Get row and column values
var r = $rows.val(); //Get value of rows
element
var c = $cols.val(); //Get value of cols element
// Create 2-D Array
for (var i = 0; i < r; i++) {
arr[i] = [];
}
// Double for-loop to create table
for (var i = 0; i < r; i++) {
$row_obj = $('<tr>'); // Create row
for (var j = 0; j < c; j++) {
$col_obj = $('<td>'); // Create table cell
var n = Math.floor(Math.random()*10000)%100; //Math methods:
floor and random
$($col_obj).append(n); // Append random number to table cell
$($row_obj).append($col_obj); // Append column to row
$($table_obj).append($row_obj); // Append row to table object
// if random number > 90 -> make background color yellow
if (n > 90) {
$col_obj.css('background-color', 'yellow'); //Change css
counter++; // counter for stats
}
}
$($table_obj).append($row_obj); // Append row to table object
}
$($my_table).append($table_obj); // Append table to div container
// Stats calculation
$stats.html("<b>" + (counter/(r*c)*100).toFixed(2) + "%<b>");
//Change html content
counter = 0; // reset counter
// event function for removing a row when its clicked on
$('tr').on('click', function(){ $(this).fadeOut(500); });
}
So I've tried a number of things, I am not sure if I am just getting the syntax wrong or if I am using the wrong function to clear the div tag.
If anyone can point me in the right direction that would help a lot!
Thank you.
EDIT: I figured out the issue. My original while() block worked fine when I put all the variables inside the function.
First of all, you have to distinguish variables.
A. There is a variable that has to define 1 time, and any changes will
be stored on that.
B. And there is a variable that needs to be reset every function
called.
variable on condition b you need put inside your function so it won't keep last value and make it has double value (last value + new value)
in this case i could say this variable is on condition b:
$table_obj, $row_obj, $col_obj, arr, ...
I draw a table (through datatable) and I would need to retrieve some specific data depending on certain conditions.
here is the table:
tom
dsdsdsds
oo
60
jones
aa
oo
61
I need to parse each tr elements, and if the td input type checkbox contains the class selected, I need to retrieve the value of td with id="id" (of the same tr).
I tried to do the following:
var nbr_lignes = document.getElementById('datatable-table').rows.length;
var i = 0;
var j = 0;
while(i < nbr_lignes){
j=0;
console.log("ligne: "+i);
var nbr_colonnes = document.getElementById('datatable-table').getElementsByTagName('tr')[i].getElementsByTagName('td').length;
console.log("nb colonnes: "+nbr_colonnes);
while(j < nbr_colonnes){
console.log("contenu td: "+document.getElementById('datatable-table').getElementsByTagName('tr')[i].getElementsByTagName('td')[j].
innerHTML);
j++;
}
i++;
}
so I can parse each td of each tr but I don't know how to check if the current td contains the class selected and in that case retrieve the value of the td id="id"
I would appreciate if you can help me.
Here is a simple solution: you're making a counter and iteration through every line ( tr ), whenever you find input.selected inside it, you are asking for value of the div with id of a counter. The result is stored in found table.
https://jsfiddle.net/prowseed/80rmcjgu/19/
var idx = 1;
var found = [];
var trs = [].slice.call(document.querySelectorAll('table tr'));
trs.forEach(function(tr){
var isSelected = (tr.querySelector('input')).classList.contains('selected');
console.log(isSelected);
if(isSelected){
console.log(document.getElementById('id'+idx));
var value = (document.getElementById('id'+idx)).innerText;
found.push({id: idx, value: value});
}
idx++;
});
(document.getElementById('result')).innerHTML = found.reduce(function(p, c){ return p + ' \n ' + c.id + ':' + c.value }, '');
So I'm trying to just make a ".replace" loop, but something mysterious is happening.
var cell = "r1c1";
for (i = 0; i <= 4; i++){
cell = cell.replace(cell[3],i+1);
My expected output:
cell = "r1c1"
cell = "r1c2"
cell = "r1c3"
cell = "r1c4"
cell = "r1c5"
The actual output:
cell = "r1c2"
cell = "r2c1"
cell = "r2c3"
cell = "r2c4"
cell = "r2c5"
As you can see, it runs normal EXCEPT for the second iteration.
What in the world am I doing so wrong?
cell.replace(cell[3], i+1) is going to replace the first instance of the '1' character it finds in the string 'r1c1'. In this case it is the '1' at position 1 that gets replaced instead of the '1' at position 3.
To get the results you want, try
var cell = "r1c1";
for (i = 0; i <= 4; i++){
cell = cell.substring(0, cell.length-1)+(i+1);
}
You can use a regular expression: /^r(\d+)c(\d+)/:
var row_col = 'r1c1';
var match = /^r(\d+)c(\d+)/.exec(row_col); // match string
var row = +match[1]; // extract row
var col = +match[2]; // extract column
// edit row and col as needed
row_col = 'r' + row + 'c' + col; // "reassemble" string
This will take care of bigger row/column numbers than 9. If that is not to be expected, then read about String.prototype.substring():
var row_col = 'r1c1';
var row = +row_col.substring(1,2);
var col = +row_col.substring(3,4)
I don't like this, but the fix I ended up using looks like this:
cell = "r"+(j)+cell.substr(2,2);
Since I'm inevitably answering my own question, here, I still want to ask for comments:
How elegant would you say a solution like this is in the long run?
I created a table in my HTML code. It has 9 columns and 13 rows. It gets filled up completely by a JavaScript loop that fills it with names of people from a few arrays. However, I want to add a validation step that makes sure that no two cells within a row hold the same value and that the value of a each cell does not repeat in the cell directly beneath it.
Since I am only able to access the values of the cells of the table as a NodeList, I decided to make it into an array to use the IndexOf property to search through the array:
var table1 = document.getElementsByTagName("td");
var table1Array = []; //number of "td" elements on page
for (i = 0; i < 117; i++) {
table1Array[i] = table1[i].innerHTML;
}
I don't know of a more elegant method (sort of a beginner here). So I set up some nested loops to compare each cell to each element in the row array I create (for all 13 rows):
function validateCells() {
for (i = 0; i < 117; i = i + 9) { //increment for going to next column (after 9 cells or elements in array)
for (j = 0; j < 8; j++) {
var curCell = table1Array[i];
var curRow = []; //I'm ignoring the first column which is "date", so it has 8 elements rather than 9
for (k = 0; k < 8; k++) {
curRow[k] = document.getElementById("row" + j).children[k].innerHTML;
}
if (curRow.indexOf(curCell) != -1) {
curCell = "CONFLICT"; //trying to change value in table. Doesn't work.
}
}
}
}
Unfortunately, this won't work. I don't even know if modifying the value of the curCell reference variable will actually change the value of the table1Array at that location, even less if it will change the data in the table.
Am I using the indexOf property correctly? Do I use the != comparison operator or !==? Does indexOf return the index as a Is there any other less complicated, more elegant to do this? I just started with jQuery, maybe it can help simplify the code and make it less error-prone.
Sorry for the all the questions, I'm really trying to understand how all of this works. Thanks!
You should get an array of rows, each row is an array of cells. That way the validation is much easier. I'm not sure about how you want to show the conflict. In this demo I've just highlight the duplicated cells (conflicted) in red (at least I like this kind of showing conflict rather than modifying the conflicted cells' text).
HTML:
<table>
<tr><td>1</td><td>2</td><td>3</td></tr>
<tr><td>1</td><td>5</td><td>6</td></tr>
<tr><td>7</td><td>8</td><td>7</td></tr>
<tr><td>8</td><td>9</td><td>10</td></tr>
</table>
<button>Check constraints</button>
CSS:
td {
width:100px;
height:50px;
border:1px solid black;
}
table {
border:1px solid black;
border-collapse:collapse;
}
td.invalid {
background:red;
}
JS:
$('td').attr('contenteditable',true);
var cell;
function highlight(){
$(arguments).toggleClass('invalid',true);
}
function checkConstraints(e){
//reset style before re-checking
$('td.invalid').toggleClass('invalid');
//get rows as an array of array
var rows = $('tr').map(function(elem,i){
return [$(this).children('td').toArray()];
}).toArray();
//loop through the rows
for(var i = 0; i < rows.length; i++){
cell = {};
for(var j = 0; j < rows[i].length; j++){
var cellText = $(rows[i][j]).text();
if(cell[cellText]) {
highlight(cell[cellText], rows[i][j]);
} else {
cell[cellText] = rows[i][j];
}
if(i < rows.length - 1 &&
cellText == $(rows[i+1][j]).text()){
highlight(rows[i][j],rows[i+1][j]);
}
}
}
}
$('button').click(checkConstraints);
Demo.
Note that, I set contenteditable for all the cells (td), you can edit the cells text to what you want and click the button to test the demo.
You can use the table rows and cells collections for the iteration. The following does a literal comparison of the text content, you may wish to process the text first to "normalise" it in regard to whitespace.
<table id="t0">
<tr><td>foo<td>bar<td>fum</td>
<tr><td>fum<td>bar<td>foo</td>
<tr><td>foo<td>fum<td>fum</td>
</table>
<script>
compareRows(document.getElementById('t0'));
function compareRows(table) {
var row, rows = table.rows;
var cell, cells;
var rowText;
// For each row in the table
for (var i=0, iLen=rows.length; i<iLen; i++) {
row = rows[i];
cells = row.cells;
// Compare the text in each cell
for (var j=0, jLen=cells.length; j<jLen; j++) {
cell = cells[j];
for (var k=0; k<jLen; k++)
if (k != j && cells[k].textContent == cell.textContent) {
// cell text is repeated in current row
console.log('row ' + i + ' cell ' + j + ' text repeated in cell ' + k);
}
// Compare with the text in the cell immediately below (if there is one)
if (i < iLen-2 && cell.textContent == rows[i+1].cells[j].textContent) {
// cell text is repeated in next row
console.log('row ' + i + ' cell ' + j + ' text repeated in row ' + (i+1));
}
}
}
}
</script>
Note that repeated text in a row will be reported twice.
The above uses the textContent property, which may be supported as innerText in some user agents. It also runs about 10 times faster than the jQuery alternative.