Javascript document.getElementsByName() function is being weird at me - javascript

I've got the following variables in my simple javascript calculator:
var distance = parseInt(document.getElementsByName("distance"), 10);
var mins_running = parseInt(document.getElementsByName("mins_running").value, 10); // the running pace minutes
var secs_running = parseInt(document.getElementsByName("secs_running").value, 10); // the running pace seconds
var mins_walking = parseInt(document.getElementsByName("mins_walking").value, 10); // the walking pace minutes
var secs_walking = parseInt(document.getElementsByName("secs_walking").value, 10); // the walking pace seconds
The problem is, when I try to use these variables (entered as text from a form but meant to be used as numbers in the calculator). When I do a typeof() in the developer console.log I'm told the values are of type 'number', but the very next line is also a console.log('mins_running'), for example, and it explicitly states the value is "NaN". Is my value a number or not? What's going on? Stupid javascript--be more normal, darn it!
Any reasonable input/help will be appreciated.
Thanks for all the help, guys. Looks like I'm back to using the old Form.elementName.value thing instead. (if this is a really bad idea or just not good for production code at all, please feel free to say something.)

document.getElementsByName("mins_running")
returns a NodeList, which has no attribute value. Use
document.getElementsByName("mins_running")[0].value
instead.
Example:
HTML:
<input type="text" name="mins_running" value="10">
<br><button id="theButton">Click Me</button>
JavaScript:
document.getElementById("theButton").onclick = function() {
// Note we're getting the first match ----------------vvv
var field = document.getElementsByName("mins_running")[0];
display("The field's current value is: " +
parseInt(field.value, 10));
// And using its value-^^^^^
};
function display(msg) {
var p = document.createElement('p');
p.innerHTML = String(msg);
document.body.appendChild(p);
}
Live Copy | Source

Waleed shared how to fix it.
The technical reason why you got NaN there is...
You grab a reference to a NodeList with document.getElementsByName("distance"), and you attempt to access the property value on that. That property does not exist on NodeList, or anywhere on the prototype chain. In JavaScript, that means undefined is returned.
When you call parseInt() with undefined as the first argument, the function will toString() it and return "undefined". You explicitly set the base as 10, which obviously only covers digits 0 to 9, and the number can't be parsed. When this happens, parseInt() returns NaN. Since NaN is of the Number type (it's part of the IEEE-754 specification), the typeof operator tells you it's a "Number".
If you'd set the base as 31, it'd be able to parse "undefined", and it'd be 26231474015353 :)

Set ids for your tags and use getElementById instead.

Related

Why do I get undefined here?

function myFunc() {
var word = document.getElementById("Text1").value;
var num = parseInt(document.getElementById("Text2").value);
var numstr = num.split(",");
var wordstr = word.split("");
for (i = 0; i < word.length; i++) {
}
document.getElementById("myDiv").innerHTML += (wordstr[(numstr[i])-1]);
}
did I parseInt incorrectly? I've tried toString(), with ParseInt it doesn't do anything and without it I get 'undefined'
The parseInt() function parses a string and returns an integer.
You check your input with id "Text2" and show your HTML here to clearify the issue.
Without knowing more about your problem, it looks like you are misunderstanding how parseInt() works. Despite the misleading name, it will read your string character by character, attempting to create an integer. It will stop as soon as it finds a character that can't be part of an integer.
If you pass it "1,2,3,4" then it will read the 2 fine, but as a comma cannot be parsed as part of an integer, it will return the number 2. It doesn't make sense to call split on a number.
As others have said, you really need to give us more details for us to be able to help, but I suspect a large part of the problem is not understanding what some of these functions do.
Maybe you could explain what you're trying to achieve, then we can help you get there. Right now, your code isn't clear enough without extra information.

Can't assign querySelectorAll() to a variable - weird behaviour

