Reputation: 143
I'm trying to create a key mapping that keeps track of the frequency for each character of a string in my createArrayMap() function but I keep getting this error from firebug: TypeError: str.charAt(...) is not a function
I found the charAt() function on Mozilla's developer website it should be a function that exists.
var input;
var container;
var str;
var arrMapKey = [];
var arrMapValue = [];
function initDocElements() {
container = document.getElementById("container");
input = document.getElementById("inputbox");
}
function createArrayMap() {
str = input.value;
for (var i = 0; i < str.length; i++) {
if (arrMapKey.find(str.charAt(i)) == undefined) {
arrMapKey.push(str.charAt(i));
arrMapValue.push(1);
}
}
}
function keyPressHandler() {
createArrayMap();
console.log(arrMapKey);
console.log(arrMapValue);
}
function prepareEventHandlers() {
input.onfocus = function() {
if (this.value == "Start typing here!") {
this.value = "";
}
};
input.onblur = function() {
if (this.value == "") {
this.value = "Start typing here!";
}
};
input.onkeyup = keyPressHandler;
}
window.onload = function() {
initDocElements();
prepareEventHandlers();
};
Upvotes: 11
Views: 60751
Reputation: 11763
This has been answered, but here's my version of your problem JSBIN LINK (also has an object option in addition to the array solution).
I moved some variables around so you'll have less global ones, added comments, and mocked with the output so it'll show it on the page instead of the console.
besides the Array.find()
issues, you weren't initializing your arrays on the build method, and so, you would have probably ended with the wrong count of letters.
HTML:
<div id="container">
<textArea id="inputbox"></textArea></div>
<p id="output">output will show here</p>
JS:
var input, // Global variables
container, //
output; //
/**
* Initialize components
*/
function initDocElements() {
container = document.getElementById("container");
input = document.getElementById("inputbox");
output = document.getElementById("output");
}
/**
* Creates the letters frequency arrays.
* Note that every time you click a letter, this is done from scratch.
* Good side: no need to deal with "backspace"
* Bad side: efficiency. Didn't try this with huge texts, but you get the point ...
*/
function createArrayMap() {
var index, // obvious
tempChar, // temp vars for: char
tempStr = input.value, // string
len = tempStr.length, // for loop iteration
arrMapKey = [], // our keys
arrMapValue = []; // our values
for (var i = 0 ; i <len ; i++) {
// These 2 change each iteration
tempChar = tempStr.charAt(i);
index = arrMapKey.indexOf(tempChar);
// If key exists, increment value
if ( index > -1) {
arrMapValue[index]++;
}
// Otherwise, push to keys array, and push 1 to value array
else {
arrMapKey.push(tempChar);
arrMapValue.push(1);
}
}
// Some temp output added, instead of cluttering the console, to the
// a paragraph beneath the text area.
output.innerHTML = "array keys: "+arrMapKey.toString() +
"<br/>array values:"+arrMapValue.toString();
}
function keyPressHandler() {
createArrayMap();
}
function prepareEventHandlers() {
input.onfocus = function() {
if (this.value == "Start typing here!") {
this.value = "";
}
};
input.onblur = function() {
if (this.value === "") {
this.value = "Start typing here!";
}
};
input.onkeyup = keyPressHandler;
}
window.onload = function() {
initDocElements();
prepareEventHandlers();
};
BTW, as the comments suggest, doing this with an object will is much nicer and shorter, since all you care is if the object has the current char as a property:
/**
* Same as above method, using an object, instead of 2 arrays
*/
function createObject() {
var index, // obvious
tempChar, // temp vars for: char
tempStr = input.value, // string
len = tempStr.length, // for loop iteration
freqObj = {}; // our frequency object
for (var i = 0 ; i <len ; i++) {
tempChar = tempStr.charAt(i); // temp char value
if (freqObj.hasOwnProperty(tempChar))
freqObj[tempChar]++;
else
freqObj[tempChar] = 1;
}
}
Upvotes: 0
Reputation: 1905
You're not going about things in the most efficient manner... What if you changed it to look like this so you are continually updated with each keypress?
var keyMap = {};
...
input.onkeyup = keyPressHandler;
function keyPressHandler(e) {
var char = String.fromCharCode(e.keyCode);
if(!(char in keyMap))
keyMap[char] = 1;
else
keyMap[char]++;
}
Upvotes: 0
Reputation: 74048
The problem is not with String.charAt()
, but with Array.find()
.
The first argument to find
is a callback, but the result of str.charAt(i)
is a character and not a callback function.
To search for an element in your array, you could use Array.indexOf()
as @adeneo already suggested in a comment
function createArrayMap() {
var str = input.value;
for (var i = 0; i < str.length; i++) {
if (arrMapKey.indexOf(str.charAt(i)) == -1) {
arrMapKey.push(str.charAt(i));
arrMapValue.push(1);
}
}
}
See JSFiddle
Upvotes: 5