Dynamic class not being inserted when supposed to - javascript

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]);

Related

How to make this JavaScript/jQuery code shorter

Is there a way to loop this four times to make it shorter? I am trying to change the class from standing to sitting and then back again one at a time.
if(sitting > 0) {
$('.standing:first-of-type').removeClass('standing').addClass('sitting');
} else {
$('.sitting:first-of-type').removeClass('sitting').addClass('standing');
}
if(sitting > 1) {
$('.standing:nth-of-type(2)').removeClass('standing').addClass('sitting');
} else {
$('.sitting:nth-of-type(2)').removeClass('sitting').addClass('standing');
}
if(sitting > 2) {
$('.standing:nth-of-type(3)').removeClass('standing').addClass('sitting');
} else {
$('.sitting:nth-of-type(3)').removeClass('sitting').addClass('standing');
}
if(sitting > 3) {
$('.standing:nth-of-type(4)').removeClass('standing').addClass('sitting');
} else {
$('.sitting:nth-of-type(4)').removeClass('sitting').addClass('standing');
}
You can use :lt and :gt selectors.
:lt(index) select all elements at an index less than index within the matched set. :gt(index) select all elements at an index greater than index within the matched set.From jQuery Docs
As the class sitting should be added to all the elements having class .standing whose index is less than the sitting variable value, :lt selector can be used with the variable sitting to select such elements. Then addClass() and removeClass() can be used on the jQuery set of elements to add and remove the passed classes respectively.
$('.standing:lt(' + sitting + ')').removeClass('standing').addClass('sitting');
$('.sitting:gt(' + sitting + ')').removeClass('sitting').addClass('standing');
Well, you can do with an ugly for-loop:
function toggleSitting(sitting){
var initial = 0;
var final = 3;
for(var i = initial; i <= final; i++){
$('.standing:nth-of-type(' + (i+1) +')')
.toggleClass('standing', sitting < i)
.toggleClass('sitting', sitting > i);
}
}
toggleSitting(sitting);
This is just a draft and it's untested, but there is a logic in what you are trying to do. Once you find the logic, you just have use it in a loop. Like that :
var condition;
for(var i = 0; i < 4; i++){
condition = sitting > i;
$('.standing:nth-of-type(' + (i + 1) + ')').toggleClass('standing', !condition).toggleClass('sitting', condtion);
}
Maybe Something like this:
var numberOfPlaces = 4;
for(var i=0; i<sitting && i<numberOfPlaces ; i++){
$('.standing:nth-of-type(' + (i+1) + ')').removeClass('standing').addClass('sitting');
}
for(var i=sitting; i<numberOfPlaces ; i++){
$('.sitting:nth-of-type(' + (i+1) + ')').removeClass('sitting').addClass('standing');
}
or this:
var numberOfPlaces = 4;
for(var i=0; i<numberOfPlaces; i++){
if(i<sitting){
$('.standing:nth-of-type(' + (i+1) + ')').removeClass('standing').addClass('sitting');
}else if(i>=sitting){
$('.sitting:nth-of-type(' + (i+1) + ')').removeClass('sitting').addClass('standing');
}
}
Do you have HTML and CSS to accompany that ?
You can use a variable to specify the 'nth' of type:
$('.standing:nth-of-type(' + i + ')')
although not sure that that works for the case where i = 1. You might need first-of-type there.
Without the CSS and HTML it isn't clear exactly what you want to do.
You might want to look at this also:
https://css-tricks.com/almanac/selectors/n/nth-of-type/

Search Box Function Not Eliminating Correct Value

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.

For loop in Javascript runs only once

Here is my code. I do not quite understand why the for loop runs only once, both inner and outer. nodeList.length and innerNodeList.length show appropriate values when I generate alert messages. I see that both i and j do not increment beyond 0. Kindly point out anything wrong with the code.
function getCategoryElements() {
var newCategoryDiv = document.getElementById("category");
var nodeList = newCategoryDiv.childNodes;
for (var i = 0; i < nodeList.length; ++i) {
var innerNodeList = nodeList[i].childNodes;
alert("innerNodeList Length" + innerNodeList.length.toString());
for (var j = 0; j < innerNodeList.length; ++j) {
if (innerNodeList[j].nodeName == "SELECT") {
alert("inside select Node value " + innerNodeList[j].nodeValue.toString());
document.getElementById("newCategories").value =
document.getElementById("newCategories").value + '<%=delimiter%>' + innerNodeList[j].nodeValue;
} else if (innerNodeList[j].nodeName == "TEXTAREA") {
document.getElementById("newCategoriesData").value =
document.getElementById("newCategoriesData").value + '<%=delimiter%>' + innerNodeList[j].nodeValue;
}
}
}
}
var newCategoryDiv, nodeList, innerNodeList, innerNode, i, j;
newCategoryDiv = document.getElementById("category");
nodeList = newCategoryDiv.childNodes;
for (i = 0; i < nodeList.length; ++i) {
innerNodeList = nodeList[i].childNodes;
alert("innerNodeList Length" + innerNodeList.length.toString());
for (j = 0; j < innerNodeList.length; ++j) {
innerNode = innerNodeList[j];
if (innerNode.nodeName === "SELECT") {
alert("inside select Node value " + innerNode.nodeValue.toString());
document.getElementById("newCategories").value += '<%=delimiter%>' + innerNode.nodeValue;
} else if (innerNode.nodeName === "TEXTAREA") {
document.getElementById("newCategoriesData").value += '<%=delimiter%>' + innerNode.nodeValue;
}
// Will this work?
alert('Does this alert appear');
}
}
I took the liberty to refactor your code and clean it up a little bit. In case you're not aware, all variables have function scope in Javascript, so no matter where you declare them within a single function, Javascript treats them as if the variable declaration is the first statement.
It appears that your code is syntactically correct, and so I think that the most logical place to look for a problem is that there could be an error occurring after the last alert function call.
In order to check this, try adding another alert function call to the end of the inner loop. If it doesn't run, you'll know this is the case.

