My "toggle class" javascript is not working - javascript

I am using this little script to toggle classes of an element on click of another element. Here is the stripped down code:
//Toggle comments
function togglecomments() {
function shiftcomments() {
var comments = document.getElementsByTagName('aside')[0];
if(comments.className = "hide"){comments.className = "show";}
else{comments.className = "hide";};
}
var commenttoggle = document.getElementById('toggle-comments');
bindEvt(commenttoggle, "click", shiftcomments);
}
bindEvt(window, "load", togglecomments);
The thing is it works once, but after that on click the class does not toggle anymore. For those interested here is the event handler I use: http://pastebin.com/md3dPvMJ (It worked fine before so it shouldn't be the problem.)
Any ideas what I did wrong?
Thanks for your feedback guys!

In your if statements you've got this:
if(comments.className = "hide")
It should be:
if(comments.className === "hide")
This would also work:
if(comments.className == "hide")
What you are actually doing up there is changing the className to "hide", not checking for equality.
For the difference between == and === I'll actually point you to another question here at stackoverflow: Which equals operator (== vs ===) should be used in JavaScript comparisons?

This is a little function I'm using, with jQuery, but it can be updated.
toggleClass = function (obj, className) {
var currentClass = $(obj).attr('class'),
hasIt = false;
if (currentClass.indexOf(className) < 0) {
currentClass += " " + className;
hasIt = true;
} else {
currentClass = currentClass.replace(className, "");
hasIt = false;
}
$(obj).attr('class', currentClass);
return hasIt;
};

Related

Optimising the Javascript/jQuery code for iPhone browsers

I'm building a website, primarily for mobiles. I had the following jQuery code
$(".reg_action").click(function () {
var action = $(this).attr("id");
var ele = $(".reg_line.selected");
var icon = $(this).html();
if (action == "deepsleep") {
var color = "#33bb45";
} else if (action == "sleep") {
var color = "#99ef96";
} else if (action == "awake") {
var color = "#e1f648";
} else if (action == "up") {
var color = "#fb0707";
}
ele.find(".reg_segment").val(action);
ele.find(".reg_color").css("background-color", color);
ele.find(".reg_icon").html(icon);
// Move on
ele.removeClass("selected");
ele.next().addClass("selected");
})
I know it might not be the best way all of it, but anyways it is EXTREMELY slow on iPhones - not fully tested, but seems like it is a general problem, even on the newer. I tried making it in JS indstead (again, might not be perfect):
function lineAction(action) {
if (action == "deepsleep") {
var color = "#33bb45";
} else if (action == "sleep") {
var color = "#99ef96";
} else if (action == "awake") {
var color = "#e1f648";
} else if (action == "up") {
var color = "#fb0707";
}
var ele = document.getElementsByClassName("selected");
ele[0].childNodes[1].value = action;
ele[0].childNodes[3].style.backgroundColor = color;
var classes = document.getElementsByClassName("selected");
classes[0].nextSibling.classList.add("selected");
classes[0].className = classes[0].className.replace(/\bselected\b/, '');
}
But even that does not seem to help. Any suggestions how to speed this up a lot? I've been googling, and it seems like DOM manipulation is just slow on iPhone. Is there a solution?
Would it for example help to make the 5 states of each line (default, deepsleep, sleep, awake, up) and then just hide/show the one needed? Pageload is not an issue at all.
Use object with keys to match and the corresponding value to be set as the value of the key. Then the value can be accessed by using the key. e.g. color[action]
Reuse the cached reference of the DOM element
Use remove method of classList to remove a class from a element, no need of ragex here
Instead of using the click event, use touchstart event
Here is the VanillaJS updated code.
var color = {
'deepsleep': '#33bb45',
'sleep': '#99ef96',
'awake': '#e1f648',
'up': '#fb0707
};
function lineAction(action) {
var ele = document.getElementsByClassName("selected");
ele[0].childNodes[1].value = action;
ele[0].childNodes[3].style.backgroundColor = color[action];
ele[0].nextSibling.classList.add("selected");
ele[0].className.remove('selected');
}

onclick has to be clicked twice to fire

