Angular's NgClick has outdated scope - javascript

I'm experiencing a strange behaviour, but I don't know who's fault it is.
I have three variables in $scope that can be changed by the user. They are bind to a select object through ng-model.
<select ng-options="hour.label for hour in hours track by hour.val" ng-model="new_hour"></select> HH :
<select ng-options="minute.label for minute in minutes track by minute.val" ng-model="new_minute"></select> MM :
<br />
new_hour = {{ new_hour }}<br />
new_minute = {{ new_minute }} </br>
where the variables are initialized as follows:
$scope.minutes = [];
for(var i = 0; i < 60; ++i)
{
var min = String(i);
if(i < 10)
min = "0" + min;
$scope.minutes.push({ val: i, label: min});
}
$scope.hours = $scope.minutes.slice(0, 24);
$scope.new_minute = $scope.minutes[0];
$scope.new_hour = $scope.hours[0];
Whenever I choose a different time, the values of $scope.new_hour and $scope.new_minute change immediately as expected.
However, I have also a button that has a ngClick and calls some function in the $scope.
<button ng-click="add_value()">Add value</button>
If I select a new (minute) value and then click on the button, then the $scope function sees the old values and not the new ones:
$scope.add_value = function()
{
console.log("new_minute: " + $scope.new_minute.val);
}
Let's say I've chosen 03 and then click on the button. The console shows new_minute: 0.
However, if I modify my code:
<button ng-click="add_value(new_minute.val)">Add vaue</button>
and
$scope.add_value = function(new_minute)
{
console.log("new_minute: " + new_minute);
}
Then the value passed to add_value is always correct. I if open the inspect console and inspect the value of $scope.new_minute.val, then $scope.new_minute.val differs from the local variable new_minute.
I've prepared a fiddle with the basic structure of my code: https://jsfiddle.net/shaoran/tnvou6ud/1/
There everything works as expected, I honestly cannot reproduce this behaviour. Has anybody any idea what might be going on?

Related

JS to perform calculation based on user input