I was trying to crawl a very old website for a specific tag, I need to get it by it's for= attribute. So I used this piece of code.
var character = document.querySelectorAll("label[for=char_1]");
For some reason it returns an undefined, but I was using this script for a few days now and it worked like a charm. Here's the fun part. Typing that command in browsers console will result in undefined. But typing this alone:
document.querySelectorAll("label[for=char_1]");
Will return a proper NodeList. Why it won't assign to a variable...?
edit: It seems that deleting var and typing character without it will make it work. It's resolved but I would still love to get an answer to "why is this happening"?
edit2:
for (var i = 0; i < 15; i++) {
var character = document.querySelectorAll("label[for=char_" + i +"]");
console.log(character); // this will return [] from the script.
var color = character[0].children[0].style.color;
}
A simple for loop. All I get is Cannot read property 'children' of undefined. But I can type in the very same command document.querySelectorAll... and it will work in the browser and will return NodeList.
I had it working like this in a very hacky script. It worked.
var character1 = document.querySelectorAll("label[for=char_1]");
var characterColor1 = character1[0].children[0].style.color;
edit3:
var character1 = document.querySelectorAll("label[for=char_1]");
var characterColor1 = character1[0].children[0].style.color;
var character2 = document.querySelectorAll("label[for=char_2]");
var characterColor2 = character2[0].children[0].style.color;
// ...
The above code works without a single problem though. I don't think it's DOM not being ready as this code is also run from Greasemonkey script and it works. The only difference is the for loop.
var x = ""; // returns undefined, because it's a var assignment.
var elements = document.querySelectorAll('div');
That's expected behavior when pasted into the console.
edit: It seems that deleting var and typing character without it will make it work. It's resolved
I'm afraid you're creating a global scope variable now. or perhaps characters is an already defined variable in that scope.
Buhah, as I said in edit 3 "the only difference is the for loop". I was so busy trying to find an answer in the DOM-related things that I made the simplest mistake ever done in programming.
See?
char_1
With...
for(var i = 0...)
0! And I was testing char_1 in the browser instead of char_0. Which - truly - returns [] instead of something useful. Time to go on a holiday break I guess, my brain seems to be there already. :)

razor engine syntax inside javascript tag for non string variables [duplicate]

