Generate new table when searching - javascript

I am trying to generate a table from an array with a searching feature. With every letter typed in the search bar the items that contain that specific string will be displayed.
I have come to the conclusion to generate the whole table with every keystroke rather than editing the current.
This is where I am at:
What´s currently typed in the searchbar:
let searchBar = document.getElementById('search-input');
let value = " ";
searchBar.addEventListener(`keyup`, function(){
value = this.value
How I make the table:
let tableUsers = document.getElementById("tabell");
function drawTable() {
let table = document.createElement("table");
let tableHead = document.createElement("thead");
let colHeads = ["Name"];
for (let header of colHeads) {
let cell = document.createElement("th")
cell.innerHTML = header;
tableHead.appendChild(cell);
}
table.appendChild(tableHead)
for (let x of people) {
let row = document.createElement("tr");
let name = document.createElement("td");
name.innerHTML = x.name.first + "&nbsp" + x.name.last;
row.appendChild(name);
table.appendChild(row);
}
tableUsers.appendChild(table);
}
drawTable()
I am trying this:
let str = x.name.first.toLowerCase()
if (str.includes(value)){
//code
}
Is it possible to do it this way? Or possible at all using JS and large arrays without using a lot of pc resources?
Any help is greatly appreciated!

Inside if statement, you need to create new array then push the values inside it then you can pass a new people as a parameter to drawTable function and call it like drawTable(people)

Related

What is the quickest way to navigate an xml document in JS?

I am working with a semi-large xml document (~4000 elements each with 30 sub nodes) and was wondering what the fastest way to pull the data is. Currently, my code is taking about 4 seconds to run, which isn't terrible, but it could be better.
I know with sql databases you can use Ordinals to get integer values to pull from the table due to string look-ups being inefficient and I was wondering if there is any way to do this with XML. Or if there is anything else I can look into / try.
My current implementation is pulling each value using .getElementsByTagName
root[i].getElementsByTagName('FirstName')[0].childNodes[0].nodeValue);
Edit: show full code
I am pretty much just copy pasting that for all the nodes in each element. Note: there are a lot more elements, but it is the exact same implementation.
const AddUserData_Response = (xml) =>{
let xmlDoc = xml.responseXML;
let root = xmlDoc.getElementsByTagName('User');
let table = document.getElementsByClassName(activityTab + "-table-body")[0];
for (let i = 0; i < root.length; i++) {
let row = document.createElement("tr");
CreateTableElement(row, root[i].getElementsByTagName('LastName')[0].childNodes[0].nodeValue);
CreateTableElement(row, root[i].getElementsByTagName('FirstName')[0].childNodes[0].nodeValue);
CreateTableElement(row, root[i].getElementsByTagName('MiddleInitial')[0].childNodes[0].nodeValue);
CreateTableElement(row, root[i].getElementsByTagName('ID')[0].childNodes[0].nodeValue);
CreateTableElement(row, root[i].getElementsByTagName('Title')[0].childNodes[0].nodeValue);
table.insertBefore(row, table.children[0]);
}
}
const CreateTableElement = (row, value) => {
let cell = document.createElement("td");
if (value != "None" && value != undefined) {
cell.innerText = value;
}
row.appendChild(cell);
}

Excel AddIn - Adding rows to an existing table

I'm having some troubles while using the Javascript Excel API to create an Excel AddIn.
First issue:
Adding rows to an existing table with the Excel Js library: I create a table and add some rows; then the user can update table content with new data coming from a REST service (so resulting table rows can change: increase / decrease, or be the same).
tl;dr; I need to replace table rows with new ones.
That seems pretty simple: there's a addRows method in Table namespace (reference).
But this won't work as expected: if the table already contains rows new ones will be added to the end, not replacing the existing ones.
Here the code:
const currentWorksheet = context.workbook.worksheets.getItemOrNullObject(
"Sheet1"
)
let excelTable = currentWorksheet.tables.getItemOrNullObject(tableName)
if (excelTable.isNullObject) {
excelTable = currentWorksheet.tables.add(tableRange, true /* hasHeaders */)
excelTable.name = tableName
excelTable.getHeaderRowRange().values = [excelHeaders]
excelTable.rows.add(null, excelData)
} else {
excelTable.rows.add(0, excelData)
}
I also tried to delete old rows, then adding new ones.
if (!excelTable.isNullObject) {
for (let i = tableRows - 1; i >= 0; i--) {
// Deletes all table rows
excelTable.rows.items[i].delete()
}
excelTable.rows.add(0, excelData)
}
But .. it works fine only if there isn't content below the columns of the table (no functions, other tables and so on).
I tried another method: using ranges.
The first time I create the table, next ones I delete all rows, get the range of new data and insert the values:
if (excelTable.isNullObject) {
excelTable = currentWorksheet.tables.add(tableRange, true /* hasHeaders */)
excelTable.name = tableName
excelTable.getHeaderRowRange().values = [excelHeaders]
excelTable.rows.add(null, excelData)
} else {
let actualRange, newDataRange
const tableRows = excelTable.rows.items.length
const tableColumns = excelTable.columns.items.length
const dataRows = excelData.length
const dataColumns = excelData[0].length
actualRange = excelTable.getDataBodyRange()
for (let i = tableRows - 1; i >= 0; i--) {
// Deletes all table rows
excelTable.rows.items[i].delete()
}
newDataRange = actualRange.getAbsoluteResizedRange(dataRows, tableColumns)
newDataRange.values = excelData
}
But there are still drawbacks with this solution.
It needs to be so hard to add/edit/remove rows in an Excel table?
Second issue:
Using the same table, if the user decides to add some 'extra' columns (with a formula based on table values e.g.), do I need to fill this new columns with null data?
const tableColumns = excelTable.columns.items.length
const dataRows = excelData.length
const dataColumns = excelData[0].length
if (tableColumns > dataColumns) {
let diff = tableColumns - dataColumns
for (let i = 0; i < diff; i++) {
for (let j = 0; j < dataRows; j++) {
excelData[j].push(null)
}
}
}
Excel API can't handle this scenario?
Please, could you help me?
Thank you in advance.
Thanks for your reporting.
Add table row API is just adding row to the table rows, not replace it.
What's more. I can't repro the issue with delete rows. Can you show me more details?

Replace text in a Google Sheet and maintaining formulas

I have a Google Sheet that I would like to use as a template. A user submits a Form and a OnFormSubmit trigger makes a copy of the template and replaces certain text with the answers. I would like to use this in several applications and the locations of these text fields may change, so I would rather not specify a specific range or Named range for every replacement.
Using some tidy code from this question I can do exactly what I want. Except, formulas that I have in the template are removed using this method. In other words, a cell in the template has =E10*F10 but after the replacement the value is either blank or 0.
Is it possible to fix this within the code that I have? I can't find a solution except to try a different approach perhaps...
function replacetext(target,key,value){
var spread_sheet = SpreadsheetApp.open(target)
var sheet = spread_sheet.getSheetByName('Sewage Flows');
replaceInSheet(sheet,key,value);
}
function replaceInSheet(sheet, to_replace, replace_with) {
//get the current data range values as an array
var values = sheet.getDataRange().getValues();
Logger.log("values: " + values)
//loop over the rows in the array
for(var row in values){
//use Array.map to execute a replace call on each of the cells in the row.
var replaced_values = values[row].map(function(original_value){
return original_value.toString().replace(to_replace,replace_with);
});
//replace the original row values with the replaced values
values[row] = replaced_values;
}
//write the updated values to the sheet
sheet.getDataRange().setValues(values);
}
This isn't the best solution, it seems really inefficient but it works. I changed the approach from grabbing all values using getValues() to just getDataRange()
Then I just check for a formula and skip those cells. Maybe there is a better way.
function replacetext(target,key,value){
var spread_sheet = SpreadsheetApp.open(target)
var sheet = spread_sheet.getSheetByName('Sewage Flows');
replaceInSheet(sheet,key,value);
}
function replaceInSheet(sheet, to_replace, replace_with) {
//get the current data range values as an array
var range = sheet.getDataRange();
var LastRow = range.getLastRow();
var LastCol = range.getLastColumn();
for(var i=0; i<= LastRow; i++){
for(var k=0; k<= LastCol; k++){
var formula = sheet.getRange(i+1,k+1).getFormula();
if(formula == ""){
var old_value = sheet.getRange(i+1,k+1).getValue().toString()
var new_value = old_value.replace(to_replace,replace_with);
Logger.log("old, new: " + old_value + ", " + new_value);
sheet.getRange(i+1,k+1).setValue(new_value);
}
}
}
}

Create an array from JSON in Javascript

I've researched quite a bit on here and I can't seem to find something that will work for me. What I have is an application that I'm trying to have go out and return the next four bus arrival times for a bus stop. I am reaching out to an API that returns this data in a JSON file. The problem I am having is I can see my request go out via fiddler but I can't seem to get the data into an array. Below is the code that I'm dealing with right now. I'm trying to get the returned data into a table format which you can see I'm failing at.
Eventually I want to get a popup to appear when the user clicks on the Show me the next 4 bus arrival times but this was for testing purposes. I would love to have the users click on my button which calls this function and then something like a like table open with these values. If you can help with that within this code I would appreciate it as well.
JSON Data:
[{"ARRIVAL":"01:23P","ROUTE":"208","DIR":"E"},
{"ARRIVAL":"01:53P","ROUTE":"208","DIR":"E"},
{"ARRIVAL":"02:23P","ROUTE":"208","DIR":"E"},
{"ARRIVAL":"02:53P","ROUTE":"208","DIR":"E"}]
Code:
<script>
function getTimes(stopNumber) {
var busArrivalAPI = "http://blahblahblah/rtcTimes/" + stopNumber ";
$.getJSON(busArrivalAPI, function(busArrivals) {
var a = [];
for (var i = 0; i < busArrivals.length; i++) {
a[i] = [busArrivals[i].ROUTE, busArrivals[i].ARRIVAL, busArrivals[i].DIR];
document.getElementById("results").createElement("TR");
for (var b = 0; b < 3; b++) {
var x = document.createElement("TH");
var z = a[i][b];
var t = document.createTextNode(z);
x.appendChild(t);
document.getElementById('results').appendChild(x);
};
};
});
</script>
My DIV:
<div style="overflow-x:scroll; overflow-y:scroll;" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="title:'Bus Arrival Times', selected:true">
<table id = 'results'>
<tr>
<th>Route</th>
<th>Arrival Time</th>
<th>Direction</th>
</tr>
</table>
</div>
UPDATE: Ok, I've use the makeTable idea provide below and it works when I program as seen below hard coding the json data. However, when trying to use the $.getJSON I'm having some cross domain issues now and don't know how I can get my $.getJSON request working. Any input on how to get the data from my getJSON request work be great.
function getTimes(stopNumber) {
// This is the API address I need to hit. Trying to figure out how to incorporate that and remove the function getJSON where I have the data hard coded.
//var busArrivalAPI = "http://-----/rtcTimes/"+ stopNumber + "?jsoncallback=?";
function makeTable(busArrivals) {
// This will remove old values so table will only load current Times
var results = document.getElementById("results");
var rowCount = results.rows.length;
for (var x=rowCount-1; x>0; x--) {
results.deleteRow(x);
}
// This will populate the result table with the correct bus routes/times/direction
busArrivals.forEach(function(busArrival) {
var tr = document.createElement('tr');
var route = document.createElement('td');
route.appendChild(document.createTextNode(busArrival.ROUTE));
var arrival = document.createElement('td');
arrival.appendChild(document.createTextNode(busArrival.ARRIVAL));
var direction = document.createElement('td');
direction.appendChild(document.createTextNode(busArrival.DIR));
tr.appendChild(route);
tr.appendChild(arrival);
tr.appendChild(direction);
document.getElementById('results').appendChild(tr);
});
}
function getJSON(callback) {
var data = [{"ARRIVAL":"05:23P","ROUTE":"201","DIR":"E"},
{"ARRIVAL":"05:54P","ROUTE":"202","DIR":"E"},
{"ARRIVAL":"06:33P","ROUTE":"203","DIR":"E"},
{"ARRIVAL":"07:11P","ROUTE":"204","DIR":"E"}];
callback(data);
}
getJSON(makeTable);
};
I think you could write a separate function to build the table, like this:
function makeTable(busArrivals) {
busArrivals.forEach(function(busArrival) {
var tr = document.createElement('tr');
var route = document.createElement('td');
route.appendChild(document.createTextNode(busArrival.ROUTE));
var arrival = document.createElement('td');
arrival.appendChild(document.createTextNode(busArrival.ARRIVAL));
var direction = document.createElement('td');
direction.appendChild(document.createTextNode(busArrival.DIR));
tr.appendChild(route);
tr.appendChild(arrival);
tr.appendChild(direction);
document.getElementById('results').appendChild(tr);
});
}
var busArrivalAPI = 'http://blahblahblah/rtcTimes/'+ stopNumber;
$.getJSON(busArrivalAPI, makeTable);
In each iteration of the forEach loop, you construct a tr element, insert the tds and finally put the whole thing inside the DOM.
You're creating a TR element, but never appending it to the table. Instead, you're appending the TH elements directly to the table, which is invalid.
function getTimes(stopNumber) {
var busArrivalAPI = "http://blahblahblah/rtcTimes/" + stopNumber;
$.getJSON(busArrivalAPI, function(busArrivals) {
var table = document.getElementById('results');
for (var i = 0; i < busArrivals.length; i++) {
var a = [busArrivals[i].ROUTE, busArrivals[i].ARRIVAL, busArrivals[i].DIR];
var row = document.createElement("TR");
for (var b = 0; b < 3; b++) {
var x = document.createElement("TH");
var z = a[b];
var t = document.createTextNode(z);
x.appendChild(t);
row.appendChild(x);
};
table.appendChild(row);
};
});
}
I'm not sure why you need the a array. If you just want to change get the object properties into an array so you can iterate over it, you can do that with a 1-dimensional array, you don't need to save all the other rows in a 2-dimensional array. I've changed a to a single array.

Data copying with Google Apps Script

I am trying to write a script in Google Apps Script that takes cell information from one sheet and copies it to another sheet, both for just grabbing certain columns to display on the second sheet and also a condition based on the values inside cells in a certain column. Here is what I have so far:
function onMyEdit() {
var myMaster = SpreadsheetApp.openById("xxxxx");
var masterSheet = myMaster.setActiveSheet(myMaster.getSheets()[0]);
var myNames = SpreadsheetApp.openById("xxxxx");
var namesSheet = myNames.setActiveSheet(myNames.getSheets()[0]);
var row1 = masterSheet.getRange(1, 1, masterSheet.getLastRow(), 1);
var rowV = row1.getValues();
var firstArray = masterSheet.getDataRange().getValues();
var dataList = [];
for (var i = 1; i < rowV.length; i++) {
dataList.push(firstArray[i][0]);
dataList.push(firstArray[i][1]);
dataList.push(firstArray[i][2]);
dataList.push(firstArray[i][3]);
}
for (var j = 0; j < rowV.length - 1; j++) {
namesSheet.getRange(2, j + 1, 1, 1).setValue(dataList[j]);
}
}
So as of now it only works on one row, starting from the second row (to allow for column headers). And I suppose when I want to grab rows conditionally based on cell data, I will use an 'if' statement for the condition inside the 'for' loop, but I want the data to copy to the next available row in both sheets. I suppose I'd use something like:
' getLastRow + 1 '
or something like that. I need this code to be as efficient as possible because of the amount of data and its purpose. I am pretty new to programming so please explain in detail, and thanks again.
I'm not sure I understood exactly what you wanted to do but -from what I understood- this code snippet should give you a better way to start with...
(I added a few comments to explain in the code itself)
function onMyEdit() {
var myMaster = SpreadsheetApp.openById("MasterSheet ID");
var masterSheet = myMaster.getSheets()[0]; // get 1rst sheet
var myNames = SpreadsheetApp.openById("NamesSheet ID");
var namesSheet = myNames.getSheets()[0]; // get 1rst sheet
var firstArray = masterSheet.getDataRange().getValues();
var dataList = [];
for ( r = 1; r < firstArray.length; r++) { // iterate the first col of masterSheet
if(firstArray[r][0]=='some condition'){ // if value in the first column == 'some condition get the second column cell in the new array (here you could change what you want to get)
dataList.push([firstArray[r][1]])
}
}
Logger.log(dataList)
if(dataList.length>0){
namesSheet.getRange(1,namesSheet.getLastColumn()+1,dataList.length,1).setValues(dataList);//copy data in a column after last col
}
}

Categories

Resources