While operator undefined - javascript

I want to make a small calculator in javascript.
I got the html code looking like this (for all the numbers)
<button type="button" onclick="calcNum(1)">1</button>
<button type="button" onclick="operator('+')">+</button>
var myNumbers = [];
The calcnumber function like this:
function calcNum(i) {
myNumbers.push(i);
var x = document.getElementById("screen").innerHTML = myNumbers.join("");
}
and the operator function like this:
function operator(op) {
var operator = op;
var y = document.getElementById("screen").innerHTML = operator;
}
My goal is to make it like this:
If I press 1,2,3 I want the screen element to display "123" (which it does) if I press "+" I want "+" to be displayed (which it does) however when the operator is pressed, and then a new number is pressed I want it to start on a new number, right now if I press "123" and then + and then "456" I get:
123456, instead I want it to display "456", hence starting on a new number. Hope it's all clear.
I figured I could add this to the calcNum function:
while(op == "undefined") {
keep pushing numbers // but this does not work
}
In the end I want to construct a calc function which takes all the numbers up to a operator is pressed as the FIRST number, then concatanate with the operator and the second number and adding them together.

I see several issues in your code but I don't know if it is due to the fact that you didn't copy all your code in your question.
First, the operator function is incorrect : you give a local variable the samename than the function. If you want the function return a value, use the returnkeyword.
I figured I could add this to the calcNum function:
while(op == "undefined") { keep pushing numbers // but this does
not work }
Where is opdefined? The only op I see is a local variable of the operatorfunction. It will always be undefined in calcNum.
Note also that if you want to test if a variable is undefined, you should not test
if (myVar == "undefined")
but
if(typeof myVar == "undefined")
Finally I'd change your code this way (should be tested though):
var currentNumber= "";
var entries = []
function calcNum(i) {
currentNumber +=i;
document.getElementById("screen").innerHTML = currentNumber;
}
function operator(op) {
var y = document.getElementById("screen").innerHTML = op;
//Note that you could already process the entered operations as if you clicked on '='
//and display the result instead of displaying the operation...
if(currentNumber != ""){//there must be a number entered before you click on an operator
entries .push(currentNumber);
entries .push(op);
currentNumber= "";
}
}
And you still need of course to implement what you do when you click on =...

Change your functions like this
var numbers = "";
function calcNum(i) {
myNumbers.push(i);
numbers +=i;
var x = document.getElementById("screen").innerHTML = numbers;
}
and
function operator(op) {
var operator = op;
var y = document.getElementById("screen").innerHTML = operator;
myNumbers.push(op);
numbers = "";
}

Declare above:
var leftOperand = null;
var lastOperator = null;
In calcNum:
if(lastOperator !== null) {
document.getElementById("screen").innerHTML = '';
leftOperand = myNumbers.join('');
myNumbers = [];
lastOperator = null;
}
// rest of the function
In operator:
lastOperator = op;
// rest of the function

Related

BOOLEAN not working after adding FOR LOOP JavaScript

I'm working on an assignment where a boolean has to switch after a variable is matched to a value in an array. The variable has to be matched with the value in the array using a for loop. However, I'm able to switch the boolean before I introduce the for loop. But after I introduce the for loop, the boolean is stuck to its original value of false.
Can somebody explain why this is happening?
Can I also request, I'm not looking for 'how to do this' but rather an explanation as to why is it happening - so I will appreciate if you do not recommend to me 'another better way' of achieving this - I just want to understand the concept as I'm a beginner.
The code I'm using before the for loop (which changes the boolean correctly) is:
var c = 3;
var w = [];
var m = false;
w.push(3,4);
if (c === w[0]){
m = true;
}
alert (m);
However after I add the for loop counter and also change the if condition from c===w[0] to c===w[i], I only get the 'false' alert using the below code:
var c = 3;
var w = [];
var m = false;
w.push(3,4);
for (i=0; i<2 && c!==w[i]; i++){
if (c === w[i]){
m = true;
}
}
alert (m);
Instead of using for loop, if you only wish that the boolean variable must be switched on satisfying only one condition, you can use some() method. Using this, the loop will not iterate through all the objects and will stop once your condition is satisfied. Example shown below:-
var arr = [3,4,5];
var m = 4;
var bool = false;
array.some(function(item) {
if (m === item){
bool = true;
}
});
alert(bool);
So this will basically give you alert true once you get the matching object from an array.
The condition from for is checked also before first iteration, so the if is not fired. Check out code like this:
var c=3;
var w=[];
w.push(3,4);
var m=false;
for (var i=0;i<2 && c!==w[i];i++){
console.log('In loop')
if (c===w[i]){
m=true;
}
}

