How to make this JavaScript/jQuery code shorter - javascript

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/

Related

How to update all child IDs using plain JavaScript

I have a JavaScript function called resetIndex. It works fine but I want to reset all child IDs. How can I do this? Is there any method like firstChild and lastChild?
I'm new with JavaScript. Can anyone help?
I have following function:
function resetIndex(delId) {
for (var i = delId + 1; i < count; i++) {
var currentElement = document.getElementById(i);
currentElement.id = i - 1;
var update = currentElement.childNodes;
update.setAttribute('id', 'deleteLink(' + currentElement.id + ')');
}
count--;
}
You can use
node.children[0]
to get the first one, and
node.children[node.children.length - 1]
to get the last one.
Make sure to check if they exist, first.
To do something to all child-nodes, you can use a for-loop, like
for(let a = 0; a < node.children.length; a++) {
node.children[a].id = "my-new-id";
}

Dynamic class not being inserted when supposed to

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

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.

Merging multiple columns as the table structure is written

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/

loop created element's value always 5

Can someone please tell me why when I click on the [s] href created next to the list of names (myhand) generated it always says selection and i are 5?
var printDD = function(myhand, mydiv){
var dtext = "";
for(var i = 0; i < myhand.length; i++){
dtext += '[s]' + myhand[i] + ', ';
}
mydiv.html(dtext);
for(var i = 0; i < myhand.length; i++){
$('#dd'+i).click(function(){
selection = i;
console.log("sel: " + selection + " i: " + i);
});
}
}
You want to take a look at JavaScript closure inside loops – simple practical example. As the answer to that question says, you can create a function to return one, or you can use inline function invocation in the for loop like so:
for(var i = 0; i < myhand.length; i++) {
$('#dd'+i).click((function(x) {
return function () {
selection = x;
console.log("sel: " + selection + " x: " + x);
}
}(i)));
}
Because the value of i is determined at the time the click handler is run. So it will always have the value of myhand.length - 1, which is the state you left i in after the for-loop.

Categories

Resources