I am trying to make a simple website where the user types input into a search box, and every time a key is press, their input is compared against the first row of a 2 dimensional array which checks for character matches. If the character they input doesn't match anything, I want it to remove that specific bucket of the array. I have attempted to write basic code for this I thought would work, and have it up at the demo site linked. (Sorry I am just using a free host and havn't optimized the equation table at all so bear with it)
http://fakefakebuzz.0fees.net/
As you can see, the function is not eliminating the appropriate table rows. For example, typing "A" should not eliminate the "Average Current Equation" row because the first letter of that is A, which means matches should not = 0.
I have been looking through this code all morning, and cannot find where I went wrong. I also want to stick to vanilla js.
Any help?
Thanks so much.
I just debugged your code, and the function you use is narrowTable. first remove onkeypress from body node
<body onload="printTable()" onkeypress="narrowTable()">
and add onkeyup instead to you input, like this:
<input type="search" name="equationSearch" id="equationSearch"
placeholder="Equation Search" autofocus="" onkeyup="narrowTable()">
because when you use onkeypress the key value hasn't been added to the input box and your input value has no value in your function, which is:
function narrowTable() {
var newTableContent = "";
var matches = 0;
var input = document.getElementById("equationSearch").value;
//input has no value
for (var i = 0; i < tableData.length; i++) {
for (var j = 0; j < tableData[i][0].length; j++) {
if (input == tableData[i][0].charAt(j)) {
matches++;
}
}
if (matches == 0) {
tableData.splice(i, 1);
}
matches = 0;
}
for (var i = 0; i < tableData.length; i++) {
newTableContent += "<tr><td>" + tableData[i][0] + "</td><td>" + tableData[i][1] + "</td></tr>";
}
document.getElementById("table").innerHTML = newTableContent;
}
the other problem your code has is after printing your table, your tableData variable has changed because you have removed some of indexes. you should reset the tableData to its original value or you can do:
function narrowTable() {
//create a copy of your original array and use currenttableData instead
var currenttableData = tableData.slice();
var newTableContent = "";
var matches = 0;
//your code
}
the other problem here is the way you search for your input value:
for (var j = 0; j < tableData[i][0].length; j++) {
if (input == tableData[i][0].charAt(j)) {
matches++;
}
}
if (matches == 0) {
tableData.splice(i, 1);
}
you can easily do this, instead:
if(tableData[i][0].search("input") == -1){
tableData.splice(i, 1);
}
First, to check if a string is a substring of another string, you can use indexOf. It will return -1 if the string is not found in the other string.
Second, you shouldn't alter the array while you are still looping through it, unless you make sure to alter the counter variable (i in this case) appropriately.
var dataToRemove = [],
i;
for (i=0; i<tableData.length; i++) {
if(tableData[i][0].indexOf(input) == -1) {
// add the index to the to-be-removed array
dataToRemove.push(i);
}
// remove them in reverse order, so the indices don't get shifted as the array gets smaller
for(i = dataToRemove.length - 1; i >= 0; i--) {
tableData.splice(i, 1);
}
dataToRemove = [];
for (i=0; i<tableData.length; i++) {
newTableContent += "<tr><td>" + tableData[i][0] + "</td><td>" + tableData[i][1] + "</td></tr>";
}
I haven't tested this code, but it should at least give you a better idea of how to make this work.
Related
I have a problem, when I used input[index] in the statement the reverse word didn't match the value of inputString. But this works in C#. When I try it in JavaScript is not working. I want to learn what are the other alternative way of .char() method. Can anybody solve my problem?
strReverse = "";
input = document.getElementById("inputValue").value;
i = input.length;
for(var j = i; j >= 0; j--) {
strReverse = strReverse + input.charAt(j); // i used input[index]
}
If you wish to use input[index] instead of input.charAt() then you need to address the issue that you are setting i = input.length;
So when you enter your loop for the first iteration, j will be equal to i. Meaning that you are trying to access the character at the index equal to the length of the string (when you do input[j]). However, as arrays and string indexing starts at zero in javascript (and in most languages), there is no index at i (the length of the string), but, there is an index at i-1, which will give the last character in the string. Thus, if you want to reverse your array using input[j] you need to start j in your for loop as j = i - 1.
Take a look at the snippet for a working example:
strReverse = "";
input = "level";
i = input.length;
for(var j = i-1; j >= 0; j--) {
strReverse = strReverse + input[j]; // i used input[index]
}
if(strReverse === input) {
alert(input +" is a palindrome!")
} else {
alert(input +" is not a palindrome!");
}
I have a for loop that is generating some HTML content:
var boxes = "";
for (i = 0; i < 11; i ++) {
boxes += "<div class=\"box\"><img src=\"unlkd.png\"/></div>";
}
document.getElementById("id").innerHTML = boxes;
I want to display 3 boxes in one row, then below them 2 boxes in one row, then 1, then 3 again, 2, and 1.
First i thought of using the if statement to check whether i > 2 to add a line break, but it will also add a line break after every box past the third one. Nothing comes to mind, and my basic knowledge of javascript tells me I'll have to make a loop for each row I want to make. Any advice?
I would use a different approch :
Use a array to store the number of item per row :
var array = [3, 2, 1, 3, 2];
Then, using two loops to iterate this
for(var i = 0; i < array.length; i++){
//Start the row
for(var j = 0; j < array[i]; ++j){
//create the item inline
}
//End the row
}
And you have a pretty system that will be dynamic if you load/update the array.
PS : not write javascript in a while, might be some syntax error
Edit :
To generate an id, this would be simple.
create a variable that will be used as a counter.
var counter = 0;
On each creating of an item, set the id like
var id = 'boxes_inline_' + counter++;
And add this value to the item you are generating.
Note : This is a small part of the algorithm I used to build a form generator. Of course the array contained much more values (properties). But this gave a really nice solution to build form depending on JSON
You can try something like this:
Idea
Keep an array of batch size
Loop over array and check if iterator is at par with position
If yes, update position and index to fetch next position
var boxes = "";
var intervals = [3, 2, 1];
var position = intervals[0];
var index = 0;
for (i = 0; i < 11; i++) {
boxes += "<div class=\"box\"><img src=\"unlkd.png\"/></div>";
if ((position-1) === i) {
boxes += "<br/>";
index = (index + 1) % intervals.length;
position += intervals[index]
}
}
document.getElementById("content").innerHTML = boxes;
.box{
display: inline-block;
}
<div id="content"></div>
var boxes = "",
boxesInRow = 3,
count = 0;
for (i = 0; i < 11; i ++) {
boxes += "<div class=\"box\"><img src=\"unlkd.png\"/></div>";
count++;
if(count === boxesInRow) {
boxes += "<br/>";
boxesInRow -= 1;
count = 0;
if (boxesInRow === 0) {
boxesInRow = 3;
}
}
}
document.getElementById("id").innerHTML = boxes;
var i;
var boxes = "";
for (i = 0; i < boxes.length; i++) {
boxes += "<div class=""><img src=""/></div>";
function displayboxes() {
"use strict";
for (i = 0; i < boxes.length; i++) {
out.appendChild(document.createTextNode(boxes[i] + "<br>"));
}
}
displayboxes(boxes);
Basically, I want to add a class to every list item, and each class has to be specific to a "house". So, I've created an array to store all the houses, and everything seems fine. The problem seems to be in the last for loop, where the classes are added, and their value are the ones store in the previous houseColours[] array: however, when I look in the console, the classes are not inserted.
Even more weird, if I manually insert a class in the console by doing something like this:
$('li:eq(0)').addClass(houseColours[0]);
... it works just fine. What could be the problem? Thanks.
function chart()
{
houseColours = [];
var html = "<ol start='0'>";
for (var i = 0; i < shuttle.seats.length; i++)
{
if (shuttle.seats[i] == null)
{
html += "<li>Empty Seat</li>";
}
else
{
for (var j = 0, n = PASSENGERS.length; j < n; j++)
{
if (shuttle.seats[i] == PASSENGERS[j].name)
{
var house = PASSENGERS[j].house;
break;
}
}
houseColours.push(house);
html += "<li>" + shuttle.seats[i] + ' at ' + house + "</li>";
}
}
html += "</ol>";
$("#chart").html(html);
for (var k = 0, banners = houseColours.length; k < banners; k++)
{
$('li:eq(k)').addClass(houseColours[k]);
}
}
In your selector, $('li:eq(k)') the k is part of the selector string, you should use it as a variable (outside of string), like below:
$('li:eq(' + k + ')').addClass(houseColours[k]);
It's better to use .eq method instead of :eq selector, however:
$('li').eq(k).addClass(houseColours[k]);
I'm struggling to get the input value from a control in JavaScript, and I think it may have something to do with the collection of controls I'm looping through.
My page consists of many input controls with decimals in them. I'm only interested in controls starting with the name 'txtinput', and I need to tally up the values in each one. However, when I do this with the code below, all I seem to be getting out is a JSON looking string for each element.
function TallyPoints() {
var eles = [];
var inputs = document.getElementsByTagName("input");
var total = 0;
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].name.indexOf('txtpoints') == 0) {
total += document.getElementsByName(inputs[i].name)[0].value;
}
}
alert('Total: ' + total.toString());
};
What I end up with is a value that looks like this:
Total: 0{"enabled":false,"emptyMessage":"","validationText":"333.33","valueAsString":"333.33","minValue":-70368744177664,"maxValue":70368744177664,"lastSetTextBoxValue":"333.33"}{"enabled":false,"emptyMessage":"","validationText":"5.66","valueAsString":"5.66","minValue":-70368744177664,"maxValue":70368744177664,"lastSetTextBoxValue":"5.66"}
Any ideas?
You probably want parseFloat() so your addition works properly (fiddle):
var inputs = document.querySelectorAll("input[name^=txtpoints]");
var total = [].reduce.call(inputs, function (p, c) {
return p + (parseFloat(c.value) || 0);
}, 0);
See also parseInt(), isNaN(), and Array.prototype.reduce()
Try this:
function TallyPoints() {
var inputs = document.getElementsByTagName("input");
var total = 0;
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].name.indexOf('txtpoints') == 0) {
var val = parseFloat(inputs[i].value);
if (!isNaN(val)) {
total += val;
}
}
}
alert('Total: ' + total);
};
parseFloat is needed to convert the input from a string to a number, so that + will do addition rather than concatenation. There's no need to use getElementsByName, since you already have the element in inputs[i]. There's no need to use total.toString(); concatenating a number to a string converts it automatically.
The if (!isNan(val)) test skips over the inputs that don't contain numbers.
You could also use document.querySelectorAll('input[name^=txtpoints]') to find the relevant input elements in one step.
I am trying to group multiple columns on my table by collapsing them into a single column and then use a UL list to separate the categories:
For this, what I am doing is adding a boolean to toggle the start/stop stacking, like this:
cols[0][0]="Name";
cols[0][1]=true; //<--toggler
cols[1][0]="Age";
cols[1][1]=false;
cols[2][0]="[M/F]";
cols[2][1]=false;
cols[3][0]="E-mail";
cols[3][1]=true;//<--toggler
However, using this method I have some problems:
I haven't managed to make two consecutive groups: [A][B+C][D+E][F]
the code is pretty hard to read, also to understand exactly what the toggle does
My code to write the head is the following:
document.writeln("<table><thead><tr>");
tmp = "<th>#";
flag = false;
for(i = 0; i < cols_len; i++){
if(cols[i][1]){ //if stack-toggler
if(flag){
tmp += "</th><th>-";
}
flag = !flag;
}
if(!flag){
tmp += "</th><th>" + cols[i][0];
}
}
if(flag){
tmp += "</th><th>-";
}
document.writeln(tmp + "</th></tr></thead><tbody>");
And then for the body of the table:
for(i = 0; i < 20; i++){ //some number of rows
if(i){
document.writeln("</tr>");
}
document.writeln("<tr><td>" + i + "</td>");
tmp = "";
flag = false;
for(j = 0; j < cols_len; j++){
if(cols[j][1]){ //if stack-toggler
if(flag){
document.writeln("<td><ul>" + (tmp.replace(/<td/g, "<li").replace(/td>/g, "li>")) + "</ul></td>");
tmp = "";
}
flag = !flag;
}
if(flag){
tmp += "<strong>" + cols[j][0] + ":</strong><br>";
}
tmp += "<td>...</td>";
if(!flag){
document.writeln(tmp);
tmp = "";
}
}
if(flag){
document.writeln("<td><ul>" + (tmp.replace(/<td/g, "<li").replace(/td>/g, "li>")) + "</ul></td>");
}
}
document.writeln("</tr></tbody></table>");
»The full code and demo can be found in this jsFiddle.
I feel this is the wrong approach, it sucks in every way and more importantly, I can't have two or more consecutive groups!, after I start stacking columns, whenever I want to stop, the next column must be alone (and not another group).
I have played around with the booleans and it is simply impossible, I can't figure it out, I already reduced the code to the most readable way and tried to rewrite parts of it but I keep getting the same results.
I made a slight change to the data model. Instead of "toggle" the boolean says if the next guy stacks or not (that is if it is true then put the next one below me.)
So the data looks like this:
/*0:caption, 1:stack-toggler*/
cols[0][0]="Name";
cols[0][1]=true; //<--stack next below
cols[1][0]="Age";
cols[1][1]=true; //<--stack next below
cols[2][0]="[M/F]";
cols[2][1]=false;
cols[3][0]="E-mail";
cols[3][1]=false;
cols[4][0]="Website";
cols[4][1]=false;
cols[5][0]="Notes";
cols[5][1]=false;
And then the code can be simple -- like this (a trick I used, you can change the loop variable internal to the loop -- so we only loop on the outer loop when we change columns.)
for(i = 0; i < 20; i++){ //some number of rows
buildHTML("<tr><td>" + i + "</td>");
for(j = 0; j < cols_len; j++){
buildHTML("<td>");
if (cols[j][1]) {
buildHTML("<ul>"+cols[j][0]+"</ul>");
// loop till we are at the penultimate
while (cols[j+1][1]) {
j++;
buildHTML("<ul>"+cols[j][0]+"</ul>");
}
j++;
buildHTML("<ul>"+cols[j][0]+"</ul>");
}
else {
buildHTML(cols[j][0]);
}
buildHTML("</td>");
}
buildHTML("</tr>");
}
buildHTML("</tbody></table>");
I did not bother with the header, you can figure that out I'm sure.
Here is the fiddle:
http://jsfiddle.net/eajQy/3/
Of course with javascript you can get fancy. Since what you really have is an array of arrays for the columns you could represent that like this:
// array of arrays -- one element std, 2 or more a list
newcols = [ ["Name","Age","[M/F]"] , ["E-Mail"] , ["Website"], ["Notes"] ];
Then to make your table you could use map and join like this:
buildHTML("<tr><td>" + i + "</td>");
strArray = $.map(newcols, function (anArray) {
if (anArray.length == 1) {
return "<td>"+anArray[0]+"</td>";
}
else {
return "<td><ul>"+anArray.join("</ul><ul>")+"</ul></td>";
}
});
buildHTML(strArray.join(""));
buildHTML("</td></tr></tbody></table>");
Here is a fiddle:
http://jsfiddle.net/eajQy/4/
Single line solution (because every question should have a single line solution):
http://jsfiddle.net/eajQy/5/