array search / for loop

I've currently got a implementation which loops through an array within a json document (returned from mongoose) and looks for specific items as below
So what's happening is i'm passing an id in the request header to express and what i need to happen is for it to grab the associated story.users.id.name from the story.users array is returned and then once it has the name send do something with all the other items in the array.
I did try to do this like below:
for (var i = 0; i < story.users.length; i++) {
if (story.users[i].id._id == req.headers.id) {
var name = story.users[i].id.name
} else {
push.apns(story.users[i].id._id, name + " started a new story");
}
}
Where it would loop through grab the name and then do something with all the other users in the array, however sometimes the else argument fires first so the name variable is undefined.
So i resorted to running two if loops after each other like below:
for (var i = 0; i < story.users.length; i++) {
if (story.users[i].id._id == req.headers.id) {
var name = story.users[i].id.name
}
};
for (var i = 0; i < story.users.length; i++) {
if (story.users[i].id._id == req.headers.id) {
} else {
push.apns(story.users[i].id._id, name + " started a new story");
}
}
But there must be a better way to the above rather than looping through an array twice?
What you do looks like the right solution (with the goal you seem to have). There's no real simple way to do only one loop.
You could make it faster and cleaner, though :
var name; // this is just cleaner than to define it in the loop
for (var i = 0; i < story.users.length; i++) {
if (story.users[i].id._id == req.headers.id) {
name = story.users[i].id.name;
break; // don't loop over the other elements
}
};
for (var i = 0; i < story.users.length; i++) {
if (story.users[i].id._id !== req.headers.id) {
push.apns(story.users[i].id._id, name + " started a new story");
}
}

Looping and finding empty array

I'm working on project in which I have to create a search engine through jQuery. Everything has been going great until I started looping through the array.
I don't know whether I'm doing it wrong, but for some reason, when I use a conditional it does not output the statement I want it to say. If I change the conditional to say whether there's something in the array output this, it does. But if the array is empty it does absolutely nothing. Why is that?
for(var i = 0, j = response.length; i < j; i++){
var searchItemRes = response[i];
if(response.length === 0){
$('' + '<ul>' +
'<li><span>Nothing found, try again</span></li>' +
'</ul>'
).appendTo(searchResults);
}
$('' + '<ul>' +
'<li><img src="" /><span> '+searchItemRes.title+'</span></li>' +
'</ul>'
).appendTo(searchResults);
}
Consider this:
// declare local variables
var str, i, item;
// build the HTML source code string
if ( response.length === 0 ) {
str = '<ul><li><span>Nothing found. Please, try again.</span></li></ul>';
} else {
str = '<ul>';
for ( i = 0; i < response.length; i += 1 ) {
item = response[i];
str += '<li><img src=""><span> ' + item.title + '</span></li>';
}
str += '</ul>';
}
// append the string to the DOM
$( searchResults ).append( str );
First off, declare the local variables at the top of the function. As you can see, my code uses 3 local variables.
Next, I doubt that you want to create one UL (list-holder) for each result. It makes more sense to have one UL element which contains all the results (which is what I've implemented in the above code).
Also, I recommend manipulating the DOM only once at the end - the live-DOM should be touched as few times as possible. Therefore, the above code builds the HTML source code string "off-DOM", and only in the end appends (the whole thing) to the DOM.
for (var i = 0, j = response.length; i < j; i++){
var searchItemRes = response[i];
if (response.length === 0) {
$('<ul><li><span>Nothing found, try again</span></li></ul>').appendTo(searchResults);
}
...
}
That condition will never be executed. If i = 0 and j = response.length and it's iterating i < j then it won't iterate at all if response.length == 0 because 0 < 0 will just break out of the loop.
How can code that triggers on response.length == 0 ever execute inside a loop that iterates response.length times?
Perhaps you meant:
if (response.length === 0) {
$('<ul><li><span>Nothing found; try again</span></li></ul>').appendTo(searchResults);
}
else {
for (var i = 0, j = response.length; i < j; i++) {
var searchItemRes = response[i];
$('<ul>' +
'<li><img src="" /><span>' + searchItemRes.title + '</span></li>' +
'</ul>'
).appendTo(searchResults);
}
}

Categories

Resources