The function in question:
function toggleElementClass(element, className) {
if (element.className.indexOf(className) > -1) {
element.className = element.className.replace(new RegExp(className, 'g'), '');
} else {
element.className += " " + className;
}}
I'm trying to identify issues with this code. I've had experience with jQuery and JavaScript here and there, but I cannot seem to come to a solid conclusion with what I've seen so far. I've seen a lot of examples using the current .toggleClass() function from jQuery but none that help me analyze the code above.
One problem I think I can identify is that it never seems to remove a class. Only adds more but I've had problems attempting to test this on plunker. Any help would be appreciated. What problems can you identify with this method?
Want to make an edit: This questions is purely for my own understanding. I'm not intending to use this or re-write a tool that already exists in jQuery! Thanks for all who have submitted answers so far!
Edit: For anyone who may be interested. This isn't a perfect solution (adds spaces between classes the more you toggle). It seems to get around the false positive the original code would cause!
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
</head>
<body>
<h1 class="football">Hello Plunker!</h1>
<script>
function toggleElementClass(element, className) {
var regex = new RegExp('\\b' + className + '\\b', 'g');
if (regex.test(element.className)) {
element.className = element.className.replace(regex, '');
} else {
element.className += " " + className;
};
};
$("h1").click(function() {
toggleElementClass(this, "test")
})
</script>
</body>
</html>
The logic is fine for most circumstances, although will get false positives when searching for foo and a football class is available.
The specific issue with your code is with how you are attaching the click event to the h1. Currently you're setting the result of the function call to the event handler, not the function reference. This means the function is called immediately on load and the scope is not what you're expecting (it's the window instead of the h1) hence the 'undefined' error you receive.
To fix this you need to wrap the click event handler in an anonymous function:
function toggleElementClass(element, className) {
if (element.className.indexOf(className) > -1) {
element.className = element.className.replace(new RegExp(className, 'g'), '');
} else {
element.className += " " + className;
};
};
$("h1").click(function() {
toggleElementClass(this, "a")
})
.a {
color: #c00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 class="a">Hello Plunker!</h1>
That being said the function is completely redundant, as you can use either jQuery's toggleClass():
$("h1").click(function() {
$(this).toggleClass('a')
})
.a {
color: #c00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 class="a">Hello Plunker!</h1>
Or alternatively you can use classList.toggle():
document.querySelector('h1').addEventListener('click', function() {
this.classList.toggle('a');
});
.a {
color: #c00;
}
<h1 class="a">Hello Plunker!</h1>
Here are some problems:
You'll get false positives for a partial class name match (searching for foo, will match foobar). If you fix this problem, be careful how you do it, since you must allow for more than one kind of space separator.
The replacement will leave extra spaces, which isn't huge, but can add up.
You're using a regular expression with the assumption that the class name will not contain any special regex characters. You already are getting the index, so why not use that? You'll need a loop to make sure they all get removed, but it's going to be safer.
Related
Why is the if statement not working here:
<!DOCTYPE html>
<html>
<body>
<style>#myP{cursor:pointer;}</style>
<p id="myP">random text</p>
<button type="button" onclick="myFunction()">alert aaa</button>
<script>
function myFunction(){
if(document.getElementById("myP").style.cursor=="pointer"){
alert("aaa");
}
}
</script>
</body>
</html>
Also, I want to know how to make the if statement work with a linked cursor like:
<style>#myP{cursor: url(../randomFolder/cursor.png) 5 8, auto;}</style>
Use this instead :
if (window.getComputedStyle(document.getElementsByTagName('body')[0]).cursor == 'pointer')
.style only works for inline CSS. window.getComputedStyle() will let you retrieve styles set via non-inline CSS.
For your second question, matching the linked image cursor is a little trickier than just matching a simple string like "pointer", because you're including a path which will be canonicalized to the full URL, as you can see below ("https://stacksnippets.net" is included in the path even though it wasn't specified in the CSS.) It's probably best to test for a substring of the full cursor value, so you don't run into problems where your code works on "yourdomain.com" but not on "www.yourdomain.com":
var myFunction = function() {
var A = document.getElementById('a');
var B = document.getElementById('b');
console.log(window.getComputedStyle(A).cursor);
console.log(window.getComputedStyle(B).cursor);
if (window.getComputedStyle(A).cursor == 'pointer') {
console.log("A matched");
}
var bCursor = window.getComputedStyle(B).cursor;
if (bCursor.indexOf('cursor.png') > -1) { // not hardcoding the full URL here
console.log("B matched");
}
}
#a {
cursor: pointer
}
#b {
cursor: url(randomFolder/cursor.png) 5 8, auto;
}
<p id="a">random text</p>
<p id="b">more random text</p>
<button onclick="myFunction()">alert</button>
You can use jQuery with css function and it will return you the kind of cursor which you need in a short code.
$('#myP').css('cursor')
I'm a long-time procedural programmer now assigned to a web-app and studying jquery from a book. The exercise is to run some code on one div selected from a row of 4 <div>s using .each(). I attempted to store the div object that was clicked, then match it as the .each looped thru the 4 divs.
My following code works after trial and error, but the same $(this) seems to sometimes point to a div object, and sometimes to an event object.
How do you explain that behavior?
I understand that .context is deprecated. I tried .target but that didn't seem to work. Is there something else that I should be using?
My primary interest is to understand what is going on (question 1), so if you can provide an explanation and not just an alternative solution (question 2), I'd really appreciate it. Thank you in advance. Here are the code snippets:
<body>
<div id="header">
<h2>Jump for Joy Sale</h2>
</div>
<div id="main">
<div class="guess_box"><img src="images/jump1.jpg"/></div>
<div class="guess_box"><img src="images/jump2.jpg"/></div>
<div class="guess_box"><img src="images/jump3.jpg"/></div>
<div class="guess_box"><img src="images/jump4.jpg"/></div>
</div>
<script src="scripts/jquery-1.6.2.min.js"></script>
<script src="scripts/my_script.js"></script>
</body>
Jscript
$(document).ready(function()
{
$(".guess_box").click(checkForCode);
function checkForCode()
{
var code_box = 2;
var discount_code = getRandomNum(1,100);
var clicked = $(this); // debugger says clicked is an event object
var iteration = 0;
$(".guess_box").each(function()
{
if ($(this).context === $(clicked).context) //act like event objs
{
if (iteration === code_box)
{
// clicked on correct box
$(this).addClass("discount"); //same $(this) acts like <div>
discount_msg = "<p>Your Code: CODE"+ discount_code +"</p>";
return(false);
}
}
else
{
if (iteration === code_box)
{
// if wrong box clicked, highlight the right one
$(this).addClass("no_discount");
discount_msg = "<p>Sorry, no discount this time</p>";
return(false);
}
}
iteration += 1;
});
$(".guess_box").unbind();
$(this).append(discount_msg); // don't worry about this line
} //checkForCode
}); //ready
The context of this depends on where and how it's used. if your function is called by an an event it will refer to the target of the event, otherwise it will refer to the object being called upon.
What youre seeing in your console is not this, or an event object, it's a jQuery object. If you want to inspect this you need to remove the jQuery wrapper function.
console.log(this);
Event example..
<div>click me</div>
$("div").click(function(){
// referring to the div itself
$(this).text("you clicked me");
// Note you can do it without jQuery as well
// this.innerHTML = "you clicked me";
});
object example
function something(){
this.something = "something";
this.doAThing = function(){
this.something = "something new";
}
}
var thing = new something();
thing.doAThing();
alert(thing.something);
Thanks to those that responded. As Pamblam indicated, I was confusing this and $(this). I replaced 2 lines in my code and it makes more sense:
clicked = $(this) becomes clicked = this
if ($(this).context === $(clicked).context) becomes
if (this === clicked)
Here is my attempt that doesn't seem to be working:
$('container').find("[data-slider='" + one + "']").removeClass('hidden');
Here is the full function that is wrapped in a document. ready function
$("#service-icon").on('click', function(){
var $this = $(this);
event.preventDefault();
$this.addClass('ease-transition').toggleClass('active-slider-btn');
$(".page-wrapper").find("[data-slider='" + one + "']").toggleClass("hidden");
});
The error that I am getting is:
"Uncaught ReferenceError: one is not defined"
Things to check:
Is `container` a class or id? If so you'll need to add a `.` or `#` respectively
That the expression in the `.find()` function returns what you're expecting
Can you post a link to a JSFiddle or something?
I have a working example here that is similar to your situation.
HTML
<div class="container">
<div data-slider="1" class="hidden">1</div>
<div data-slider="2">2</div>
</div>
<button id="show-1">show slider 1</button>
CSS
.hidden {
display: none;
}
JavaScript
var one = "1";
$("#show-1").click(function(e){
$(".container").find("[data-slider='" + one + "']").removeClass("hidden");
});
Something like this has to work:
$('.page-wrapper').find("[data-slider='" + one + "']").removeClass('hidden');
See it working here: http://jsfiddle.net/sNp7x/2/
Maybe the data attribute is set via javascript as well, so you have to be aware of the timing?!
I am doing length validation with java script. If input is short in length I shows an alert and after that I want to set focus back in the text field. It is working in IE but not working in FF. I have searched a lot on google but no solution could work plz guide and help me.
function IsLengthOK(_title,_control,_length)
{
if(_control.value.length < _length)
{
alert("'"+ _title +"'" + " must be minimum "+_length+" characters in length");
document.getElementById('txtUserName').focus();
return(false);
}
}
I am calling this function here on textbox's blur event:
if(IsLengthOK("Registration Username",this,6))
{
// do something next.
}
HTML of my textbox is:
<input id="txtUserName" type="text" tabindex="1" name="txtUserName" style="background: none repeat scroll 0% 0% white;">
function IsLengthOK(_title,_control,_length) {
if(_control.value.length < _length) {
alert("'" + _title + "'" + " must be minimum " + _length + " characters in length");
setTimeout(function() {
document.getElementById('txtUserName').focus();
}, 0);
return false;
}
}
This's working in my Firefox. It will have the focus on object#txtUserName after the setTimeout called.
It works fine for me in Firefox 4.
jsFiddle.
Here is a suggested rewrite of your function...
function IsLengthOK(_title, _control, _length) {
if (_control.value.length < _length) {
alert("'" + _title + "'" + " must be minimum " + _length + " characters in length");
_control.focus();
return false;
}
return true;
}
jsFiddle.
You are passing a reference to your element but then selecting it again. There is no reason to do that. It will only make maintenance more difficult. It will also bind that function to your one element when it could easily be more flexible.
You return false in parenthesis. That is not necessary. Also, if the condition is true, it returns false, so it would stand to reason otherwise it should return true (instead of undefined).
If you have a bunch of validation utility functions like this, it may be a good idea to namespace them as methods of a Validator object, for example.
Why do you prefix your variables with _? You should drop them.
Instead of using document.getElementById, like you are here:
document.getElementById('txtUserName').focus();
Use a jquery selector and then extract the raw element, like so.
$('#txtUserName')[0].focus();
I know blinking is not a nice thing. However...
I have a long complex HTML form with a number of compulsory fields. As well as highlighting the empty text boxes I want to draw attention to them by flashing the text of the question for maybe three seconds.
All the javascript/css methods I can find all seem to fall over when there is more than one such item to blink or are designed for leaving the item blinking all the time.
Any suggestions for how to achieve this?
The method at What is the replacement for a blinking text in a web page? seems like overkill.
thanks
Derek
I've tried this (to blink each designated span just over three seconds) but it only works on the first item it's called for:
function blinkOn(span){
span.counter=0;
span.defColor=span.style.color;
span.alertTimerId =setInterval("blinkOnce('"+span.id+"')", 400 );
}
function blinkOnce(spanID){
var span=document.getElementById(spanID)
span.counter++;
if(span.style.color==span.defColor){
span.style.color='transparent'}
else{
span.style.color=span.defColor;
}
if(span.counter>8){
blinkOff(span);
}
}
function blinkOff(span){
clearInterval(span.alertTimerId);
span.style.color=span.defColor;
}
I use jQuery for this kind of thing, personally:
$('#element_id')
.fadeOut(300)
.fadeIn(300)
.fadeOut(300)
.fadeIn(300)
.fadeOut(300)
.fadeIn(300)
.fadeOut(300)
.fadeIn(300)
.fadeOut(300)
.fadeIn(300);
Quite inelegant I know but it does the job. jQuery UI does have some more concise effects.
The only place I use it is for when a user adds something to a shopping basket without redirecting to the basket page, just to make sure they know that it's been added.
See:
http://api.jquery.com/fadeIn/, http://api.jquery.com/fadeOut/ and http://jqueryui.com/docs/show/ (pulsate, in particular)
I'm not exactly clear about the behavior you desire, but it sounds like you might be able to flash the question (or take some kind of action) using a Javascript timer. You can create unique timers for each element that you want to flash. And you can flash them once or set them up to repeat infinitely or up to a limit. Here's one example:
http://www.elated.com/articles/javascript-timers-with-settimeout-and-setinterval/
I took some time to work this out this morning. If you haven't gotten yours to work yet, I hope you can adapt this to help.
<html>
<head>
<script type="text/javascript">
var idArray = [];
var defaultColor = '#000000';
function makeItemsBlink(blinkTime) {
blinkForTime('q1', blinkTime, '#ff0000');
blinkForTime('q2', blinkTime, '#00ff00');
blinkForTime('q3', blinkTime, '#0000ff');
}
function blinkForTime(id, blinkTime, blinkColor) {
idArray[id] = setInterval('toggleColor("' + id + '", "' + blinkColor + '")', 400);
setTimeout('stopBlinking("' + id + '")', blinkTime);
}
function stopBlinking(id) {
clearInterval(idArray[id]);
document.getElementById(id).style.color = defaultColor;
}
function toggleColor(id, blinkColor) {
var e = document.getElementById(id);
var currentColor = e.style.color;
if (currentColor == defaultColor) {
e.style.color = blinkColor;
}
else {
e.style.color = defaultColor;
}
}
</script>
</head>
<body onload="makeItemsBlink(3000);">
<div id="q1">Test question 1</div>
<div id="q2">Test question 2</div>
<div id="q3">Test question 3</div>
</body>
</html>