Named vs nameless function for replacing numbers in a string

I am a JavaScript beginner, and one of the problems in the latest programming assignment I got is to replace all numbers in a string with sum of their digits, so, for example, for an input like this:
"m123a"
the output should be
"m6a"
I actually managed to write a working code, but I do not understand why it works.
This is my HTML:
<html>
<TEXTAREA ID = "text" ROWS = 10 COLS = 30></TEXTAREA>
<br>
<INPUT TYPE = "button" ID = "button" VALUE = "Replace">
<SCRIPT src = "zaz3.js" type="text/javascript"></SCRIPT>
</html>
This is my working JavaScript code:
function ReplaceNumbers()
{
var s = document.getElementById("text").value;
document.getElementById("text").value = s.replace(/\d+/g, function DigitSum(x)
{
var sum = 0;
while (x > 0)
{
sum += x%10;
x = x/10;
x = Math.floor(x);
}
return sum;
});
}
var button = document.getElementById( "button");
button.addEventListener("click" , ReplaceNumbers);
And this is the first version of my JavaScript code which does not work:
function DigitSum(x)
{
var sum = 0;
while (x > 0)
{
sum += x%10;
x = x/10;
x = Math.floor(x);
}
return sum;
}
function ReplaceNumbers()
{
var s = document.getElementById("text").value;
document.getElementById("text").value = s.replace(/\d+/g, DigitSum(x));
}
var button = document.getElementById( "button");
button.addEventListener("click" , ReplaceNumbers);
The only difference here is that function DigitSum is implemented separately in the second version.
When debugging the second code, the error returned is "ReferenceError: x is not defined". I do not understand how the parameter x in the first code is even interpreted since it's not mentioned anywhere else in the code.
So, my question is, what is the difference between implementing the function DigitSum separately vs implementing it where it is needed, and what actually is x in the first version, and what is it in the second version.
because in the second one you are calling the function and whatever it returns is being assigned to the replace. In your case you should have an error that says "x is undefined".
document.getElementById("text").value = s.replace(/\d+/g, DigitSum(x));
It should just be
document.getElementById("text").value = s.replace(/\d+/g, DigitSum);
You are using a callback
document.getElementById("text").value = s.replace(/\d+/g, DigitSum(x));
// ^^^^^^^^^^^
but instead to use only the function reference, you insert a call of the function with x, which does not exist.
Use this for a valid reference of a callback.
document.getElementById("text").value = s.replace(/\d+/g, DigitSum);
// ^^^^^^^^ without parenthesis
A calback is a function which is used for repeating calls with a fixed parameter list. The surrounding function defines the parameters and in this case you may have a look to String#replace.

JavaScript Throws Undefined Error