I have a code where I am trying to calculate a total value based on the value of the input selected by a user. It seems simple but I can't get the total to reflect. Please can someone show me where the fault is?
function calculate() {
var panel = parseInt(document.getElementsById("panel").value);
panelv = 65;
panelt = panel * panelv;
derating_value = 2;
total_hours_standby = panelt * derating_value;
}
document.getElementsById("total_hours").innerHTML = total_hours_standby;
<input type="number" id="panel" placeholder="panel quantity"></input><br>
<button type="button" onclick="calculate">Result</button>
<p id="total_hours">result displays here</p>
You need to
use for onclick="calculate()" take the function call, not only the function,
use getElementById, spelling matter,
declare all variables,
and finally move the output inside of the function
function calculate() {
var panel = parseInt(document.getElementById("panel").value),
panelv = 65,
panelt = panel * panelv,
derating_value = 2,
total_hours_standby = panelt * derating_value;
document.getElementById("total_hours").innerHTML = total_hours_standby;
}
<input type="number" id="panel" placeholder="panel quantity"></input><br>
<button type="button" onclick="calculate()">Result</button>
<p id="total_hours">result displays here</p>
getElementById is singular
declare your vars
call calculate() with brackets
assign the value inside the function
</input> is not needed
Here is a version with eventListeners since other answers already showed you how to fix YOUR version
function calculate() {
var panel = +document.getElementById("panel").value;
if (panel === "" || isNaN(panel)) panel = 0;
let panelv = 65;
let panelt = panel * panelv;
let derating_value = 2;
document.getElementById("total_hours").textContent = (panelt * derating_value);
}
window.addEventListener("load", function() {
document.getElementById("calc").addEventListener("click", calculate)
calculate(); // run at load
})
<input type="number" id="panel" placeholder="panel quantity"><br>
<button type="button" id="calc">Result</button> result displays here: <span id="total_hours"></span>
First, you should call method calculate.
<button type="button" onclick="calculate()">Result</button>
Then, add this line document.getElementsById("total_hours").innerHTML = total_hours_standby; inside calculate function.
Alos, typo error: document.getElementById instead of document.getElementsById
There are couple of issues here:
Most you could have found out if you had looked into console logs.
For starter the function is called getElementById not getElementsById, because there is supposed to be only one element with unique id, so plural does not make sense here.
Another one is a logic error: not updating content after clicking on button i.e when calculate gets executed.
There is also one more syntax error, which is how functions should be passed to HTML element's attribute. It needs to be functionName() instead of functionName
This is how simply fixing this code could look like:
var total_hours_standby = 0;
function calculate() {
var panel = parseInt(document.getElementById("panel").value);
panelv = 65;
panelt = panel * panelv;
derating_value = 2;
total_hours_standby = panelt * derating_value;
document.getElementById("total_hours").innerHTML = total_hours_standby;
}
document.getElementById("total_hours").innerHTML = total_hours_standby;
<input type="number" id="panel" placeholder="panel quantity"></input><br>
<button type="button" onclick="calculate()">Result</button>
<p id="total_hours">result displays here</p>
Here I give you couple of ideas for improving it.
Since you use global variable total_hours_standby it may be a good
idea to encapsulate it. So called module pattern should do the job.
New value of total_hours_standby does not seem to depend on an old
one, so I guess you mean to use it somewhere else - in order to do
so, you need to expose it with "public" getter.
If above is not the case, then you don't need total_hours_standby
variable at all and you can just directly return it or display it
without storing this value in variable.
I put code for rendering in separate function - this is because rule
of thumb for functions is that they should have single
responsibility. One functions for calculations, another for rendering
and then one function for handling user's input and click event, that
uses two previous ones. This way if for example you only want to
calculate something without rendering result, then you just, simply can :)
I also stored DOM nodes in variables, instead of calling
getElementById, it is not due to performance, how it is often
assumed, I did it only for better readability.
Constants instead of hard-coded values.
var Calculator = (function() {
const panelInput = document.getElementById("panel");
const output = document.getElementById("total_hours");
const PANEL_V = 65;
const DERATING_VALUE = 2;
const render = value => output.innerHTML = value;
const calculate = value => value * PANEL_V * DERATING_VALUE;
let total_hours_standby = 0;
return {
handleInput: function() {
total_hours_standby = calculate(panelInput.value);
render(total_hours_standby);
},
getTotalHoursStandby: () => total_hours_standby
};
})();
<input type="number" id="panel" placeholder="Panel quantity" />
<button type="button" onclick="Calculator.handleInput()">Calculate</button>
<p id="total_hours">Result displays here</p>
It is typo,
document.getElementsById
should be
document.getElementById

JavaScript returning null on a function for a simple guessing game

