Trying to reduce redundancies - javascript

I wrote some code, but I am pretty sure, that this could be shorter but my brain just stopped working and therefore I want to ask you about some tipps.
The problem is, that there are kind of redundancies in the code and like I said, I am pretty sure, that some kind of loop or something could handle this problem.
This piece of code is, like the name of the function, for toggling two different contents. This is for simulating a header with two tabs and therefore to present different content, when one of the two tabs are clicked.
function toggleContent() {
if(!firstTab.classList.contains("active")) {
firstTab.classList.add("active");
secondTab.classList.remove("active");
firstContent.classList.add("visible");
secondContent.classList.remove("visible");
} else {
secondTab.classList.add("active");
firstTab.classList.remove("active");
secondContent.classList.add("visible");
firstContent.classList.remove("visible");
}
}

classList has a toggle method with a second argument that may help
function toggleContent() {
var isFirstTabActive = firstTab.classList.contains("active");
firstTab.classList.toggle("active", !isFirstTabActive);
secondTab.classList.toggle("active", isFirstTabActive);
firstContent.classList.toggle("visible", !isFirstTabActive);
secondContent.classList.toggle("visible", isFirstTabActive);
}
This doesn't take into consideration the possibility of even shorter code - however, as the HTML is a mystery, this will do

Related

Javascript: Array not shifting, multiple setTimeout functions (JSON)

I'm really stuck on this javascript question!
So I'm making a web page that will be completely animated (so it can be used for display for example in a television). That animation will be configurable by the user (stored in a database).
Right now, I've already made the code to store the configuration and to get the configuration (I do an AJAX call and save the configuration in an array of json objects) and everything is as it should be.
The problem is in the animation in which I go through the array and use setTimeout function to create animations. To iterate through the array I rotate it
(I use array.push(array.shift()) according to the answer here).
The first time the intervalmaster function is used, everything goes according to plan, but when the function is called again I need to rotate the array once more (because of the last animation) and the array just doesn't rotate!
Bellow I've left a portion of the code that I'm using that reproduces the problem I'm getting. I've also added the array jsonanima with some possible values (In reality the array is probably much bigger and with higher values).
I really don't understand what is happening, I've also considered that this could be a problem of the multiple setTimeout functions because I've read somewhere (couldn't find the link, sorry!) that is not really advised to use multiple setTimeout.
If that's the case is there any other way to do this?
Thank you in advance!
EDIT: Thanks to the comment from mplungjan I've realized that if change the console.log(jsonanimate) to console.log(JSON.stringfy(jsonanima)) it outputs the correct values (the json array rotated). This got me even more confused! Why do I need to JSON.stringfy to get the array in the correct order?!
Anyway, can't test this with the full code now as I'm not in the office, tomorrow I'll give more feedback. Thank you mplungjan.
EDIT2: Finally solved my problem! So the thing was the call to the function recursivegroup (recursivegroup(0);), this call was made before I rotated the array, so when restarting the animation the array would still have the incorrect values and every sub-sequential value was wrong.
A special thanks to mplungjan and trincot for the comments that helped me debug this problem.
Bellow I leave the code corrected so anybody with the same problem can check it out.
jsonanima=[{"VD":5,"A":10,"diff":0.25},{"L":7,"IE":8,"diff":0.25}];
function intervalmaster(flag){
function recursivegroup(index)
{
if(index==0)
{
//animateeach(jsonanima,0);
}
setTimeout(function(){
//HERE IT WORKS
jsonanima.push(jsonanima.shift());
console.log(JSON.stringify(jsonanima));
//animateeach(jsonanima,0);
//removed the if statement, since it was irrelevant as mplungjan noted
recursivegroup(index+1);
},(jsonanima[0]['diff'])*60*1000);
}
//Changed this
//recursivegroup(0);
var mastertime=0;
for(var key in jsonanima)
{
mastertime+=(jsonanima[key]['diff']);
}
console.log(mastertime,flag);
console.log(JSON.stringify(jsonanima));
if(flag==true)
{
jsonanima.push(jsonanima.shift());
console.log(JSON.stringify(jsonanima));
}
//changed to here
recursivegroup(0);
masterinterval=setTimeout(function(){intervalmaster(true)},mastertime*60*1000);
}
intervalmaster(false);

How to _prevent_ divs from appearing in random order

Okay, so I'm learning front-end dev with javascript/jquery/bootstrap through FreeCodeCamp. This is not a core part of the project, but I don't understand it and it's distracting me too much. In this code pen here:
http://codepen.io/JDenman6/pen/zqeGwp/ --
I have an array of Twitch.tv usernames that I check through an API and build divs to display them based on the JSON object comes back from the API call.
The weird thing is that every time I refresh the page, I get the divs in a different (apparently random) order. I'm guessing that the API calls are going out asynchronously and the divs are appearing in the order that the API calls finish.
When I Googled for other people having problems with divs in random order I found many solutions for causing random display order, but nothing on preventing it. So then I went looking for a solution to sorting divs and found this post, Ordering DIVs based on class name using Javascript/Jquery, which led me to this bit of code:
$(function(){
var elem = $('#twitcherList').find('div').sort(sortMe);
$('#twitcherList').append(elem);
});
function sortMe(a, b) {
return a.className < b.className;
}
Only I haven't been able to get it to work. I forked off my original codepen to do some poking around here: http://codepen.io/JDenman6/pen/MeYOJP.
The list of divs in the twitcherList in the html tab is from inspecting the twitcherList after rendering the original code. I thought it might be easier to sort them if they're hard coded, rather than coming in from the API call. I also added a little test div and inserted some code into the sort function to 1) check that it was running and 2) double check that a.classname and b.classname were returning what I thought they were, which they are.
I feel like I'm missing something massive, fundamental, and possibly quite obvious. Any thoughts?
You need to return -1, 0 or 1 based on the condition for proper sorting.
function sortMe(a, b) {
return a.className.localeCompare(b.className);
}
For better browser support use,
function sortMe(a, b) {
return a.className < b.className ? 1 : -1;
}