What it is supposed to do -
Example
url1(pages,"ALT") returns "www.xyz.ac.uk"
url1(pages,"xyz") returns ""
The error - TypeError: Cannot call method 'toUpperCase' of undefined
This is just for some coursework, Im stuck with these errors. Any help would be much appreciated
function index(string,pattern,caseSensitive) {
if(caseSensitive == false) {
var v = string.toUpperCase();
} else {
var v = string;
}
return indexNumber = v.indexOf(pattern);
}
var pages = [ "|www.lboro.ac.uk|Loughborough University offers degree programmes and world class research.", "!www.xyz.ac.uk!An alternative University" , "%www%Yet another University"];
alert(url1(pages, "ALT"));
function url1(pages,pattern) {
var siteContent = [];
for(i=0;i<pages.length;i++) {
var seperator = pages[i].charAt(0);
if(pages[i].indexOf(seperator)>0){
siteContent = pages[i].split(pages[i].indexOf(seperator));
}
if( index(siteContent[2],pattern,false)>=0){
return siteContent[1];
}else{
return "";
}
}
}
if(pages[i].indexOf(seperator)>0){
siteContent = pages[i].split(pages[i].indexOf(seperator));
}
if( index(siteContent[2],pattern,false)>=0){
return siteContent[1];
}else{
return "";
}
If pages[i].indexOf(seperator)<=0, siteContent is still whatever it was from the last iteration. If that happens on the first iteration, siteContent is still [], and siteContent[2] is undefined.
Another problem: the expression pages[i].indexOf(seperator) returns a number, and pages[i].split expects a delimiting string as an argument. Since the number doesn't appear in your input, you'll always get a single-element array, and siteContent[2] will always be undefined. Get rid of .indexOf(seperator), change it to siteContent = pages[i].split(seperator).
One more: get rid of the else { return ""; }. Add a return ""; after the for loop.
Finally, in the first if statement condition, change .indexOf(seperator) > 0 to .indexOf(seperator, 1) !== -1. Since you're getting seperator from the first character of the string, it will be found at 0. You want the second occurrence, so start the search at 1. In addition, .indexOf returns -1 if it doesn't find the substring. You'll need to account for this in both if conditions.
Side note, as this is not causing your problem: never use == false. JS will coerce stuff like 0 and "" to == false. If that's what you want, just use the ! operator, because the expression has nothing to do with the value false.
My final answer is http://jsfiddle.net/QF237/
Right here:
alert(url1(pages, ALT)); // ALT ISN'T DEFINED
I believe you forgot to quote it:
alert(url1(pages, "ALT"));
You should split the string passing the separator character itself. Your function then will look like:
function url1(pages,pattern) {
var siteContent = [];
for(i=0;i<pages.length;i++) {
var seperator = pages[i].charAt(0);
console.log(seperator);
if(pages[i].indexOf(seperator)>=0){
siteContent = pages[i].split(seperator); //fixed here
}
console.log(siteContent);
if( index(siteContent[2],pattern,false)>=0){
return siteContent[1];
}else{
return "";
}
}
}
Tell us if it worked, please.
EDIT: It seeems your index() also has a little problem. Please try the function below.
function index(string,pattern,caseSensitive) {
var v;
if(caseSensitive == false) {
v = string.toUpperCase();
pattern = pattern.toUpperCase(); //to clarify: pattern should be uppercased also if caseSensitiveness is false
} else {
v = string;
}
return v.indexOf(pattern);
}
EDIT 2:
And url1() is finally like this:
function url1(pages,pattern) {
var siteContent = [];
for(i=0;i<pages.length;i++) {
var seperator = pages[i].charAt(0);
if(pages[i].indexOf(seperator)>=0){
siteContent = pages[i].split(seperator);
}
if( index(siteContent[2],pattern,false)>=0){
return siteContent[1];
}
}
return "";
}
In this case, the first occurrence of pattern in all pages will be returned.

Javascript if value is in array else in next array

