I am trying to swap two array in javascript. While the replacement comes to the last iteration, I am getting "NotFoundError: Node was not found" in the call of parent.replaceChild(item2,item1). Please help me what mistake I have committed.
function sortTable(col){
if($("loacte-resultsTable") == null || $("loacte-resultsTable") == undefined){
return false;
}
if (lastSort == col) {
// sorting on same column twice = reverse sort order
absOrder ? absOrder = false : absOrder = true
}
else{
absOrder = true
}
lastSort = col;
try{
var loacteResultsTable = $("loacte-resultsTable").getElementsByTagName("TBODY")[0];
var loacteResultsTableTR = loacteResultsTable.getElementsByTagName("TR");
allTR = loacteResultsTableTR;
} catch (e) {
return false;
}
// allTR now holds all the rows in the dataTable
totalRows = allTR.length;
colToSort = new Array(); //holds all the cells in the column to sort
colArr = new Array(); //holds all the rows that correspond to the sort cell
copyArr = new Array(); //holds an original copy of the sort data to match to colArr
resultArr = new Array(); //holds the output
allNums = true
allDates = true
//store the original data
//remember that the first row - [0] - has column headings
//so start with the second row - [1]
//and load the contents of the cell into the array that will be sorted
for (x=0; x < totalRows; x++){
var data = setDataType(allTR[x].childNodes[col].innerText);
if(typeof data!="undefined"){
colToSort[x] = setDataType(allTR[x].childNodes[col].innerText);
}else{
colToSort[x] = setDataType(allTR[x].childNodes[col].textContent);
}
colArr[x] = allTR[x];
}
//make a copy of the original
for (x=0; x<colToSort.length; x++){
copyArr[x] = colToSort[x];
}
//sort the original data based on data type
if (allNums){
colToSort.sort(numberOrder);
} else if (allDates){
colToSort.sort(dateOrder);
} else {
colToSort.sort(textOrder);
}
//match copy to sorted
for(x=0; x<colToSort.length; x++) {
for(y=0; y<copyArr.length; y++) {
if (colToSort[x] == copyArr[y]) {
boolListed = false
//search the ouput array to make sure not to use duplicate rows
for(z=0; z<resultArr.length; z++) {
if (resultArr[z]==y) {
boolListed = true
break;
}
}
if (!boolListed){
resultArr[x] = y
break;
}
}
}
}
//now display the results - it is as simple as swapping rows
for (x=0; x<resultArr.length; x++) {
//allTR[x].swapNode(colArr[resultArr[x]])
swapNodes(allTR[x],colArr[resultArr[x]]);
}
function swapNodes(item1,item2)
{
var itemtmp = item1.cloneNode(1);
var parent = item1.parentNode;
item2 = parent.replaceChild(itemtmp,item2);
parent.replaceChild(item2,item1);
parent.replaceChild(item1,itemtmp);
itemtmp = null;
}
}
The call to the sortTable method is from synch().This is the UI part coded in JS:
function synch(){
var loacteResults = $('loacte-results');
var loacteResultsTable = $('loacte-resultsTable');
tab = loacteResults.getElementsByTagName('TABLE')[0];
loacteResults.removeChild(tab);
var updatedResults =
'<table id="loacte-resultsTable" cellspacing="0" cellpadding="3" border="1">' +
'<thead class="thead">' +
'<tr>' +
'<th>Site ID</th>' +
'<th>Store Name</th>' +
'<th>Agent Code</th>' +
'<th>Address</th>' +
'<th>City, State</th>' +
'<th>Phone</th>' +
'<th>Hours</th>' +
'<th>Deleted</th>' +
'<th width="65px;">Priority <img src="images/sort_up_down.gif" onclick="javascript:sortTable(8)" style="cursor: pointer;"/></th>' +
'<th width="115px;">Est.Dist.(miles) <img src="images/sort_up_down.gif" onclick="javascript:sortTable(9)" style="cursor: pointer;"/></th>' +
'</tr>' +
'</thead>' ;
if(tr == '')
updatedResults = updatedResults + '<tbody><tr><td colspan="10">No Stores to display</td></tr></tbody></table>';
else
updatedResults = updatedResults + '<tbody>' + tr + '</tbody></table>';
loacteResults.innerHTML = updatedResults;
}
In the third parent.replaceChild line item1 is no longer is on the page, since it has been replaced with item2.
Your code broken down:
function swapNodes(item1,item2)
{
var itemtmp = item1.cloneNode(1); //create a copy of item 1
var parent = item1.parentNode; //set a reference to the parent
item2 = parent.replaceChild(itemtmp,item2); //replace item2 with the copy of item1 and store the old child in item2
parent.replaceChild(item2,item1); //replace item1 with item2
parent.replaceChild(item1,itemtmp); //this line is redundant. <-- item1 no longer is on the page.
itemtmp = null;
}
Related
I'm kinda new to scripting and all and just wanted to know if anyone could help me edit my code to hide the whole table from the start and then just display the rows that match the keyword.
Right now what the code does is:
You enter a keyword in an inputbox
The script searches through a table looking for rows matching the keyword.
Hide all other rows.
But i would like it to work another way, but don't really know how to.
What i would like it to do is:
Display the inputbox only on the page.(Table is hidden)
Display the results that match the keyword without displaying the whole table.
Code:
var TableSearch = function(searchBoxId, dataTableId, options) {
this.searchBox = document.querySelector('#' + searchBoxId);
this.dataTable = document.querySelector('#' + dataTableId);
this.options = options;
}
TableSearch.prototype = {
init: function(searchBoxId, dataTableId, options) {
// defaults options
var settings = {
firstRowHeader: true,
highlightCss: "style='background-color:yellow'",
noResultsText: null
};
if (this.options) {
for (var key in settings) {
// Update settings if valid option and value was supplied.
if (this.options.hasOwnProperty(key) && (this.options[key] != null && this.options[key].toString() != '')) {
if (key == 'highlightCss') {
settings[key] = "class='" + this.options[key] + "'";
continue;
}
settings[key] = this.options[key];
}
}
}
this.options = settings;
this.searchBox.addEventListener('keyup', this.search.bind(this), false);
},
search: function(e) {
if(e.keyCode == 27) {
this.searchBox.value = ''; // Clear search on Esc
}
this.toggleNoResult('remove');
var keyword = this.escapeSpecialChars(this.searchBox.value);
var textSearchRegex = new RegExp(keyword, "ig"); // case in-sensitive
var rowDisplay, rowObj, rowHtml, match;
var firstRowIndex = (this.options.firstRowHeader == true) ? 1 : 0;
for (var rowIndex = firstRowIndex; rowIndex < this.dataTable.rows.length; rowIndex++) {
rowDisplay = '';
rowObj = this.dataTable.rows.item(rowIndex);
rowHtml = rowObj.innerHTML.replace(/<mark[^/>]*>/g,'').replace(/<\/mark>/g,''); // remove previous highlighting
if (keyword == '')
rowDisplay = 'table-row';
else {
match = rowHtml.replace(/<[^>]*>/g, '').match(textSearchRegex); // strip html tags and search for keyword
if(match) {
// Get unique matches: http://stackoverflow.com/a/21292834/1440057
match = match.sort().filter(function(element, index, array) { return index == array.indexOf(element); });
var tempHtml = rowHtml;
for (var i = 0; i < match.length; i++)
tempHtml = this.highlight(tempHtml, match[i]);
if (tempHtml.search(/<\/mark>/g) > -1) {
rowHtml = tempHtml;
rowDisplay = 'table-row';
}
else // Keyword did not match with any column content
rowDisplay = 'none';
}
else // Keyword did not match even in the row text content
rowDisplay = 'none';
}
rowObj.innerHTML = rowHtml;
rowObj.style.display = rowDisplay;
}
// Check if 'no results' row needs to be added
if (keyword != '' && this.options.noResultsText && this.dataTable.innerHTML.search(/style=\"display: table-row;\"/g) == -1)
this.toggleNoResult('add');
},
highlight: function(rowHtml, match) {
var row = document.createElement('tr');
row.innerHTML = rowHtml;
var textReplaceRegex = new RegExp(this.escapeSpecialChars(match), "g"); // case sensitive
var highlightMarkup = '<mark ' + this.options.highlightCss + '>' + match + '</mark>';
var cell = null;
var htmlOut = '';
for (var i = 0; i < row.cells.length; i++) {
cell = row.cells.item(i);
// Highlighting works only for direct text content, not nested tags.
// e.g. searching "blog" in <td>my blog</td> won't work.
if (cell.children.length == 0) {
if (cell.textContent.indexOf(match) > -1) {
// Match found in this cell, highlight it
htmlOut += '<td>' + cell.textContent.replace(textReplaceRegex, highlightMarkup) + '</td>';
continue;
}
}
htmlOut += '<td>' + cell.innerHTML + '</td>';
}
return htmlOut;
},
escapeSpecialChars: function(inStr) {
return inStr.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
},
toggleNoResult: function(mode) {
var noResultsRow;
if (mode == 'add') {
noResultsRow = this.dataTable.insertRow(this.dataTable.rows.length);
noResultsRow.setAttribute('id', 'noResultsRow');
var noResultsRowCell = noResultsRow.insertCell(0);
noResultsRowCell.setAttribute('colspan', this.dataTable.rows[0].cells.length);
noResultsRowCell.setAttribute('align', 'center');
noResultsRowCell.textContent = this.options.noResultsText;
}
else if (mode == 'remove') {
noResultsRow = this.dataTable.querySelector('#noResultsRow');
if (noResultsRow != null) {
this.dataTable.deleteRow(this.dataTable.rows.length - 1);
}
}
}
}
Thanks in advance :)
I'm trying to return every value from the array allArtistsArray, which gets values from a spreadsheet, and have them display as an unordered list with buttonTemplate first, and then every value in the spreadsheet after it.
The problem I'm having is that only the first value from the spreadsheet is being returned and displayed on the web app. How do I get every value to display after buttonTemplate?
What's being displayed is:
* buttonTemplate
or
* value 1 from spreadsheet
What I'm trying to get displayed is:
* buttonTemplate
* value 1 from spreadsheet
* value 2 from spreadsheet
* value 3 from spreadsheet
* etc
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= getContent("js") ?>
<?!= getContent("css") ?>
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Abel">
</head>
<body>
<div id="artistTabs">
<ul id="artistList">
<?!= createArtistList(); ?>
</ul>
</div>
</body>
</html>
code.gs
var ss = SpreadsheetApp.openById('id');
var sheet = ss.getSheets()[0];
function doGet()
{
return HtmlService.createTemplateFromFile('index').evaluate();
}
function getContent(filename)
{
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function createArtistList()
{
var buttonStartingRow = 2;
var buttonStartingColumn = 1;
var buttonCell = sheet.getRange(buttonStartingRow, buttonStartingColumn).getValue();
var x = '<li><a onClick="addArtist(); return false;" href="">';
var y = buttonCell;
var z = '</a></li>';
var buttonTemplate = x + y + z;
//return buttonTemplate;
var startingRow = 2;
var startingColumn = 1;
var howManyRows = sheet.getLastRow() - 1;
var howManyColumns = 1;
var allArtistsArray = sheet.getRange(startingRow, startingColumn, howManyRows, howManyColumns).getValues(); //get every name in 1st column after second row
//allArtistsArray = allArtistsArray.filter(function(n){return n[0] !== '' && n[0] !== buttonCell}); //filter 'buttonCell' value and blank rows
//allArtistsArray = allArtistsArray.toString().split(","); //flatten 2d array to 1d array
//Logger.log(allArtistsArray);
for (i = 0; i < allArtistsArray.length; i++)
{
allArtistsArray = allArtistsArray.filter(function(n){return n[0] !== '' && n[0] !== buttonCell}); //filter 'buttonCell' value and blank rows
allArtistsArray = allArtistsArray.toString().split(","); //flatten 2d array to 1d array
if (allArtistsArray == '')
{
Logger.log("array = blank");
break; //leave for loop and only return buttonTemplate ???
}
else
{
var x1 = '<li><a onClick="test(); return false;" href="">';
var z1 = '</a></li>';
var _1 = allArtistsArray[i];
var _2 = x1 + _1 + z1;
Logger.log(_2);
}
}
Logger.log(allArtistsArray);
return buttonTemplate;
}
Looks to me like you should be changing the value of buttonTemplate IN your for loop if that is the result you want. For example: buttonTemplate += _2 (or whatever you want appended it is unclear from your example).
EDIT
Without a snippet to play around with it's hard to see if this works but here is a better example of what I meant:
function createArtistList()
{
var buttonStartingRow = 2;
var buttonStartingColumn = 1;
var buttonCell = sheet.getRange(buttonStartingRow, buttonStartingColumn).getValue();
var x = '<li><a onClick="addArtist(); return false;" href="">';
var y = buttonCell;
var z = '</a></li>';
var buttonTemplate = x + y + z;
var artistsOutput = '';
//return buttonTemplate;
var startingRow = 2;
var startingColumn = 1;
var howManyRows = sheet.getLastRow() - 1;
var howManyColumns = 1;
var allArtistsArray = sheet.getRange(startingRow, startingColumn, howManyRows, howManyColumns).getValues(); //get every name in 1st column after second row
//allArtistsArray = allArtistsArray.filter(function(n){return n[0] !== '' && n[0] !== buttonCell}); //filter 'buttonCell' value and blank rows
//allArtistsArray = allArtistsArray.toString().split(","); //flatten 2d array to 1d array
//Logger.log(allArtistsArray);
for (i = 0; i < allArtistsArray.length; i++)
{
allArtistsArray = allArtistsArray.filter(function(n){return n[0] !== '' && n[0] !== buttonCell}); //filter 'buttonCell' value and blank rows
allArtistsArray = allArtistsArray.toString().split(","); //flatten 2d array to 1d array
if (allArtistsArray == '')
{
Logger.log("array = blank");
break; //leave for loop and only return buttonTemplate ???
}
else
{
var x1 = '<li><a onClick="test(); return false;" href="">';
var z1 = '</a></li>';
var _1 = allArtistsArray[i];
if (_1 != null)
{
var _2 = x1 + _1 + z1;
artistsOutput += _2;
Logger.log(_2);
} else {
Logger.log('The ' + i + 'th element was null for some reason');
}
}
}
Logger.log(allArtistsArray);
return buttonTemplate + artistsOutput;
}
I have a unique problem that I hope someone can help with. I have a page that pulls data from a controller with AJAX and presents it to this function to construct a table:
// make rows in table from json data
function makeTableRows() {
if (jsonTableData != null) {
tbl = null;
tbl = createTable('tableResults');
// constructHeader(tbl, 'left', jsonTableData[0]);
newHeader(tbl, 'left', jsonTableData[0]);
var totalItems = jsonTableData.length;
var topItem;
topItem = 0;
if ((lastItem + perpage) > totalItems) {
topItem = totalItems;
$(".btnNext").prop('disabled', true);
}
else {
topItem = lastItem + perpage;
}
for (var i = lastItem; i <= topItem - 1; i++) {
makeTableRow(tbl, jsonTableData[i], 'left', true, 'showTourDetails(' + jsonTableData[i]["TransactionID"] + ',' + i + ')', 0);
}
$("#divSearchResults").html(tbl);
makePagesLabel();
makeTableFooter(tbl);
}
}
the function inside the separate file is this:
function constructHeader(table, alignment, firstRow) {
if (firstRow != null) {
var thead = document.createElement('thead');
table.appendChild(thead);
var tr = document.createElement('tr');
for (var key in firstRow) {
var header = key.match(/[A-Z][a-z]*/g);
var newHeader = '';
for (var i = 0; i <= header.length - 1; i++) {
newHeader += header[i] + ' ';
}
var th = document.createElement('th');
var text = document.createTextNode(newHeader);
th.appendChild(text);
th.style.textAlign = alignment;
th.style.cursor = 'pointer';
th.setAttribute('title', "Sort by " + newHeader);
th.onclick = function () {
var rows = $(table).find('tbody').find('tr').toArray().sort(comparer($(this).index()));
this.asc = !this.asc;
if (!this.asc) {
rows = rows.reverse();
}
for (var j = 0; j < rows.length; j++) {
$(table).append(rows[j]);
}
$(table).find('tbody').find('tr:even').css("background-color", "#dae5f4");
$(table).find('tbody').find('tr:odd').css("background-color", "#b8d1f3");
};
tr.appendChild(th);
}
thead.appendChild(tr);
}
}
Basically the function creates a sort process for the header of each column. After the sort of the column, I want to reapply the zebra striping that is applied with the class of the table. If I don't try to reapply I end up with the striping all messed up. Now, the problem is that if I copy the function into the .cshtml page and give it the name of 'newheader', the re-striping works fine. It does not work in the separate JS file and I cannot figure out why. Anyone have any clues?
I have an array defined and appending it to a string field to dynamically write a HTML TR. I have named a series of JPEGs with the same name as the string value in the array so that I can dynamically print the String name and its associated image. My problem is that I want to add an onclick event to the image and pass a javascript function the same name that is printed for the table row. The images and string iterate properly but the value passed to the javascript function for each table row is defaulting to the last array item? I tried multiple scenarios and don't understand why the same storyWords[index] isn't working when it used to choose the correct JPEG file and print out the correct name.
<script type="text/javascript">
var storyWords = "";
var index;
var strWord ="";
function doStuff(word){
alert(word);
};
$(document).ready(function(){
var storyId = localStorage.getItem("StoryId");
var strHTML = "<table>";
if (storyId == "1"){
storyWords = ["Ant", "Bananas", "Bottle", "Car", "Castle"];
}
else if (storyId == "2"){
storyWords = ["Dragons", "Football", "Hollow", "Hospital", "Island"];
}
else if (storyId == "3"){
storyWords = ["Log", "Party", "Mountain", "Poles", "Princess"];
}
else{
storyWords = ["Trophy"];
}
for (index = 0; index < storyWords.length; index++){
strWord = storyWords[index];
strHTML += "<tr><td><img src=img/Words/" + storyWords[index] + ".jpg onclick=doStuff("+ storyWords[index] +");> " + storyWords[index] + "</td></tr>";
}
$('#wordText').html(strHTML + "</table>");
});
</script>
Thanks for any help!
Just rewrote your function a bit and created a Fiddle
$(document).ready(function () {
function doStuff(word) {
alert(word);
}
var storyId = 3; // just set static storyId 3 as example
var table = $('<table>');
if (storyId == "1") {
storyWords = ["Ant", "Bananas", "Bottle", "Car", "Castle"];
}
else if (storyId == "2") {
storyWords = ["Dragons", "Football", "Hollow", "Hospital", "Island"];
}
else if (storyId == "3") {
storyWords = ["Log", "Party", "Mountain", "Poles", "Princess"];
}
else {
storyWords = ["Trophy"];
}
for (index = 0; index < storyWords.length; index++) {
(function (story) {
strImg = "";
var tr = $('<tr>');
var td = $('<td>');
var img = $('<img>');
img.attr('src', 'img/Words/' + story + '.jpg');
img.click(function () {
doStuff(story);
})
img.appendTo(td);
td.append(" " + story);
td.appendTo(tr);
tr.appendTo(table);
})(storyWords[index]);
}
$("#wordText").append(table);
});
HTML:
<div id="wordText"></div>
I adjusted the creating / appending of the rows, columns, etc a bit instead of writing the whole row including the table-closing-tag as one variable. Just a suggestion as I'm more used to write it like that. Hope this is of any use for you though it's kind of a different approach :)
The program is a Seat reservation program rows 1 and 2 are first class, row 3-9 are business class and rows 10 through 13 are economy. They are initialized to * and become X when it is reserved. and alert you if the seat is already filled.
The rows will fill for the first 6 rows but it ignores request for row 7 and beyond. But i know it goes to the appropriate function because if i request Economy with row 3 (which is invalid) it alerts me. But if i ask for first class with row7 it will act like nothing has been requested.
It won't let me post the html code but it will display as row1-13 on the left and A - F across the top. I use drop down list and I set the values to the corresponding for the options to their corresponding spot in a the 2-d array (eg if i select row 5 and seat c the value of row 5 is 5 and the value of C is 3)
var rowSeat;
function start()
{
rowSeat = new Array(14);
for(var i = 0; i <rowSeat.length; i++)
{
rowSeat[i] = new Array(7);
}
var j = 65;
for(var i = 1; i <rowSeat[0].length; i++)
{
rowSeat[0][i] = String.fromCharCode(j);
j++;
}
rowSeat[0][0] = " ";
for(var i = 1; i <rowSeat.length; i++)
{
rowSeat[i][0] = "Row "+i;
}
for(var i = 1; i <rowSeat.length; i++)
{
for(var j = 1; j <rowSeat[i].length; j++)
{
rowSeat[i][j] = "*";
}
}
display();
var subButton = document.getElementById("submitButton");
subButton.addEventListener("click", assign, false);
}
function display()
{
var results = "";
results+="<table>"
for(var i in rowSeat)
{
results+="<tr>";
for(var j in rowSeat[i])
{
results += "<td>" +rowSeat[i][j]+ "</td>";
}
results += "</tr>";
}
results+="</table>"
var show2 = document.getElementById( "show2" );
show2.innerHTML = results;
}
function assign()
{
var inputField = document.getElementById("classAssign");
var classType = inputField.options[inputField.selectedIndex].value;
if (classType == "FirstClass")
{
fClassSearch();
}
else if (classType == "Business")
{
bClassSearch();
}
else
{
eClassSearch();
}
display();
}
function fClassSearch(){
var inputField = document.getElementById("seatAssign");
var seat = inputField.options[inputField.selectedIndex].value;
var inputField2 = document.getElementById("rowAssign");
var row = inputField.options[inputField2.selectedIndex].value;
var test = document.getElementById( "test" );
test.innerHTML = row +" "+ seat;
if (row >2){
var show2 = document.getElementById( "show" );
show.innerHTML = "Invalid choice only row 1 and 2 are First Class";
}
else {
if(rowSeat[row][seat] == "*")
{
rowSeat[row][seat] = "X";
show.innerHTML = "Your Seat choice was accepted and Reserved";
}
else{
show.innerHTML = "Your choice was already reserved please make another choice";
}
}
}
function bClassSearch(){
var inputField = document.getElementById("seatAssign");
var seat = inputField.options[inputField.selectedIndex].value;
var inputField2 = document.getElementById("rowAssign");
var row = inputField.options[inputField2.selectedIndex].value;
if (row <3 ||row >9){
var show2 = document.getElementById( "show" );
show.innerHTML = "Invalid choice only row 3 through 9 are BusinessClass";
}
else {
if(rowSeat[row][seat] == "*")
{
rowSeat[row][seat] = "X";
show.innerHTML = "Your Seat choice was accepted and Reserved";
}
else{
show.innerHTML = "Your choice was already reserved please make another choice";
}
}
}
function eClassSearch(){
var inputField = document.getElementById("seatAssign");
var seat = inputField.options[inputField.selectedIndex].value;
var inputField2 = document.getElementById("rowAssign");
var row = inputField.options[inputField2.selectedIndex].value;
var show1 = document.getElementById( "show" );
if (row <10){
show1.innerHTML = "Invalid choice only rows 10 through 13 are Economy Class";
}
else {
if(rowSeat[row][seat] == "*")
{
rowSeat[row][seat] = "X";
show.innerHTML = "Your Seat choice was accepted and Reserved";
}
else{
show.innerHTML = "Your choice was already reserved please make another choice";
}
}
}
window.addEventListener("load",start, false);
</script>
var row = inputField.options[inputField2.selectedIndex].value;
inputField.options should be inputField2.options
inputField.options only goes to 6 because you only have 6 seats wide, but you are trying to look at the row in the seat list.