Something about this 'NOT_FOUND_ERR: Dom exception 8' confuses me - javascript

Well, here I continue, trying to learn this very nice language... So I previously had a very ugly code full of 'document.write()' and more ugly things, and now I am transforming it into a very nice standards compliant code, and I am liking it! But I found a problem where I don't see the logic. Here it goes:
In the html file I have this:
<body onload="generatetable(0)">
And in the .js file I have this:
function generatetable(product) {
var tbinfo = document.createElement("table"); //table
var tbbody = document.createElement("tbody"); //tbody
var row = document.createElement("tr"); // creates row
for (var i = 0; i < 4; i++) { // creates 4 cells
var cell = document.createElement("td");
}
var tname = arraypro[product].Name;
cell.appendChild(tname);
(I don't paste the rest of the table, because it seems to work fine)
And when running, I get the 'Exception 8' error on the var tname = arraypro[product].Name line
But if I do just an
alert(arraypro[0].Name);
it outputs exactly what it should output, the very right word. How it's possible that the value in arraypro[product].Name can be retrieved by an alert (if you pass the value of 'product') but not by the appendChild?
I am still not very well used to the logic of programming, but I try...
PD: The arraypro , where the information is, has been declared as a global value, accessible for everything, in case it matters to know.
Thanks very much for any input here.

appendChild() expects a DOM-Node, you're passing in a string I believe.
You can change it to:
var tname = arraypro[product].Name;
cell.appendChild(document.createTextNode(tname));

Related

Handsontable Performance Issues On Updating Comments to Cells

I have a function that updates a comment to every single cell in a row. This function is called many times by a higher level function that loops through every row in the table and determines what comments to apply.
This all works fine. See a simplified version of the code below.
// Loop through all hot rows and determine comment to apply
var loopThroughHotRows = function (hot) {
var rows = hot.getSourceData().length;
for (var i = 0; i < rows; i++) {
var comment = "some comment determined by another function";
applyResponseCommentsToRow(hot, comment, i);
}
}
// Apply comments to a whole row in a passed handsontable
var applyCommentsToRow = function (hot, comment, logicalrow) {
var cols = hot.countCols();
var commentsPlugin = hot.getPlugin('comments');
for (var i = 0; i < cols; i++) {
// render being issued for each comment set.
// need to restrict rendering somehow.
commentsPlugin.setCommentAtCell(logicalrow, i, comment);
}
}
The problem is that each time a comment is applied to a cell. The rendering of the entire handsontable instance is initiated. Causing the web browser to get blocked/chug/become very slow and responsive until all the rendering is complete.
So my question is. Is there some way to prevent Handsontable from rendering each time that a new comment is applied to a cell? Either by temporarily disabling all rendering or adding the comments in a different manner?
I actually ended up figuring out a solution to this on my own. If you set the comment of the cell by calling the hot.getCellMeta() function.
This actually bypasses the re-rendering of the handsontable. See updated function below.
// Apply comments to a whole row in a passed handsontable
var applyCommentsToRow = function (hot, comment, logicalrow) {
var cols = hot.countCols();
for (var i = 0; i < cols; i++) {
// New method of writing comment to cell. Does not cause handsontable re-render.
hot.getCellMeta(logicalrow, i).comment = {'value':responseComments};
}
// Call render once after all comments have been assigned to row!
hot.render();
}
The first thing I can think of to enhance the speed of your function is to not change the comment in cells when it's not necessary. (old comment value = new comment value). To do that, you simply have to compare both String before doing setCommentAtCell :
if(comment.localeCompare(hot.getPlugin('comments').getCommentAtCell(logicalRow,i)) != 0)
commentsPlugin.setCommentAtCell(logicalRow, i, comment);
I used a little example to quickly test this change that you can find in this JSFiddle. (For the sake of 'quick testing', I trigger the change comment for every cell when I copy : whether you use ctrl+C in the table, or you use the action copy in the context menu).
You will see that it will freeze the first time (as every cell will be modified), but the second time there is no freeze at all since the changes are not necessary.

Can't assign querySelectorAll() to a variable - weird behaviour

I was trying to crawl a very old website for a specific tag, I need to get it by it's for= attribute. So I used this piece of code.
var character = document.querySelectorAll("label[for=char_1]");
For some reason it returns an undefined, but I was using this script for a few days now and it worked like a charm. Here's the fun part. Typing that command in browsers console will result in undefined. But typing this alone:
document.querySelectorAll("label[for=char_1]");
Will return a proper NodeList. Why it won't assign to a variable...?
edit: It seems that deleting var and typing character without it will make it work. It's resolved but I would still love to get an answer to "why is this happening"?
edit2:
for (var i = 0; i < 15; i++) {
var character = document.querySelectorAll("label[for=char_" + i +"]");
console.log(character); // this will return [] from the script.
var color = character[0].children[0].style.color;
}
A simple for loop. All I get is Cannot read property 'children' of undefined. But I can type in the very same command document.querySelectorAll... and it will work in the browser and will return NodeList.
I had it working like this in a very hacky script. It worked.
var character1 = document.querySelectorAll("label[for=char_1]");
var characterColor1 = character1[0].children[0].style.color;
edit3:
var character1 = document.querySelectorAll("label[for=char_1]");
var characterColor1 = character1[0].children[0].style.color;
var character2 = document.querySelectorAll("label[for=char_2]");
var characterColor2 = character2[0].children[0].style.color;
// ...
The above code works without a single problem though. I don't think it's DOM not being ready as this code is also run from Greasemonkey script and it works. The only difference is the for loop.
var x = ""; // returns undefined, because it's a var assignment.
var elements = document.querySelectorAll('div');
That's expected behavior when pasted into the console.
edit: It seems that deleting var and typing character without it will make it work. It's resolved
I'm afraid you're creating a global scope variable now. or perhaps characters is an already defined variable in that scope.
Buhah, as I said in edit 3 "the only difference is the for loop". I was so busy trying to find an answer in the DOM-related things that I made the simplest mistake ever done in programming.
See?
char_1
With...
for(var i = 0...)
0! And I was testing char_1 in the browser instead of char_0. Which - truly - returns [] instead of something useful. Time to go on a holiday break I guess, my brain seems to be there already. :)

Can I make an array list adaptable in the HTML?

I am currently creating a spelling game where you drag and drop letters onto the corresponding words. At the moment I have a list of words in the array list that generate a grid dynamically.
The problem is when new words need to be added to the game, they have to be added through the HTML as that side of the office are not familiar with JavaScript/JQuery and not willing to learn.
What would be the best approach to this?
Is there a way that they can add things to the array in the script through HTML?
This is the script I have at the moment...
var listOfWords = new Array();
listOfWords['mat'] = 'http://www.wav-sounds.com/cartoon/daffyduck1.wav';
listOfWords['cat'] = 'http://www.wav-sounds.com/cartoon/porkypig1.wav';
listOfWords['dog'] = 'http://www.wav-sounds.com/cartoon/bugsbunny1.wav';
listOfWords['pit'] = 'http://www.wav-sounds.com/cartoon/daffyduck1.wav';
listOfWords['pot'] = 'http://www.wav-sounds.com/cartoon/porkypig1.wav';
listOfWords['fog'] = 'http://www.wav-sounds.com/cartoon/daffyduck1.wav';
listOfWords['log'] = 'http://www.wav-sounds.com/cartoon/porkypig1.wav';
listOfWords['pan'] = 'http://www.wav-sounds.com/cartoon/bugsbunny1.wav';
listOfWords['can'] = 'http://www.wav-sounds.com/cartoon/bugsbunny1.wav';
listOfWords['man'] = 'http://www.wav-sounds.com/cartoon/porkypig1.wav';
listOfWords['pin'] = 'http://www.wav-sounds.com/cartoon/daffyduck1.wav';
listOfWords['gag'] = 'http://www.wav-sounds.com/cartoon/porkypig1.wav';
Then i have script that takes the array list items and creates a grid dynamically.
var rndWord = null;
var guesses = new Array();
var shuffledWords = keys(listOfWords).slice(0).sort(function() {
return 0.5 - Math.random();
}).slice(0, 12);
var tbl = document.createElement('table');
tbl.className = 'tablestyle';
var wordsPerRow = 2;
for (var i = 0; i < Object.keys(shuffledWords).length - 1; i += wordsPerRow) {
var row = document.createElement('tr');
for (var j = i; j < i + wordsPerRow; ++j) {
var word = shuffledWords[j];
guesses[word] = [];
for (var k = 0; k < word.length; ++k) {
var cell = document.createElement('td');
$(cell).addClass('drop').attr('data-word', word);
cell.textContent = word[k];
// IF FIREFOX USE cell.textContent = word[j]; INSTEAD
row.appendChild(cell);
}
}
tbl.appendChild(row);
}
document.body.appendChild(tbl);
Thanks.
You could add a hidden object in the DOM:
<ul style="display:none;" id="wordlist">
<li data-word="mat" data-audio="http://www.wav-sounds.com/cartoon/daffyduck1.wav"></li>
<li data-word="cat" data-audio="http://www.wav-sounds.com/cartoon/porkypig1.wav"></li>
<!-- data-xxx can be read with JS, node["data-xxx"] or jQuery: node.data("xxx") -->
</ul>
You can then iterate over all elements using either jQuery or node.children:
var listOfWords = {};
var ul = document.getElementById("wordlist");
var i;
for(i = 0; i < ul.children.length; ++i){
listOfWords[ul.children[i].getAttribute("data-word")] = ul.children[i].getAttribute("data-audio");
}
console.log(listOfWords);
Demo
Hint: Please note that you're listOfWords is actually an object and not an array. An array supports only integer indexes and should be filled with .push.
Edit:
Please have a look at Tomas' answer. While this approach will definitely make it possible for your co-workers to add or change elements without actually writing JavaScript it's simply too much effort. Either way they will ask you questions how to add elements to the list. See also Dennis' comment.
Although Zeta's answer probably gives you an idea of how to do this, I'd say it doesn't really solve your actual problem. As you said yourself:
The problem is when new words need to be added to the game, they have to be added through the HTML as that side of the office are not familiar with JavaScript/JQuery and not willing to learn.
To me, this points to more fundamental difficulties in your team than just how to specify the dictionary in HTML; you seem to be working with people that are actively working against you. I see a couple of different ways to resolve this situation - some of them more provocative than others, while some requires more work on your part than others. You'll have to judge yourself which of them, if any, are applicable to you...
Force them to learn. It's not like they have to be jQuery masters to add a word to the dictionary - they just have to learn a specific syntax which you can teach them.
They are apparently capable of specifying the dictionary in HTML
markup, and can thus be assumed comfortable with some form of syntax.
I'd say your syntax for the dictionary is way simpler than what Zeta
suggested, so if they can learn one you should be able to teach them
the other.
If you need to, step up the company ladder and talk to their manager. They won't like it, but your development process probably will.
Do their work. Consider simplifying the whole process by reorganizing who does what in the development process. If the team responsible for the dictionary cannot add the actual key/value pairs to the code, maybe they can just ask you to do it for them? An email to a dedicated address, which you check a couple of times a day and add the corresponding stuff to the code would be one way to solve it.
Write them an admin system. This includes a lot of work on your part, both to create and support the feature - but it might earn you some goodwill in other matters. If the application should support later addition of new words, why not write a simple service that lets them add words to the dictionary from a web form? You store everything on the server, and load the dictionary with AJAX when you need it. The other team doesn't have to learn anything - they just enter the information in the form and click "send", and it's fixed.
My point is that if you're working with a team that doesn't want to meet half-way in a simple matter as this, you have bigger problems than just how to get these words into the list. I would focus on resolving the real problem here.
In short - No, you can't do it using only HTML
You need to write simple script which will generate js file containing array and you can include this file to your HTML file.
Basicly script may looks like this:
<?php
if (isset($_POST['code']) && isset($_POST['path'])){
$string = "listOfWords['" . $_POST['code'] . "'] = '" . $_POST['path'] . "';"
$fh = fopen('listofwords.js', 'a');
fwrite($fh, $string);
fclose($fh);
}
?>
<form action="" method="post">
<input type="text" name="code" />
<input type="text" name="path" />
<input type="submit" value="Add code" />
</form>
Of course this script is only for adding, if you need to edit/delete records you should rewrite script according your needs

Replacing Carriage Returns "ch13?" in Datagridview with <br> using ONLY javascript

I have been trying to find a way to replace a carriage return with the html break. I think it is cr13? Not entirely sure. I am new to programming. I have a content page. So i am setting the javascript in the content area. I have many other javascripts in the page. One hides and shows columns. So i have a way to find the columns. But i think i need to find the cells? It is only one column where this is needed. I am using asp.net, with vb.net, importing a sql server 2008 db. Unfortunatly this must be done in just javascript to avoid page reloads on the click of a button.
Thanks.
function showComments() {
Begincol_num = 8
Endcol_num = 9
Commentcol_num = 7
rows = document.getElementById("<%=GridView1.ClientID%>").rows;
for (i = 0; i < rows.length; i++) {
rows[i].cells[Begincol_num].style.display = "none";
rows[i].cells[Endcol_num].style.display = "none";
rows[i].cells[Commentcol_num].style.display = "";
}
}
The idea is put the js to replace the cr with br within this function(if possible). I am at a loss as to where to start to call the replace in the comment cells. There are 30 comment cells, in the comment column at the moment and will only grow as it goes. This function is called on the click of a button that is not meant to return to the server, which is what i meant by only js.
I am trying to be as clear as possible. I know vb and asp but js makes no sense to me.
Thank you for the help.
In javascript, new lines are represented by "\n", the new line character. If you want to replace a new line with a <br />, then use the string replace function
var stringWithBR = stringVarName.replace("\n", "<br />");
Assuming your comments are contained directly inside the cells with no other tags in between, you could do this:
// ...
for (i = 0; i < rows.length; i++) {
rows[i].cells[Begincol_num].style.display = "none";
rows[i].cells[Endcol_num].style.display = "none";
var commentCell = rows[i].cells[Commentcol_num];
commentCell.style.display = "";
commentCell.innerHTML = commentCell.innerHTML.replace("/\n/g", "<br />");
}
// ...
But it is not a clean solution to do such a thing on showing the comments at all. You should do it either directly on the server or else on load. Otherwise, if you show and hide the comments more than once, you will do some unnecessary work which may not be a performance- but definitely a design problem.
After all problems could occur if there are line breaks inside HTML tags inside a comment. You can prevent that by using innerText and textContent but that would erase any tags. Better solutions are complicated.

Javascript variable

I'm struggling to get the result of one variable change another unrelated variable.
I have a script that is generating a random number between 0 and 19, which attaches itself to the global variable "index". I'd like to have another script that can read the result of the "index" variable and assign the appropriate text response from a different array, and post that text into a new variable (lets call it "response"). These two variables need to match up as well, the text ("response") following the associated number ("index"). e.g if the var index=0 then the var response= "good", when var index=1 then var response="bad" so on an so forth for all 20 possible outcomes put each array.
It seems pretty simple, but has eluded me accept for very complex and inefficient (i.e incompatible) means.
Thank you so much in advance, there's some very talented peeps out there!
Thanks for your prompt responses!
Here's some of the code.
var answers= new Array(20);
for (i = 0; i < answers.length; i++)
answers[i] = new Image();
answers[0].src = 'images/answer1.jpg';
//so on an so forth from 0 - 19
var index;
function askQuestion(){
index = Math.floor(Math.random() * (answers.length));}
So I've got the var index returning values which trigger the associated image, but then want to use the result of the index var to output an associated text too (using the another var). I can't believe I'm stumped on such a simple thing! I think I'm over complicating it with multiple variables or doubling the code again. Perhaps I'm just stuffing up the syntax. Damn, my javascript coding aint the greatest. Shouldn't of dropped out of maths all those years ago! Any ideas?
Do you just need this?
var response = yourDifferentArray[window.index];
The syntax window[varName] allows you to retrieve the value of a global variable from anywhere in your code.
So it was really simple. My problem was being too tricky (and a syntax error) by trying to use multiple scripts which weren't communicating. Here's the result.
var answers= new Array(20);
for (i = 0; i < answers.length; i++)
answers[i] = new Image();
answers[0].src = 'images/answer1.jpg';
//so on an so forth from 0 - 19
var index;
var remarks = ["remark0","remark1"] //..so on 0-19
var response;
function askQuestion(){
window.index = Math.floor(Math.random() * (answers.length));}
response = remarks[window.index];
Thank you so much for the help! GOLD STAR!!

Categories