Can someone format the code below so that I can set srcript variables with c# code using razor?
The below does not work, i've got it that way to make is easy for someone to help.
#{int proID = 123; int nonProID = 456;}
<script type="text/javascript">
#{
<text>
var nonID =#nonProID;
var proID= #proID;
window.nonID = #nonProID;
window.proID=#proID;
</text>
}
</script>
I am getting a design time error
You should take a look at the output that your razor page is resulting. Actually, you need to know what is executed by server-side and client-side. Try this:
#{
int proID = 123;
int nonProID = 456;
}
<script>
var nonID = #nonProID;
var proID = #proID;
window.nonID = #nonProID;
window.proID = #proID;
</script>
The output should be like this:
Depending what version of Visual Studio you are using, it point some highlights in the design-time for views with razor.
Since razor syntax errors can become problematic while you're working on the view, I totally get why you'd want to avoid them. Here's a couple other options.
<script type="text/javascript">
// #Model.Count is an int
var count = '#Model.Count';
var countInt = parseInt('#Model.ActiveLocsCount');
</script>
The quotes act as delimiters, so the razor parser is happy. But of course your C# int becomes a JS string in the first statement. For purists, the second option might be better.
If somebody has a better way of doing this without the razor syntax errors, in particular maintaining the type of the var, I'd love to see it!
This is how I solved the problem:
#{int proID = 123; int nonProID = 456;}
<script type="text/javascript">
var nonID = Number(#nonProID);
var proID = Number(#proID);
</script>
It is self-documenting and it doesn't involve conversion to and from text.
Note: be careful to use the Number() function not create new Number() objects - as the exactly equals operator may behave in a non-obvious way:
var y = new Number(123); // Note incorrect usage of "new"
var x = new Number(123);
alert(y === 123); // displays false
alert(x == y); // displays false
I've seen several approaches to working around the bug, and I ran some timing tests to see what works for speed (http://jsfiddle.net/5dwwy/)
Approaches:
Direct assignment
In this approach, the razor syntax is directly assigned to the variable. This is what throws the error. As a baseline, the JavaScript speed test simply does a straight assignment of a number to a variable.
Pass through `Number` constructor
In this approach, we wrap the razor syntax in a call to the `Number` constructor, as in `Number(#ViewBag.Value)`.
ParseInt
In this approach, the razor syntax is put inside quotes and passed to the `parseInt` function.
Value-returning function
In this approach, a function is created that simply takes the razor syntax as a parameter and returns it.
Type-checking function
In this approach, the function performs some basic type checking (looking for null, basically) and returns the value if it isn't null.
Procedure:
Using each approach mentioned above, a for-loop repeats each function call 10M times, getting the total time for the entire loop. Then, that for-loop is repeated 30 times to obtain an average time per 10M actions. These times were then compared to each other to determine which actions were faster than others.
Note that since it is JavaScript running, the actual numbers other people receive will differ, but the importance is not in the actual number, but how the numbers compare to the other numbers.
Results:
Using the Direct assignment approach, the average time to process 10M assignments was 98.033ms. Using the Number constructor yielded 1554.93ms per 10M. Similarly, the parseInt method took 1404.27ms. The two function calls took 97.5ms for the simple function and 101.4ms for the more complex function.
Conclusions:
The cleanest code to understand is the Direct assignment. However, because of the bug in Visual Studio, this reports an error and could cause issues with Intellisense and give a vague sense of being wrong.
The fastest code was the simple function call, but only by a slim margin. Since I didn't do further analysis, I do not know if this difference has a statistical significance. The type-checking function was also very fast, only slightly slower than a direct assignment, and includes the possibility that the variable may be null. It's not really practical, though, because even the basic function will return undefined if the parameter is undefined (null in razor syntax).
Parsing the razor value as an int and running it through the constructor were extremely slow, on the order of 15x slower than a direct assignment. Most likely the Number constructor is actually internally calling parseInt, which would explain why it takes longer than a simple parseInt. However, they do have the advantage of being more meaningful, without requiring an externally-defined (ie somewhere else in the file or application) function to execute, with the Number constructor actually minimizing the visible casting of an integer to a string.
Bottom line, these numbers were generated running through 10M iterations. On a single item, the speed is incalculably small. For most, simply running it through the Number constructor might be the most readable code, despite being the slowest.
#{
int proID = 123;
int nonProID = 456;
}
<script>
var nonID = '#nonProID';
var proID = '#proID';
window.nonID = '#nonProID';
window.proID = '#proID';
</script>
One of the easy way is:
<input type="hidden" id="SaleDateValue" value="#ViewBag.SaleDate" />
<input type="hidden" id="VoidItem" value="#Model.SecurityControl["VoidItem"].ToString()" />
And then get the value in javascript:
var SaleDate = document.getElementById('SaleDateValue').value;
var Item = document.getElementById('VoidItem').value;
I found a very clean solution that allows separate logic and GUI:
in your razor .cshtml page try this:
<body id="myId" data-my-variable="myValue">
...your page code here
</body>
in your .js file or .ts (if you use typeScript) to read stored value from your view put some like this (jquery library is required):
$("#myId").data("my-variable")
Not so much an answer as a cautionary tale: this was bugging me as well - and I thought I had a solution by pre-pending a zero and using the #(...) syntax. i.e your code would have been:
var nonID = 0#(nonProID);
var proID = 0#(proID);
Getting output like:
var nonId = 0123;
What I didn't realise was that this is how JavaScript (version 3) represents octal/base-8 numbers and is actually altering the value. Additionally, if you are using the "use strict"; command then it will break your code entirely as octal numbers have been removed.
I'm still looking for a proper solution to this.
It works if you do something like this:
var proID = #proID + 0;
Which produces code that is something like:
var proID = 4 + 0;
A bit odd for sure, but no more fake syntax errors at least.
Sadly the errors are still reported in VS2013, so this hasn't been properly addressed (yet).
I've been looking into this approach:
function getServerObject(serverObject) {
if (typeof serverObject === "undefined") {
return null;
}
return serverObject;
}
var itCameFromDotNet = getServerObject(#dotNetObject);
To me this seems to make it safer on the JS side... worst case you end up with a null variable.
This should cover all major types:
public class ViewBagUtils
{
public static string ToJavascriptValue(dynamic val)
{
if (val == null) return "null";
if (val is string) return val;
if (val is bool) return val.ToString().ToLower();
if (val is DateTime) return val.ToString();
if (double.TryParse(val.ToString(), out double dval)) return dval.ToString();
throw new ArgumentException("Could not convert value.");
}
}
And in your .cshtml file inside the <script> tag:
#using Namespace_Of_ViewBagUtils
const someValue = #ViewBagUtils.ToJavascriptValue(ViewBag.SomeValue);
Note that for string values, you'll have to use the #ViewBagUtils expression inside single (or double) quotes, like so:
const someValue = "#ViewBagUtils.ToJavascriptValue(ViewBag.SomeValue)";
I use a very simple function to solve syntax errors in body of JavaScript codes that mixed with Razor codes ;)
function n(num){return num;}
var nonID = n(#nonProID);
var proID= n(#proID);
This sets a JavaScript var for me directly from a web.config defined appSetting..
var pv = '#System.Web.Configuration.WebConfigurationManager.AppSettings["pv"]';
With
var jsVar = JSON.parse(#Html.Raw(Json.Serialize(razorObject)));
you can parse any razor object into a JavaScript object.
It's long but universal

JavaScript returns 'memory' as 0, even though I increase or decrease its value

Code: http://pastebin.com/xGa9VLDY
The question:
I am making a little calculator app to hone my JavaScript skills, and it turned out alright. However, the problem I am experiencing is that JavaScript returns my variable 'memory' as 0, even though the value is increased (or decreased), and I can't seem to figure out how, so the calculator is pretty much useless, since the equal button only returns 0. I've tried to use the console in Chrome to increase the value, just to test and this is my result:
memory + 5
5
But when I try to check the value of 'memory' again:
memory
0
Is it something I am missing, or is it just a stupid, little mistake?
What I've tried:
As you can see, I have now tried to store the value in localStorage, but to no avail, and I do not see what else I can do. I recently switched from
memory += textBox.value;
to
memory = memory + textBox.value;
but obviously, that didn't work either.
EDIT:
I have got a very strange problem now:
memory: 0
textBox.value: "6"
parseInt(textBox.value): 6
memory + parseInt(textBox.value): 6
typeof(memory): "number"
This is all the values when the textbox still is populated with a number, and this is these are values right after pressing the plus sign:
memory: NaN
textBox.value: ""
parseInt(textBox.value): NaN
memory + parseInt(textBox.value): NaN
typeof(memory): "number"
The console is giving you the result of your mathematical operation, not storing it anywhere.
So you start with memory containing the value 0. To make that 5, you need to add 5, and then store the result back in memory.
memory = memory + 5;
There is a shorthand for that:
memory += 5;
And also a shorthand for just adding 1 (because it's a very common task):
++memory;
although this is not considered best practise.
Regarding the textBox.value version, where you are doing this, the value property of a textBox is a string, not a numeric value. Even though 1234 looks like a number, it is actually the characters '1', '2', '3' and '4'. You could happily include 'a' or 'z'. To get a numeric value out that you can use in a mathematical expression, you need to parse the string:
Either
enteredValueInt = parseInt(textBox.value); // or
enteredValueFloat = parseFloat(textBox.value);
depending on whether you expect the textBox to have a whole number or a floating point value in.
Demo here: http://jsbin.com/yijezifowu/1/edit?html,js,output
EDIT: Re 'very strange problem':
You have a spurious call to emptyBox at the top of the mathStuff function in your pastebin code:
function mathStuff(operator) {
emptyBox();
//... stuff with operators
}
So you're beginning by clearing the textbox before attempting to retrieve the numbers.
memory + 5
is a calculation which yields the sum of the two values, which is 0 in your case, since memory is 0. You want to store the value in memory, but you need to assign the value to your memory variable, like this:
memory = memory + 5;
or, a shorthand version:
memory += 5;
Read more about assignment operators here.
Also, you must make sure the operator you are using will work well, as:
'0' + 5 === '05'
while
0 + 5 === 5

jQuery won't count up variables

I have a little problem with my jQuery script: instead of counting up all variables, the script puts them next to each other. How do I count up the variables? (I am new to jQuery, so maybe I overlooked something or made a stupid mistake).
This is the line of code that should count up the variables.
totalcost = ((commissioncost + paypalcost) + qrticketcost);
http://jsfiddle.net/bsuh5q8k/1/
Thanks.
Often when you retrieve a value from a field using jquery's .val(), you'll get the string value (String type) instead of the numeric value you desire here. For instance, the field value may be 37.50, but you're getting "37.50" from .val()
So when you do this:
commissioncost = $('input[name=price]').val();
You'll get the String value.
So instead, try this:
commissioncost = Number($('input[name=price]').val());
This will convert/cast the value into a Number for you.
Also, a word of caution: just be sure whatever value is in that field, it can be evaluated as a Number, otherwise comissioncost will equal "NaN" (not a number) and will give you the same grief you're experiencing now. The rudimentary method to check if the type conversion was successful is:
commissioncost = Number($('input[name=price]').val());
if(isNaN(commissioncost)){
// oops, value wasn't a number!
}else{
// hooray! value was a number (most of the time - but that's a longer discussion)
}
commissioncost is being treated as a string. So when you add it thinks you're wanting to concatenate.
When you pull it from the input, explicitly tell Javascript that it's a number/float.
commissioncost = parseFloat($('input[name=price]').val());

Categories