I have found a few posts on here with similar questions but not entirely the same as what I am trying. I am currently using a simple if statement that checks the data the user enters then checks to see if it starts with a number of different values. I am doing this with the following:
var value = string;
var value = value.toLowerCase();
country = "NONE";
county = "NONE";
if (value.indexOf('ba1 ') == 0 || value.indexOf('ba2 ') == 0 || value.indexOf('ba3 ') == 0) { //CHECK AVON (MAINLAND UK) UK.AVON
country = "UK";
county = "UK.AVON";
} else if(value.indexOf('lu') == 0){//CHECK BEDFORDSHIRE (MAINLAND UK) UK.BEDS
country = "UK";
county = "UK.BEDS";
}
I have about 20-30 different if, else statements that are basically checking the post code entered and finding the county associated. However some of these if statements are incredibly long so I would like to store the values inside an array and then in the if statement simply check value.indexOf() for each of the array values.
So in the above example I would have an array as follows for the statement:
var avon = new Array('ba1 ','ba 2','ba3 ');
then inside the indexOf() use each value
Would this be possible with minimal script or am I going to need to make a function for this to work? I am ideally wanting to keep the array inside the if statement instead of querying for each array value.
You can use the some Array method (though you might need to shim it for legacy environments):
var value = string.toLowerCase(),
country = "NONE",
county = "NONE";
if (['ba1 ','ba 2','ba3 '].some(function(str) {
return value.slice(0, str.length) === str;
})) {
country = "UK";
county = "UK.AVON";
}
(using a more performant How to check if a string "StartsWith" another string? implementation also)
For an even shorter condition, you might also resort to regex (anchor and alternation):
if (/^ba(1 | 2|3 )/i.test(string)) { … }
No, it doesn’t exist, but you can make a function to do just that:
function containsAny(string, substrings) {
for(var i = 0; i < substrings.length; i++) {
if(string.indexOf(substrings[i]) !== -1) {
return true;
}
}
return false;
}
Alternatively, there’s a regular expression:
/ba[123] /.test(value)
My recomendation is to rethink your approach and use regular expressions instead of indexOf.
But if you really need it, you can use the following method:
function checkStart(value, acceptableStarts){
for (var i=0; i<acceptableStarts.length; i++) {
if (value.indexOf(acceptableStarts[i]) == 0) {
return true;
}
}
return false;
}
Your previous usage turns into:
if (checkStart(value, ['ba1', ba2 ', 'ba3'])) {
country = 'UK';
}
Even better you can generalize stuff, like this:
var countryPrefixes = {
'UK' : ['ba1','ba2 ', 'ba3'],
'FR' : ['fa2','fa2']
}
for (var key in countryPrefixes) {
if (checkStart(value, countryPrefixes[key]) {
country = key;
}
}
I'd forget using hard-coded logic for this, and just use data:
var countyMapping = {
'BA1': 'UK.AVON',
'BA2': 'UK.AVON',
'BA3': 'UK.AVON',
'LU': 'UK.BEDS',
...
};
Take successive characters off the right hand side of the postcode and do a trivial lookup in the table until you get a match. Four or so lines of code ought to do it:
function getCounty(str) {
while (str.length) {
var res = countyMapping[str];
if (res !== undefined) return res;
str = str.slice(0, -1);
}
}
I'd suggest normalising your strings first to ensure that the space between the two halves of the postcode is present and in the right place.
For extra bonus points, get the table out of a database so you don't have to modify your code when Scotland gets thrown out of leaves the UK ;-)

How do I call a function with in a function?

I need to add i3c to my and statements. I don't know the correct syntax. This code is broken. Would an anonymous function be better? So if c0() passes, c4() runs, if c4() passes I need i3c() to run or what is in i3c to run.
function o1(a,b)
{
document.getElementById(a).value=b;
}
function i3()
{
var a=document.forms['f3'].elements,b='f3e';
c0(a,'Please enter both a tile and a url',b)&&c4(a[2],'Please enter a valid url',b)&&d0()&&s0('pi3a.php',is('f3'),s2);
o1(f3aa,'');o1(f3bb,'');
}
function d0()
{
var a=document.getElementById('Bb1c'),
b=document.createElement('a'),
c=document.forms['f3'].elements;
b.href=c[2].value;
b.name="a1";
b.className ="b";
b.innerHTML = c[1].value;
a.appendChild(b);
return 1;
}
The && (logical AND operator) is processed left to right. If any expression returns false, that value is returned. If all but the last one return true, then the value of the last expression is returned (whether it is true or false).
So if i3c is not being called, it is because the return value of one of the preceding calls is falsey, i.e. it type converts to false, so it might be 0, '' (empty string), undefined, NaN, null, ... I've probably left one out.
Edit
As patrick w commented, the line:
c.setAttribute("class","b");
will fail in IE. Don't use setAttribute for standard attributes, use DOM properties instead:
c.href = d[2].value;
c.name = "a1";
c.className = "b";
Faster and less bugy.
function i3() {
var e = 'f3e';
if ( !(c0(a,'Please enter both a tile and a url',e)) ) { return flase; }
if ( !(c4(a[2],'Please enter a valid url',b)) ) { return flase; }
(function() {
var doc = document,
a = doc.forms.f3.elements,
b = doc.getElementById('Bb1c'),
c = doc.createElement('a'),
d = doc.forms.f3.elements;
c.href = d[2].value;
c.name = "a1";
c.className = "b";
c.innerHTML = d[1].value;
b.appendChild(c);
// which a you need here ???
//var a = is('f3');
var someOtherA = is('f3');
//------------------------
s0('pi3a.php', a, s2);
// if these are part of the form you use in this function
// use
// document.forms[<name>].elements[<name>].value
doc.getElementById('f3aa').value = '';
doc.getElementById('f3bb').value = '';
})();
}
This may work, I suppose c0 and c4 return true/false. This way they are easier to read. If they return true, continue with the next one and don`t return.
In the i3c function you declare a twice!
Look at the comments for more details.

Categories