Having trouble using ngChange to update model - javascript

I just started learning the basics of Angular. I'm attempting to making an annual salary converter, just for fun. I'm having difficulty with my monthly ng-model updating when the yearly model is changed by the user. The fields are input tags. Here is the code
<!doctype html>
<html ng-app="salaryApp">
<head>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container" ng-controller="converter">
<h1>Salary converter</h1>
<div class="form-group">
<label>Annual Salary</label>
<input type="number" class="form-control" placeholder="0" ng-model="yearly" ng-change="reCalculate()" >
<br>
<label>Monthly Salary</label>
<input type="number" class="form-control" placeholder="0" ng-model="monthly" disabled>
</div>
</div>
<!--<div ng-controller="converter">
Write some text in textbox:
<input type="text">
<h1>Hello {{ yearly }}</h1>
<h1>Hello {{ monthly }}</h1>
</div>-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<!--<script src="salaryConverter.js"></script>-->
<script type="text/javascript">
var app = angular.module('salaryApp', []);
app.controller('converter', function($scope) {
$scope.yearly = 80000;
console.log("log1");
$scope.monthly = $scope.yearly / 12;
console.log("log2");
function reCalculate() {
console.log("function was run");
return $scope.yearly /12.00;
}
});
</script>
</body>
</html>
Here is the plnkr
http://plnkr.co/edit/26y0JRR7iVcrLOBlm7D2?p=preview

Youe need to use it as scope property. Here :
function reCalculate() {
console.log("function was run");
return $scope.yearly /12.00;
}
should be
$scope.reCalculate = function () {
console.log("function was run");
$scope.monthly=$scope.yearly /12.00;//Don't return, you neet to assign
}

Define function as in $scopeto be called from view and assign value to monthly instead of returning.
$scope.reCalculate = function () {
console.log("function was run");
$scope.monthly = $scope.yearly / 12.00;
}
DEMO

You need to add the reCalculate method to your scope:
app.controller('converter', function($scope) {
$scope.yearly = 80000;
$scope.reCalculate = reCalculate; <--- THIS LINE
console.log("log1");
$scope.monthly = $scope.yearly / 12;
console.log("log2");
function reCalculate() {
console.log("function was run");
return $scope.yearly /12.00;
}
});
You could also add it directly:
$scope.reCalculate = function()...
But I recommend to follow some style guides on how to write your controllers:
https://github.com/johnpapa/angular-styleguide

app.controller('converter', function($scope) {
$scope.yearly = 80000;
console.log("log1");
$scope.monthly = $scope.yearly / 12;
console.log("log2");
$scope.reCalculate = function () {
console.log("function was run");
$scope.monthly = $scope.yearly / 12;
}
});
Here is your plunker working

Related

Angular only update input field when not having focus

I have an input field which is for both setting and readback. I would like to have the following behavior:
No focus: update the field with readback
Focus: no update, if enter is pressed call send with the value written in the field.
I have a mwe which is a start but does update when focused.
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js"></script>
<script>
angular.module('App', []).controller('world', function ($scope) {
$scope.value1 = 0;
$scope.value2 = 0;
$scope.send = function(value) {
alert(value);
}
let readback = function() {
$scope.value1 += 1;
$scope.value2 += 1;
$scope.$apply();
setTimeout(readback, 100);
};
setTimeout(readback, 1);
});
</script>
</head>
<body ng-app="App" ng-controller="world">
<input type="text" ng-model="value1" ng-keyup="$event.keyCode == 13 && send(value1)" />
<input type="text" ng-model="value2" ng-keyup="$event.keyCode == 13 && send(value2)" />
</body>
Edit: Sorry I was a bit unclear and cut down my mwe too much. I have about ten such input fields. The unfocused fields should still update while only the one which is selected does not.
you can detect ng-focus and ng-blur, using separate controller instances for each input:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js">
</script>
<script>
angular.module('App', []).controller('world', function ($scope) {
let isFocus = false;
$scope.value = 0;
$scope.send = () => alert($scope.value);
$scope.focus = () => isFocus = true;
$scope.blur = () => isFocus = false;
let readback = function() {
if (!isFocus) {
$scope.value += 1;
$scope.$apply();
}
setTimeout(readback, 100);
};
setTimeout(readback, 1);
});
</script>
</head>
<body ng-app="App">
<input type="text"
ng-controller="world"
ng-model="value"
ng-keyup="$event.keyCode == 13 && send()"
ng-focus="focus()"
ng-blur="blur()" />
<input type="text"
ng-controller="world"
ng-model="value"
ng-keyup="$event.keyCode == 13 && send()"
ng-focus="focus()"
ng-blur="blur()" />
</body>

How to pass data from input to a custom service?