My onclick function won't fire unless it is clicked twice. I am very new to javascript but so far i trie moving around the var obj line, and changing the =="none" to "none"?"empty"; which are both things I didn't understand but saw other people did to fix this problem. Neither worked.
+
function showDiv(id){
var obj = document.getElementById(id);
if( obj.style.display == "none") {
obj.style.display='block'
}
else{
obj.style.display='none'
}
}
<div id="show1">
Roughly 2-3 months.
</div>
Your problem is, that you use the style property of the element directly. Assuming, that you did not set obj.style.display = "none"; in your code explicitly, the value remains undefined until the first click. After the first click it is set and everything works like you want it to.
To solve it use getComputedStyle() to access the element's style. This includes all styles set via CSS:
function showDiv(id){
var obj = document.getElementById(id),
compStyle = window.getComputedStyle( obj );
if( compStyle.display == "none") {
obj.style.display='block'
} else {
obj.style.display='none'
}
}
You should use strict equal operators to prevent from undefined style rule.
I would rather use addEventListener instead of onclick to keep my code cleaner, here is a jsfiddle with my version (some extras as dataset and triple conditional are there, but they are not necessarily needed in your example)
var showDiv = function (ev) {
var id = ev.currentTarget.dataset.id;
var obj = document.getElementById('show' + id);
obj.style.display = (obj.style.display === "none") ? 'block' : 'none';
};
http://jsfiddle.net/mindcookin/06nvkay7/4/

Disable a Link after it is clicked --no jquery

i want to disable my link when it is clicked .
checkletter is a function which checks if letter is available in word for my hangman game.
<span id="A">A</span>
i tried using this
a.visited{
display:none;
}
it doesn't seem to be working
Please advice!!
document.querySelector('#A a').style.pointerEvents = 'none';
** http://caniuse.com/#search=pointer-events
Can you just use your checkLetter function?
function checkLetter(letter) {
// Do stuff
document.getElementById(letter).style.display = "none";
}
update
To disable the link instead of hiding it (as requested in comment) see this link: http://jsfiddle.net/J67eY/1/
EDIT:
Very Fun Fiddle
Long story short: assuming link is assigned to your link:
link.href = null;
will disable the link entirely.
I got excited and posted too quickly. Here's what you want :)
var links = document.links || document.anchors || document.getElementsByTagName('a');
for (var i = 0, j = links.length; i < j; i++) {
addEvent(links[i], 'click', disable);
}
function disable(evt) {
var e = evt || window.event,
link = (e.currentTarget) ? e.currentTarget : e.srcElement;
checkLetter(link.innerHTML);
link.href = null;
return false;
}
function addEvent(element, myEvent, fnc) {
return ((element.attachEvent) ? element.attachEvent('on' + myEvent, fnc) : element.addEventListener(myEvent, fnc, false));
}
This code also assumes you removed javascript:checkLetter('A') from your link's href="". Instead, I call it inside the function using the letter that it is (link.innerHTML)

Javascript show div on HTML select