I created a guessing game using JavaScript. Initially, I wrote it in codepen where it ran fine, and when I moved it over to sublime to test it in the browsers as a standalone, the code did not work. I am getting this error: "Uncaught TypeError: Cannot read property 'value' of null at guess" which is line 14 var guessValue = parseInt(guessIn.value); and links back to the HTML of line 20 which is Guess
I can't figure out where the null is coming from. What am I doing wrong or haven't defined properly that is causing the null? I removed the CSS to blank slate it and make sure that wasn't screwing anything up.
//Generate random number between 1 and 500
var randomNumber = Math.floor((Math.random() * 500) + 1);
//Create variables to store info for loops and displaying info back to user
var guessIn = document.getElementById('userGuess');
var guessOut = document.getElementById('guessesMade');
var counter = 0;
//function runs when the guess button is hit
function guess() {
//declare temp local var and store as an integer for conditional testing
var guessValue = parseInt(guessIn.value);
//if statement for finding the value and reporting to the user
//check if the counter is less than 10 and guessValue is not empty
if (counter < 10 && guessValue) {
counter++;
}
//the guess is correct
if (guessValue == randomNumber) {
guessOut.value = guessOut.value + '\n' + "Guess " + counter + " is " + guessIn.value + ':' + ' You have correctly guessed the number. You may escape.';
}
// the guess is greater
if (guessValue > randomNumber) {
guessOut.value = guessOut.value + '\n' +"Guess " + counter + " is " + guessIn.value + ':' + ' Your guess is incorrect. The number I am thinking of is lower.';
}
//the guess is lower
if (guessValue < randomNumber) {
guessOut.value = guessOut.value + '\n' + "Guess " + counter + " is " + guessIn.value + ':' + ' Your guess is incorrect. The number I am thinking of is higher.';
}
//when all 10 guesses are used
else if (counter == 10) {
guessOut.value = guessOut.value + '\n' + "You did not guess the number I was thinking, " + randomNumber + "." + " You have met your end. Goodbye.";
}
return false;
}
//Show the number to guess upon clicking the checkbox for Cheat
function cheat() {
if (document.getElementById('cheat').checked) { document.getElementById('cheatNumber').value = randomNumber;
document.getElementById('cheatShow').style.display = 'inline';
}
else { document.getElementById('cheatNumber').value = '';
document.getElementById('cheatShow').style.display = 'none';
}
}
//function to reset the game
function reset() {
//reset guess value
userGuess.value = "";
//reset text area
guessesMade.value = "";
//reset counter
counter = 0;
//set new random number for play
randomNumber = Math.floor((Math.random() * 500) + 1);
return false;
}
<html>
<head>
<title>Do You Wanna Play A Game?</title>
<script src="game.js"></script>
</head>
<body>
<h1>Do You Wanna Play A Game?</h1>
<h3>A Guessing Game</h3>
<fieldset>
<legend>The Game Starts Now</legend>
<p>Welcome. You have stumbled upon this page. As a consequence, you have been trapped. To get out, the objective is simple.</p>
<p>I am thinking of a number. This number is between 1 and 500. You get ten guesses.</p>
<p>Good luck.</p>
<div id="guessingarea">
<input type="text" id="userGuess" value="394" /><br />
<button onClick="guess();">Guess</button>
<button onClick="reset();">Reset</button>
<br />
<input id="cheat" type="checkbox" value="cheat" onClick="cheat();" />
<label for="cheat">Cheat</label>
<div id="cheatShow" style="display: none;">
<input id="cheatNumber" type="text"/>
</div>
</div>
</fieldset>
<p></p>
<fieldset>
<legend>Let's examine your guess, shall we?</legend>
<textarea id="guessesMade" rows="14" style="width: 100%;"></textarea>
</fieldset>
</body>
</html>
It looks like you are including the script before your html document.
document.getElementById('userGuess');
is called before the element 'userGuess' exists.
I can think of two solutions to this, either include the script at the end of the document, or access this element only when you need it, rather than declaring it at the beginning like so:
var guessValue = parseInt(document.getElementById('userGuess').value);
You have included the script, before the element is available. As soon as the parser, hits the JS file, it will stop the rendering of the page and try to parse javascript. When the script is encountered, the element is still not available.
You have 2 options to make this work.
Move the script tag to before the close of the body element. This will make sure the page has the available elements before manipulating them.
<fieldset>
<legend>Let's examine your guess, shall we?</legend>
<textarea id="guessesMade" rows="14" style="width: 100%;"></textarea>
</fieldset>
<script src="game.js"></script>
</body>
Query the elements every single time inside the guess method since it is only invoked on a click action, which happens only after page is rendered.
function guess() {
var guessIn = document.getElementById('userGuess');
var guessOut = document.getElementById('guessesMade');
//declare temp local var and store as an integer for conditional testing
var guessValue = parseInt(guessIn.value);
......
......
The reason it works on code pen is because, the scripts are executed are deferred to onLoad which makes sure the elements are available on the page.
If you move the variable declarations inside the function it will work. The issue is that the JavaScript code is executed before the document is ready so the guessIn and guessOut variables are initialised to null.
Alternatively you can wrap your JavaScript code in a function that will execute when the DOM is complete.
document.onreadystatechange = function () {
if (document.readyState === "complete") {
// your code goes in here
}
}
See MDN for more details.

Javascript returns [object HTMLSpanElement]

I'm making a simple game for selling anchovies. I have an upgrade to buy a small fishing net. The fishing net costs a certain amount of anchovies, so I subtract that number from the total and then rewrite using innerHTML. I want this small net to add 1 anchovy every second, so I use window.setInterval. However, now every second [object HTMLSpanElement] is written to the page.
What do I do?
Here is the jsfiddle link: http://jsfiddle.net/Bj6M5/1/
And here is the code:
<head>
<script type="text/javascript">
var anchovies = 0;
var money = 0;
function goFish(num) {
anchovies = anchovies + num;
money = 0.433 * anchovies;
var money_rounded;
money_rounded = money.toFixed(2);
if (anchovies != 1) {
document.getElementById("anchovies").innerHTML = anchovies + " anchovies";
}
else {
document.getElementById("anchovies").innerHTML = "1 anchovy";
}
document.title = "$" + money_rounded + " - Anchovy Bros.";
}
function buySmallNet(){
var smallnet_price = Math.floor(10 * Math.pow(1.1,smallnets));
if (anchovies >= smallnet_price) {
smallnets = smallnets + 1;
anchovies = anchovies - smallnet_price;
if (smallnets != 1) {
document.getElementById("smallnets").innerHTML = smallnets + " small nets";
}
else {
document.getElementById("smallnets").innerHTML = "1 small net";
}
document.getElementById("anchovies").innerHTML = anchovies + " anchovies";
}
else {
alert("You don't have enough anchovies!");
}
}
window.setInterval(function(){
goFish(smallnets);
}, 1000);
</script>
<title>$0 - Anchovy Bros.</title>
</head>
<body>
<button onclick="goFish(1);">FISH!</button>
<br>
<span id="anchovies"></span>
<div style="float:right;" id="upgrades">
<center>
<button onclick="buySmallNet();">small fishing net</button>
<br>
<span>costs 15 anchovies</span>
<br>
<span id="smallnets"></span>
</center>
</div>
</body>
You're calling goFish(smallnets). smallnets is the id of an element, so you're passing that element. You're expecting a number in goFish and do all kinds of calculations and assignments, which obviously fail, because it's an element and not a number. In the end, you're outputting anchovies, which is now assigned that element, instead of the result of a calculation.
So there's a missing links somewhere where you need to convert the element to a number, which should probably be the contents of the element (being the number of small nets in posession).
The reason is this line:
goFish(smallnets);
You haven't declared a smallnets variable anywhere, but you have an element in your markup with the id "smallnets" which is a span. Most browsers create global variables for elements with id values, where the name of the variable is the id and the value is the DOM element.
Then in goFish, this line:
anchovies = anchovies + num;
is (on the first pass):
anchovies = 0 + a_span_element;
Since the span can't be reasonably converted to a number, it's converted to a string, which is "[object HTMLSpanElement]". Then the 0 is converted to a string and you have "0[object HTMLSpanElement]".
And then the next time the interval fires, you add another copy of "[object HTMLSpanElement]" to it, etc., etc.
If your goal is to use the text of the span, you want:
goFish(smallnets.innerHTML);
or better
goFish(parseInt(smallnets.innerHTML, 10));
or even better, don't rely on the global created via the id:
goFish(parseInt(document.getElementById("smallnets").innerHTML, 10));
You'll also want to put 0 or something in the span, e.g.:
<span id="smallnets">0</span>

Pass variable in document.getElementByid in javascript

I have a variable account_number in which account number is stored. now i want to get the value of the element having id as account_number. How to do it in javascript ?
I tried doing document.getElementById(account_number).value, but it is null.
html looks like this :
<input class='transparent' disabled type='text' name='113114234567_name' id='113114234567_name' value = 'Neeloy' style='border:0px;height:25px;font-size:16px;line-height:25px;' />
and the js is :
function getElement()
{
var acc_list = document.forms.editBeneficiary.elements.bene_account_number_edit;
for(var i=0;i<acc_list.length;i++)
{
if(acc_list[i].checked == true)
{
var account_number = acc_list[i].value.toString();
var ben_name = account_number + "_name";
alert(document.getElementById("'" + ben_name.toString() + "'").value);
}
}
}
here bene_account_number_edit are the radio buttons.
Thanks
Are you storing just an integer as the element's id attribute? If so, browsers tend to behave in strange ways when looking for an element by an integer id. Try passing account_number.toString(), instead.
If that doesn't work, prepend something like "account_" to the beginning of your elements' id attributes and then call document.getElementById('account_' + account_number).value.
Why are you prefixing and post-fixing ' characters to the name string? ben_name is already a string because you've appended '_name' to the value.
I'd recommend doing a console.log of ben_name just to be sure you're getting the value you expect.
the way to use a variable for document.getElementById is the same as for any other function:
document.getElementById(ben_name);
I don't know why you think it would act any differently.
There is no use of converting ben_name to string because it is already the string.
Concatenation of two string will always give you string.
var account_number = acc_list[i].value.toString();
var ben_name = account_number + "_name";
try following code it will work fine
var ben_name=acc_list[i]+ "_name";
here also
alert(document.getElementById("'" + ben_name.toString() + "'").value);
try
alert(document.getElementById(ben_name).value);
I have tested similar type of code which worked correctly. If you are passing variable don't use quotes. What you are doing is passing ben_name.toString() as the value, it will definitely cause an error because it can not find any element with that id viz.(ben_name.toString()). In each function call, you are passing same value i.e. ben_name.toString() which is of course wrong.
I found this page in search for a fix for my issue...
Let's say you have a list of products:
<div class="rel-prod-item">
<img src="assets/product-photos/title-of-the-related-product_thumbnail.jpg" alt="Western Digital 1TB" />
<p class="rel-prod-title">Western Digital 1TB</p>
<p class="rel-prod-price" id="price_format_1">149.95</p>
add to cart
</div>
<div class="rel-prod-item">
<img src="assets/product-photos/title-of-the-related-product_thumbnail.jpg" alt="Western Digital 1TB" />
<p class="rel-prod-title">Western Digital 1TB</p>
<p class="rel-prod-price" id="price_format_2">139.95</p>
add to cart
</div>
<div class="rel-prod-item">
<img src="assets/product-photos/title-of-the-related-product_thumbnail.jpg" alt="Western Digital 1TB" />
<p class="rel-prod-title">Western Digital 1TB</p>
<p class="rel-prod-price" id="price_format_3">49.95</p>
add to cart
</div>
The designer made all the prices have the digits after the . be superscript. So your choice is to either have the cms spit out the price in 2 parts from the backend and put it back together with <sup> tags around it, or just leave it alone and change it via the DOM. That's what I opted for and here's what I came up with:
window.onload = function() {
var pricelist = document.getElementsByClassName("rel-prod-price");
var price_id = "";
for (var b = 1; b <= pricelist.length; b++) {
var price_id = "price_format_" + b;
var price_original = document.getElementById(price_id).innerHTML;
var price_parts = price_original.split(".");
var formatted_price = price_parts[0] + ".<b>" + price_parts[1] + "</b>";
document.getElementById(price_id).innerHTML = formatted_price;
}
}
And here's the CSS I used:
.rel-prod-item p.rel-prod-price b {
font-size: 50%;
position: relative;
top: -4px;
}
I hope this helps someone keep all their hair :-)
Here's a screenshot of the finished product

change option of <select> Dynamically with javascript and read it on asp.net

I have : select id="select1" runat="server"> option>choose something /option> /select>
and I have this javascript function
var op = document.getElementById("select1");
for (i = 0; i < array.length - 1; i++) {
op.options[i] = new Option(arr[i]);
}
now after this function, the select has more <option>.
Now When pressing on asp:button, I want to be able to read(on server side) the new selected value.
unfortunately when the server process the page ,all the selcet1 values that was given by the javascript function are gone and the server always see the orignal value of the select1 ("choose something").
so, I can I read, on server side, the new options of the select1, that was generte by the javascript ?
Thanks for any help
Baaroz
You can loop the values by finding it using Request.Form, like
foreach(string key in Request.Form) {
Response.Write(key + ": " + Request.Form[key] + "<br />");
}
You might also just find it by using Request.Form["select1"];

Categories