JavaScript not starting function

I have search for some sort of way to do this, but i can't make it work. It may seem simple but i don't know much about javascript so I have found very little information on the problem and I don't know were is the error at so i'll just briefly explain what it's supposed to do. First here is my code:
function showI(a){
$("#show").fadeIn();
$("#show .load").fadeIn();
$("#show").load("ajax/showi.php?id="+a,$("#show .load").fadeOut("fast"))
}
$('.List-item').on('click touchstart',function(){
var id=$(this).attr("id").split("list-").join();
showI(id);
})
So there's like a button with the class list-item which when click should open a new window with the showI function, but it doesn't(I used before the attribute onClick, but it didn't work on mobile so I changed it to .on(click touchstart))
Any help would be appreciate. (Don't know if this is replicated because i can't find a word to describe the problem)
This line:
$("#show").load("ajax/showi.php?id="+a,$("#show .load").fadeOut("fast"))
calls $("#show .load").fadeOut("fast") and then passes its return value into load as a second argument, exactly the way foo(bar()) calls bar and then passes its return value into foo.
If you're looking for a completion callback, you need to wrap that in a function:
$("#show").load("ajax/showi.php?id="+a, function() {
$("#show .load").fadeOut("fast");
});

Refactoring jQuery to use $(this) and add/remove classes from another element

so I have this idea I'm working on over on Codepen. I've got it working as it is but before I go and add more clickable areas I've realized a massive need to refactor and DRY things up. So far it works but it's ugly as hell and would involve a massive amount of repeated code.
So I'm trying to replace the many $(.class).click(function() { ... }); functions with a switch statement that uses $(this) to populate a single .click function instead. But I'm lost.
You can see everything here and edit it also: http://codepen.io/lukewatts/pen/ubtmI
I feel like I'm close but I've hit a wall. The top commented out part is the DRY attempt while what is uncommented for now is the working version. Click the min, off, max words or the LEDs to see it work.
Thank you very much in advance for any advise on this. PHP is my main language to be honest.
P.S. I had leds.click(function() { ... }) and I replaced it with leds.on(function() { ... }) but still nothing.
I understand what you are trying to do, but that not how the jQuery object works. In order to check for the object to match a selector, you will have to use .is().
As such, you will not be able to use a switch, but you will have to use a serie of chained ifs to achieve the goal the way you are trying, such as
if ( $this.is('.led[data-level="one"]') )
var led = $('p.min a');
var level = "one";
I have updated your CodePen example to work in this way: Codepen
As I mentioned in my comment to the question, though, I am not making any code review here, just fixing what didn't work for you. I am not sure this is actually a better approach than your messy original one, to be entirely honest.
The refactored version looks good for me. If you don't like to use addClass and removeClass you may directly change the class property of the element:
indicator.attr("class", "one on");
The reason your switch statement doesn't work is because every time you create a jQuery object, it gets an Id, so when the switch tries to compare $this to a selector like $(p.min a), they won't be equal. However, if you used multiple if statements with $.is, you could compare:
$this = $(this)
if($this.is('p.min a')) {
// do work
} else if($this.is('p.max a')) {
// do work
}
I wouldn't, however, recommend this approach. For more complex pages, I'd recommend a binding framework like Knockout.js. For something small, you're adding a lot of complexity. For clarity: If this becomes part of a larger control set or system, a binding framework would be useful. For the control as-is, both a binding framework and the OP's current approach are overkill.
You may want to look at event delegation, I find it very helpful to keeping things DRY. Clicks will bubble up the DOM tree to higher elements, and you can register your handler on an ancestral element. This is actually ideal, as you only bind a single handler to a single element, instead of binding to multiple elements and thus you realize a performance benefit in addition to cleaner code.
First thing, wrap all your .led elements in a <div id="leds">:
<div id="leds">
</div>
Now create your handler:
$('#leds').bind('click', function(e){
var target = e.target;
var $target = $(target);
//do interesting stuff
if (target.nodeName === 'A') {
var level = $target.data('level');
if(level = 'one'){
//do more interesting stuff
}
}
}
});

Is it possible to encapsulate event logic to avoid duplicate code?

Say when a checkbox is checked/unchecked, I want specific behavior to occur.
Now if there are multiple points in my code where I set a checkbox as checked/unchecked, I have to run through the same logic ever time.
What is a way I can encapsulate the logic that occurs when a checkbox is checked, and just re-use that logic?
My guess is that you're currently binding click event handlers like this:
$('some-selector').click(function (event)
{
// do fancy stuff here
});
To encapsulate that logic, you just need to switch from using an anonymous function, to a function that you can reuse, like this:
function handleClicks(event)
{
// do fancy stuff here
}
$('some-selector').click(handleClicks);
$('some-other-selector').click(handleClicks);
How's that?
I might also take a guess at the fact that the logic you're writing and rewriting is to wire a "check-all" sort of checkbox to a group of checkboxes. I wrote a jQuery plugin recently to handle exactly this sort of thing.
I never got around to uploading it properly to GitHub - here's the gist of it. Let me know if you'd like to actually use it, and I can explain its usage - it's pretty darn simple.
Just extending what 'Bears will eat you' said about using non-anonymous functions, you should all so integrate your own function library to jquery:
Create your functions like so
$.fn.handleClicks = function (){
$(this).click(function(event){
alert('Click');
return false
})
}
Then you can use them like so, makes things a little more neater and a little lesser code. IMO;
$('a').handleClicks(); ​

Categories

Resources