If Statements Skipping or Evaluating Strangely, JavaScript and jquery - javascript

So in jQuery, I have a global variable "currentSubNav" that stores a current visible element. The following code executes on "mouseenter".
I need it to get store element's ID, check to see if there was one. If there wasn't, set the new visible element to the default.
$('#mainMenu a').mouseenter(function() {
var newName = $(this).attr("id");
if(newName == ''){
var newName = "default";
}
Then it checks to see if the new element matches the current one. If so, it returns. If not, it performs the animations to bring in the new one.
if(newName == currentSubNav){
return;
}else{
$("div[name=" + currentSubNav + "]").animate({"left": "+=600px", "opacity": "toggle"}, "slow");
$("div[name=" + newName + "]").css({"margin-top": "0"});
$("div[name=" + newName + "]").fadeIn(2000);
$("div[name=" + currentSubNav + "]").animate({"left": "-=600px"}, 0);
currentSubNav = newName;
return;
}
});
I'm using Chrome at the moment, and according to the dev tools that isn't what happens.
Problem #1
"$(this).attr("id");" isn't returning undefined as the documentation claims. It seems to be returning "". BUT, when I have the if statement as I do above, it skips over the statement entirely. I set a breakpoint, but it never pauses execuation, so the statement is never evaluated.
Problem #2
After the animations occur, instead of using the return at the end of the statements it goes back and uses the return for the "newName == currentSubNav" if statement. I guess that not a big deal, but it's not the intended behavior.
I'm fairly new to JavaScript, and it appears I'm missing something about how JavaScript works. But I can't find what anywhere. Any help?
EDIT: It seems to be working in FireFox, (though jQuery isn't returning undefined, it is returning ''). So this is a Chrome problem at the moment.

I would change the assignment of "newName" as follows:
var newName = $(this).attr('id') || 'default';
That's more idiomatic, and it'll handle cases where you're getting null instead of an empty string, or vice-versa, and when it doesn't really matter anyway.
I suspect that some of the "problems" you're seeing are more a matter of the Chrome debugger than the actual way that the code is running.

Related

How to check this i the same element JQuery [duplicate]

I'm trying to use jQuery to open / close control 'boxes' on a webpage. Unfortunately, it doesn't look very good to close a box just to re-open it if the user happens to click on the already opened box. (Boxes are mutually exclusive).
The code I'm using doesn't work, and I'm not sure why. I still get a box closing just to open up anew, which isn't the desired functionality. I created the 'val' variable for debugging purposes; in the debugger, it shows 'val' as having the exact same value as $(this), which should prevent it from getting to the .slideToggle() inside the if statement, but doesn't.
function openBox(index)
{
val = $('#box' + index);
$('.profilePageContentBox').each(function(){
if($(this).css('display') != 'none')
{
if($(this) != val)
{
$(this).slideToggle(200);
}
}
});
val.slideToggle(200);
}
You can also do:
if(val.is(this))
Using the $() function will always create a new object, so no matter what, your equality check there will always fail.
For example:
var div = document.getElementById('myDiv');
$(div) === $(div); // false!
Instead, you could try just storing the actual DOM elements, since those are just referred to inside jQuery objects.
val = $('#box'+index).get(0);
...
if (this !== val) { }
Try this:
function openBox(index)
{
val=$('#box'+index);
$('.profilePageContentBox').each(function(){
if($(this).is(":visible"))
{
if(!$(this).is("#box"+index))
$(this).slideToggle(200);
}
});
val.slideToggle(200);
}

If/elseif statements not working

For a reason I can't Identify, this isn't being successfully called, I've tried everything I can think of, but nothing seems to get this to work, it has no errors.
<img id="risk" src="assets/R0.png" width="100" height="150" style="border: dotted;"><br>
<button id="ContinueBtn" onclick="Continue()">Continue</button>
if (document.getElementById("risk").src == "assets/R0.png"){
document.getElementById("risk").src = "assets/R1.png";
}
else if (document.getElementById("risk").src == "assets/R1.png"){
document.getElementById("risk").src = "assets/R2.png";
}
else if (document.getElementById("risk").src == "assets/R2.png"){
document.getElementById("risk").src = "assets/RF.png";
document.getElementById("happiness").src = "assets/PF.png";
document.getElementById("main").src = "assets/fired.png";
alert("Debug")
var Cont = document.getElementById("ContinueBtn");
Cont.parentNode.removeChild(Cont);
}
When I add an else statement to it, it by passes the if and elseif's, making it seem like it is not finding anything for "risk",
else{
alert("An error has occured! Try refreshing your page.")
}
Short answer:
When you test the .src property in JS, some browsers report the full path of the image even when your original markup only specified a relative path. Which means your == comparison will fail.
Long answer:
Assuming that block of code is called after the elements have been created, I think you'll find that the problem is that the src you set in your html is not the same as what is reported when you test the .src property. If your source code sets a relative path for the src you may find the .src property value reported by the browser is actually the full path. So, e.g.:
<img src="assets/R0.png">
...and then:
console.log(document.getElementById("risk").src);
...will log "http://www.yourdomainhere.com/fullpath/assets/R0.png"
Which of course won't be equal when you compare with ==. Obviously you can easily test this by adding a console.log() statement just before the first if (or use an alert() if you must). Whenever you find an if statement isn't doing what you expect the first thing to try is adding a console.log() of the variables involved in the expression so that you can be sure they have the values you think they do.
If that is what's happening, then you obviously just need to use string functions to extract the last path of the path. E.g.:
var imgEl = document.getElementById("risk"),
imgSrc = imgEl.src.split("/").pop();
if (imgSrc == "R0.png"){
imgEl.src = "assets/R1.png";
} else if (imgSrc == "R1.png") {
imgEl.src = "assets/R2.png";
}
// etc.
The code imgEl.src.split("/").pop() that I've used takes the full path and uses .split() to create an array with all of the pieces between the forward slashes and then .pop() to take the last "piece", i.e. the last array element.
(I've also introduced a variable imgEl to reference your img element, because that's much neater and more efficient than repeatedly calling document.getElementById() for the same element.
Try using RegExp:
var risk = document.getElementById("risk");
if (risk.src.match("assets/R0.png")){
risk.src = "assets/R1.png";
} else if(condition) {
...
} else {
...
}

Why does this script never run?

I've got the following JavaScript statement, that executes on Page Load:
The variable u1 is populated with one of the following values:
BBSLoan|Accept|PPI+No|60Months
BBSLoan|Refer|PPI+No|60Months
HSBSLoan|Accept|PPI+No|48Months
HSBSLoan|Refer|PPI+No|48Months
I have been informed that the conditions in the conditional statements will never be met - is this true? From what I can see, going on each of the variables, the index that will be returned by indexOf is 0? Unless I am mistaken?
EDIT: Just to clarify, the variable 'u1' will be populated dynamically with any of the 4 strings listed above. The %pu1=!; is actually a macro that will populate this value.
<script language="JavaScript" type="text/javascript">
var u1 = '%pu1=!;';
if (u1.indexOf('BBSLoan|Accept') > -1) {
var pvnPixel = '<img src="http://www.url1.com"/>';
document.writeln(pvnPixel);
}
if (u1.indexOf('BBSLoan|Refer') > -1) {
var pvnPixel2 = '<img src="https://www.url2.com;"/>';
document.writeln(pvnPixel2);
}
if (u1.indexOf('HSBSLoan|Accept') > -1) {
var pvnPixel3 = '<img src="https://www.url3.com;"/>';
document.writeln(pvnPixel3);
}
</script>
Thanks in advance!
EDIT: Just to clarify, the variable 'u1' will be populated dynamically with any of the 4 strings listed above. The %pu1=!; is actually a macro that will populate this value.
This answer is not correct. It will be deleted later, but is being left to prevent this answer from popping up again.
var u1 = '%pu1=!;';
The value of u1 is always '%pu1=!;', since you declare it as that.
Ok I finally got this to work using search instead of indexOf!
Would it make more sense to use a switch statement with a default case, or at a minimum provide an "else" with a default?
Have you tried to put a debugger statement in after var u1 is set, and step through using the client (firefox, chrome, IE, safari all have built in "developer tools" with the ability to step through js code) debugger to see what the value of u1 is?

Javascript/jQuery function yields undefined in <IE8

A short while back I asked a question here about how I could calculate when a heading was longer than one line within a given container, and subsequently wrap each of these lines in a <span>:
Use Javascript/jQuery to determine where a heading breaks to the next line?
I chose an answer which worked great for me, at least until I checked in IE7 and IE6, in which all the headings handled by this script rendered as
"undefinedundefinedundefinedundefinedundefinedundefined[...]"
on the page. As I'm not really a JavaScript person (that's why I asked such a question in the first place), it's really tough for me to figure out where the problem is. I assumed an undefined variable or something, but I just can't seem to grasp it.
Can anyone help?
I'll repeat the code here, but please refer to the link above for context:
$(function(){
$h = $('.fixed').find('h3');
$h.each(function(i,e){
var txt = $(e).text();
$th = $('<h3 />').prependTo($(e).parent());
var lh = $(e).text('X').height();
$(e).text('');
while (txt.length > 0) {
$th.text($th.text() + txt[0]);
txt = txt.slice(1);
if (($th.height() > lh) || (txt.length <= 0)) {
var shc = $th.text().split(' ');
var ph = shc.slice(0,-1).join(' ')+' ';
if (txt.length <= 0) { ph += shc.pop(); }
$('<span />').text(ph).appendTo($(e));
$th.text(shc.pop());
}
}
$th.remove();
})
});
You need to change
$th.text($th.text() + txt[0]);
to be
$th.text($th.text() + txt.charAt(0));
IE<8 doesn't accept string positions through array indexes ;)
The styling doesn't work, but that'll be a CSS issue which I couldn't fix before leaving. But everything is wrapped in spans :)
Nothing jumps out at me. But, since you mentioned in your comment to your question that you see "undefined" in Firebug, I would start there. Even though those browsers are failing gracefully, the fact that you see undefined there is your first hint to finding the problem for the harder-to-diagnose IE6/7. I would use Firebug and either breakpoint in the function, or use some console.log() calls to document what the values that you are working with are each step of the way. Once you start seeing undefined... you have likely found your problem.

How to loop through elements and call onblur handler for certain elements

I have a case where I have a bunch of text boxes and radio buttons on a screen all built dynamically with various DIVs. There are onblur routines for all of the text boxes to validate entry, but depending on the radio button selection, the text box entry could be invalid when it was valid originally. I can't use onblur with the radio buttons because they could go from the radio button into one of the text boxes that was made invalid and create an infinite loop since I'm putting focus into the invalid element. Since each text box has its own special parameters for the onblur calls, I figure the best way to do this is to call the onblur event for the textboxes when the form gets submitted to make sure all entry is still valid with the radio button configuration they have selected. I also need it to stop submitting if one of the onblur events returns false so they can correct the textbox that is wrong. This is what I've written:
for (var intElement = 0; intElement < document.forms[0].elements.length; intElement = intElement + 1)
{
if (document.forms[0].elements[intElement].name.substr(3) == "FactorAmount") // The first 3 characters of the name are a unique identifier for each field
{
if (document.forms[0].elements[intElement].onblur())
{
return false;
break;
}
}
}
return true;
I originally had (!document.forms[0].elements[intElement].onblur()) but the alert messages from the onblur events weren't popping up when I had that. Now the alert messages are popping up, but it's still continuing to loop through elements if it hits an error. I've stepped through this with a debugger both ways, and it appears to be looping just fine, but it's either 1) not stopping and returning false when I need it to or 2) not executing my alert messages to tell the user what the error was. Can someone possibly help? It's probably something stupid I'm doing.
The onblur method that is getting called looks like this:
function f_VerifyRange(tagFactor, reaMin, reaMax, intPrecision, sLOB, sIL, sFactorCode)
{
var tagCreditOrDebit;
var tagIsTotal;
var tagPercentageOrDecimal;
eval("tagCreditOrDebit = document.forms[0]." + tagFactor.name.substr(0,3) + "CreditOrDebitC");
eval("tagIsTotal = document.forms[0]." + tagFactor.name.substr(0,3) + "IsTotal");
eval("tagPercentageOrDecimal = document.forms[0]." + tagFactor.name.substr(0,3) + "PercentageOrDecimal");
if (tagPercentageOrDecimal.value == "P")
{
reaMax = Math.round((reaMax - 1) * 100);
reaMin = Math.round((1 - reaMin) * 100);
if (parseFloat(tagFactor.value) == 0)
{
alert("Please enter a value other than 0 or leave this field blank.");
f_SetFocus(tagFactor);
return false;
}
if (tagIsTotal.value == "True")
{
if (tagCreditOrDebit.checked)
{
if (parseFloat(tagFactor.value) > reaMin)
{
alert("Please enter a value less than or equal to " + reaMin + "% for a credit or " + reaMax + "% for a debit.");
f_SetFocus(tagFactor);
return false;
}
}
else
{
if (parseFloat(tagFactor.value) > reaMax)
{
alert("Please enter a value less than or equal to " + reaMin + "% for a credit or " + reaMax + "% for a debit.");
f_SetFocus(tagFactor);
return false;
}
}
}
}
return true;
}
EDIT: I think I've figured out why this isn't working as expected, but I still don't know how I can accomplish what I need to. The line below:
if (!document.forms[0].elements[intElement].onblur())
or
if (document.forms[0].elements[intElement].onblur())
is not returning what the single onblur function (f_VerifyRange) is returning. Instead it is always returning either true or false no matter what. In the first case, it returns true and then quits and aborts the submit after the first textbox even though there was no error with the first textbox. In the second case, it returns false and runs through all the boxes. Even though there might have been errors (which it displays), it doesn't think there are any errors, so it continues on with the submit. I guess what I really need is how to get the return value from f_VerifyRange which is my onblur function.
This question is a bit too involved for me at this time of the night, but I will give you this bit of advice:
eval("tagCreditOrDebit = document.forms[0]." + tagFactor.name.substr(0,3) + "CreditOrDebitC");
This can be written in a MUCH better way:
tagCreditOrDebit = document.forms[0][tagFactor.name.substr(0,3) + "CreditOrDebitC"];
In javascript, anywhere where you can use dotted syntax, you can use square brackets.
document.body;
document['body'];
var b = 'body';
document[b];
Also, think about giving your forms some sort of identifier. I have no clue at all why document.forms[0] was the standard way to address a form for so long... if you decide to place another form on the page before this one, then everything will break!
Other ways to do it include:
// HTML
<form name="myFormName">
// Javascript
var f = document.myFormName;
or
<form id="myFormId">
var f = document.getElementById("myFormId")
You´re not getting any success with if (!...onblur()) because the return of onblur() is always undefined when used directly. OnBlur() is a Event Handler Function. Like you descovered, you have to create a workaround.
I ended up solving this with a global variable. I originally set a value g_bHardEditsPassed to true assuming we will have no errors. Then in f_VerifyRange, everytime I return a value, I put a line before it to set the g_bHardEditsPassed variable to match. Then I modified the loop to look like this...
g_bHardEditsPassed = true;
for (var intElement = 0; intElement < document.forms[0].elements.length; intElement = intElement + 1)
{
if (document.forms[0].elements[intElement].name.substr(3) == "FactorAmount")
{
document.forms[0].elements[intElement].onblur()
if (!g_bHardEditsPassed)
{
g_bHardEditsPassed = true;
return false;
}
}
}
return true;
Thanks for everyone's suggestions. I'm sure that the jQuery thing especially will be worth looking into for the future.
First, for the love of god and all that is holy, stop writing native javascript and help yourself to some of that jQuery :)
Second, start using a validation framework. For jQuery, jQuery Validate usually works really well. It supports things like dependencies between different fields, etc. And you can also quite easily add new rules, like valid ISBN numbers, etc.
Edit: As for your code, I'm not sure that you can use onunload for this, as at that point there's no way back, you can't abort at that point. You should put this code on the onsubmit event instead.

Categories

Resources