I am new to AngularJS and I have a problem: how to display the hex equivalent of the number inserted into the input box?
I am using ng-change to see if the input is modified and the output should also change according to the input.
This is the code:
<div ng-app="myApp" ng-controller="myCtrl">
<input type="number" ng-model="in" ng-change="hex(in)">
{{in}} <br>{{hex}}
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.js"></script>
<script>
var app = angular.module('myApp', []);
app.service('hexafy', function() {
this.myFunc = function (x) {
return x.toString(16);
}
});
app.controller('myCtrl', function($scope, hexafy) {
$scope.in= 11;
$scope.hex = hexafy.myFunc($scope.in);
});
</script>
Why it does not work?
In your input, you try to call a function:
<input type="number" ng-model="in" ng-change="hex(in)">
But $scope.hex is not a function in your controller:
$scope.hex = hexafy.myFunc($scope.in);
How to fix it?
Change it to:
$scope.hex = function() {
$scope.result = hexafy.myFunc($scope.in);
}
var app = angular.module('myApp', []);
app.service('hexafy', function() {
this.myFunc = function (x) {
return x.toString(16);
}
});
app.controller('myCtrl', function($scope, hexafy) {
$scope.in= 11;
$scope.hex = function() {
$scope.result = hexafy.myFunc($scope.in);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<input type="number" ng-model="in" ng-change="hex()">
{{in}} <br>{{result}}
</div>
Created Plunker. Problem is that you are using function name as assignment.
<input type="number" ng-model="in" ng-change="convertToHex(in)">
$scope.convertToHex= function(value) {
$scope.hex = hexafy.myFunc(value);
}

Addition of two numbers in angularJS onclick

I am trying to add two numbers and want to display its result only when I click a button. Here is my code below:
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="myApp" ng-controller="myCtrl">
<h2>Calculator</h2>
a: <input type="number" ng-model="a">
b: <input type="number" ng-model="b">
<button ng-click="addFunc()">Sum</button>
Sum : {{sum}}
<!-- <p><b>Summation:</b> {{sum = a + b}}</p> -->
<br/><br/><br/>
c: <input type="number" ng-model="c">
d: <input type="number" ng-model="d">
<p><b>Subtraction:</b> {{c - d}}</p>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.sum = 0;
$scope.addFunc = function() {
$scope.sum=a+b;
}
});
</script>
</body>
</html>
If you try to access a and b from this function, it will look into the lexical scope of this function. Since you don't have the variables declared over there it won't work. You neither have the variables declared anywhere up in the scope chain as its inside the custom $scope(just a javascript Object) maintained by angular. Angular uses its own $scope which is injected into the controller, to access that scope you have to access via $scope. itself. The idea is to share this between template(view) and function(controller)
$scope.addFunc = function() {
$scope.sum=a+b;
}
In your template a + b works because angular uses $scope internally for all variables used in your template, so you don't have to add $scope over there.
<p><b>Summation:</b> {{sum = a + b}}</p>
In your case you can use $scope like:
$scope.addFunc = function() {
$scope.sum= $scope.a + $scope.b;
}
or use this as the function is called with $scope and will have implicit reference.
$scope.addFunc = function() {
this.sum= this.a + this.b; //when calling $scope.addFunc() this will be $scope
}
or use with statement (although not recommended due to some edge cases)
$scope.addFunc = function() {
with($scope) sum = a + b;
}
The moment you wrote a & b as ng-model, They are automatically connected to $scope object.
So if you want to add them, you simply have to write
$scope.a + $scope.b
Try this code
Calculator
a: <input type="number" ng-model="a">
b: <input type="number" ng-model="b">
<button ng-click="addFunc()">Sum</button>
Sum : {{sum}}
<!-- <p><b>Summation:</b> {{sum = a + b}}</p> -->
<br/><br/><br/>
c: <input type="number" ng-model="c">
d: <input type="number" ng-model="d">
<p><b>Subtraction:</b> {{c - d}}</p>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.sum = 0;
$scope.addFunc = function() {
$scope.sum=$scope.a+$scope.b;
}
});
</script>
</body>
</html>
a and b are in $scope:
$scope.addFunc = function() {
$scope.sum = $scope.a + $scope.b;
}
Pass the values to controller
<button ng-click="addFunc(a, b)">Sum</button>
controler
$scope.addFunc = function(a, b) {
$scope.sum=a+b;
}
OR
HTML:
<button ng-click="addFunc()">Sum</button>
Controller:
$scope.addFunc = function() {
$scope.sum=$scope.a+$scope.b;
}
Here is solution
jsfiddle
function MyCtrl($scope) {
$scope.name = 'Superhero';
$scope.sum = 0;
$scope.addFunc = function() {
$scope.sum=$scope.a+$scope.b;
}
Try this code: We need to type cast our variable i.e., ng-model value to number else it will return string.
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body ng-app="MyApp" ng-controller="myctrl">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"> </script>
<script>
var app=angular.module("MyApp",[]);
app.controller("myctrl",function($scope){
$scope.value=0;
$scope.add=function(){
$scope.value=Number($scope.fnum)+ Number($scope.snum);
};
});
</script>
firstname:<input type="text" ng-model="fnum" placeholder="Enter value" /><br>
lastname:<input type="text" ng-model="snum" placeholder="Enter value" /><br>
<input type="button" value="Click" ng-click="add() " /><br>
<div ng-repeat="a in res()">{{a}}</div>
<div>{{value}}</div>
</body>
</html>

accessing attribute directive values using controller as

I know how to do it Without controller as:
html
Let's assume I have a directive named ngUpperCase(either true or false)
<div ng-controller="myControl" >
<input type="text" ng-upper-case="isGiant" >
</div>
Js
myApp.directive('ngUpperCase',function(){
return{
restrict:'A',
priority:0,
link:function($scope,element,attr){
//---to retrieve value
var val = $scope[attr.ngUpperCase];
var anotherVal = $scope.$eval(attr.ngUpperCase);
$scope.$watch(attr.ngUpperCase,function(val){
//---to watch
})
}
};
})
How to make the directive if I'm using something like this?
<div ng-controller="myControl as ctl" >
<input type="text" ng-upper-case="ctl.isGiant" >
</div>
Since it's not very clear what you want to achieve, here is an example of doing what I understand you need: changing an input value to upper or lower case depending on a variable:
function ngUpperCase() {
return{
restrict:'A',
priority:0,
link:function($scope,element,attr){
//---to retrieve value
var val = $scope[attr.ngUpperCase];
var anotherVal = $scope.$eval(attr.ngUpperCase);
$scope.$watch(attr.ngUpperCase,function(val){
if(val) {
element[0].value = element[0].value.toUpperCase();
} else {
element[0].value = element[0].value.toLowerCase();
}
})
}
}
}
function myController() {
this.isGiant = true;
}
angular.module('myApp', []);
angular
.module('myApp')
.controller('myController', myController)
.directive('ngUpperCase', ngUpperCase);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myController as ctl" >
lower case<br>
upper case
<input type="text" ng-upper-case="ctl.isGiant" value="TeStiNg123" >
</div>
</div>

Unable to trigger submit in angularJS from a single button

Using ng-submit I have a form submission callback namely submitFN. Have 2 buttons:
Fund my startup!
Reset
My desirable output is on clicking the reset button, the input field gets 0. And on clicking "Fund my startUp" it shows an alert. How to attain this?
Problem:
Both the buttons are triggering the submitFN. Unable to reset.
Code:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.js">
</script>
<script>
var mainApp = angular.module("mainApp", []);
mainApp.controller('startUpController', function($scope) {
$scope.funding = {
startingEstimate: 0
};
$scope.calculate = function () {
$scope.funding.needed = $scope.funding.startingEstimate * 10;
};
$scope.submitFN = function () {
window.alert('Go and find more customers.')
}
$scope.resetFN = function () {
$scope.startingEstimate = 0;
}
});
</script>
</head>
<body>
<div ng-app='mainApp'>
<form ng-submit="submitFN()" ng-controller="startUpController">
Starting: <input type="text" ng-change="calculate()" ng-model="funding.startingEstimate"/>
Recommended: {{funding.needed}}
<button>Fund my startup!</button>
<button ng-click="resetFN()">Reset</button>
</form>
</div>
</body>
</html>
I am entirely novice in angularJS and any help is highly appreciable. Thanks in advance.
UPDATE
One of code I tried:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.js">
</script>
<script>
var mainApp = angular.module("mainApp", []);
mainApp.controller('startUpController', function($scope) {
$scope.funding = {
startingEstimate: 0
};
$scope.calculate = function () {
$scope.funding.needed = $scope.funding.startingEstimate * 10;
};
$scope.submitFN = function () {
window.alert('Go and find more customers.')
}
$scope.resetFN = function () {
$scope.startingEstimate = 0;
}
});
</script>
</head>
<body>
<div ng-app='mainApp'>
<form ng-submit="submitFN()" ng-controller="startUpController">
Starting: <input type="text" ng-change="calculate()" ng-model="funding.startingEstimate"/>
Recommended: {{funding.needed}}
<button>Fund my startup!</button>
<button type = "button" ng-click="resetFN()">Reset</button>
</form>
</div>
</body>
</html>
By default the button type is submit, so you the 2nd button also has button type submit. If you don't want to submit a form on that button, you should explicitly make that button type as a button
type="button"
Also you had mistake in resetFN code, It should be modify a value which is assigned to ng-model
$scope.resetFN = function () {
$scope.funding.startingEstimate = 0;
}
corrected code below:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.js">
</script>
<script>
var mainApp = angular.module("mainApp", []);
mainApp.controller('startUpController', function($scope) {
$scope.funding = {
startingEstimate: 0
};
$scope.calculate = function () {
$scope.funding.needed = $scope.funding.startingEstimate * 10;
};
$scope.submitFN = function () {
window.alert('Go and find more customers.')
}
$scope.resetFN = function () {
$scope.funding.startingEstimate = 0;
}
});
</script>
</head>
<body>
<div ng-app='mainApp'>
<form ng-submit="submitFN()" ng-controller="startUpController">
Starting: <input type="text" ng-change="calculate()" ng-model="funding.startingEstimate"/>
Recommended: {{funding.needed}}
<button>Fund my startup!</button>
<button type="button" ng-click="resetFN()">Reset</button>
</form>
</div>
</body>
</html>
You miss funding
$scope.resetFN = function () {
$scope.funding.startingEstimate = 0;
}

Categories

Resources