I've been playing with javascript to create a drop down list that shows a div depending on which option is selected.
All the code can be seen here:
http://jsfiddle.net/nmdTy/
var select = document.getElementById('test'),
onChange = function(event) {
var shown = this.options[this.selectedIndex].value == 1;
document.getElementById('hidden_div').style.display = shown ? 'block' : 'none';
};
I want to know how do I streamline this code and remove repetition - maybe some kind of loop?
Another code :
var select = document.getElementById('test'),
nbItems = 2,
onChange = function (event) {
var val = this.options[this.selectedIndex].value;
for (var i = 1; i <= nbItems; i++) {
document.getElementById('hidden_div' + i).style.display = val == i ? 'block' : 'none';
}
};
http://jsfiddle.net/nmdTy/11/
You don't need two event handlers, you can use variables (shown below) to determine which div needs to be displayed or hidden.
var select = document.getElementById('test'), onChange = function(event) {
var div1 = 'hidden_div';
var div2 = 'hidden_div2';
var index1 = this.options[this.selectedIndex].value == 1;
var index2 = this.options[this.selectedIndex].value == 2;
if(index1 || index2){
document.getElementById(div1).style.display = index1 ? 'block' : 'none';
document.getElementById(div2).style.display = index2 ? 'block' : 'none';
}
else{
document.getElementById(div1).style.display = 'none';
document.getElementById(div2).style.display = 'none';
}
};
// attach event handler
if (window.addEventListener) {
select.addEventListener('change', onChange, false);
} else {
// of course, IE < 9 needs special treatment
select.attachEvent('onchange', function() {
onChange.apply(select, arguments);
});
}
Working Fiddle
I'm not really sure what do you mean by "repetition" but my guess is, that you don't want to type every each of the divs to be hidden/shown.
There could be multiple approaches to such task. The most universal is to have the div id's in a separate array. Then you can hide all but the selected div.
var divs = ["hidden_div1", "special_hidden", "one_more_hidden"];
var select = document.getElementById('test');
var onchange = function(event) { //Use var!
var shown = this.options[this.selectedIndex].value;
for(var i=0; i<window.divs.length; i++) { //It would be more effective to save last shown div in a variable, but I've chosen this aproach with loop
var div = document.getElementById(window.divs[i]);
if(div!=null) {
if(i==shown)
div.style.display="block";
else
div.style.display="none";
}
}
};
select.addEventListener("change", onchange); //Could type the function right here, without using "onchange" variable
In my code, <option> value represents index in the array. Here is jsFiddle.
Delegating a change event in IE<9 is a pain. It is possible, check this question to see how it's done, but it's not what you call elegant.
But your code doesn't delegate the event, so just attaching the handler directly at the onload event should do the trick (and it's X-browser compatible):
document.getElementById('test').onchange = function(e)
{
e = e || window.event;//the only IE headache
var shown = this.options[this.selectedIndex].value == 1;
document.getElementById('hidden_div').style.display = shown ? 'block' : 'none';
//^^ could keep a reference to this in a closure
};
The full code (with onload and closure reference to hidden div and preventing memory leaks in ie) should look like this:
var winLoad = function(e)
{
var hiddenDiv = document.getElementById('hidden_div');
document.getElementById('test').onchange = function(e)
{
var shown = !!(this.option[this.selectedIndex].value == 1);//to be safe, coerce to bool
hiddenDiv.style.display = shown ? 'block' : 'none';
};
if (window.addEventListener)
{
return window.removeEventListener('load',winLoad,false);
}
return window.detachEvent('onload',winLoad);
};
if (window.addEventListener)
{
window.addEventListener('load',winLoad,false);
}
else
{
window.attachEvent('onload',winLoad);
}
that should work fine on all major browsers, even IE7 (probably IE6, too)

Performance issues in javascript onclick handler

I have written a game in java script and while it works, it is slow responding to multiple clicks. Below is a very simplified version of the code that I am using to handle clicks and it is still fails to respond to a second click of 2 if you don't wait long enough. Is this something that I need to just accept or is there a faster way to be ready for the next click?
BTW, I attach this function using AddEvent from the quirksmode recoding contest.
var selected = false;
var z = null;
function handleClicks(evt) {
evt = (evt)?evt:((window.event)?window.event:null);
if (selected) {
z.innerHTML = '<div class="rowbox a">a</div>';
selected = false;
} else {
z.innerHTML = '<div class="rowbox selecteda">a</div>';
selected = true;
}
}
The live code may be seen at http://www.omega-link.com/index.php?content=testgame
You could try to only change the classname instead of removing/adding a div to the DOM (which is what the innerHTML property does).
Something like:
var selected = false;
var z = null;
function handleClicks(evt)
{
var tmp;
if(z == null)
return;
evt = (evt)?evt:((window.event)?window.event:null);
tmp = z.firstChild;
while((tmp != null) && (tmp.tagName != 'DIV'))
tmp = tmp.firstChild;
if(tmp != null)
{
if (selected)
{
tmp.className = "rowbox a";
selected = false;
} else
{
tmp.className = "rowbox selecteda";
selected = true;
}
}
}
I think your problem is that the 2nd click is registering as a dblclick event, not as a click event. The change is happening quickly, but the 2nd click is ignored unless you wait. I would suggest changing to either the mousedown or mouseup event.
I believe your problem is the changing of the innerHTML which changes the DOM which is a huge performance problem.
Yeah you may want to compare the performance of innerHTML against document.createElement() or even:
el.style.display = 'block' // turn off display: none.
Profiling your code may be helpful as you A/B various refactorings:
http://www.mozilla.org/performance/jsprofiler.html
http://developer.yahoo.com/yui/profiler/
http://weblogs.asp.net/stevewellens/archive/2009/03/26/ie-8-can-profile-javascript.aspx

Categories

Resources