Angular - ngOptions model value not updating - angularjs

Getting started with Angular and am having an issue getting the model binding to work for a select option in a template.
I have the following ng-options select in a template:
<select ng-model="listenercount" ng-options="n for n in [] | range:0:1000" ng-change="listenersUpdate()"></select>
I have filter which looks like this:
angular.module('myapp').filter('range', function() {
return function(input, min, max) {
min = parseInt(min);
max = parseInt(max);
for (var i=min; i<max; i++) {
input.push(i);
}
return input;
};
});
My select shows up correctly with options 0-1000 based on my filter.
In my controller I have the following:
$scope.listenercount = 0;
$scope.listenersUpdate = function() {
alert('new listener count is now:' + $scope.listenercount);
}
My alert message pops up every time I change the select as expected, but it always show $scope.listenercount = 0. The $scope.listenercount model binding does not seem to be update the value.
Anything obvious I am doing wrong?

<body ng-app="myapp">
<script>
angular.module('myapp', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.listenercount = 0;
$scope.listenersUpdate = function() {
alert('new listener count is now:' + $scope.listenercount);
}
}]);
angular.module('myapp').filter('range', function() {
return function(input, min, max) {
min = parseInt(min);
max = parseInt(max);
for (var i=min; i<max; i++) {
input.push(i);
}
return input;
};
});
</script>
<div ng-controller="ExampleController">
<select ng-model="listenercount" ng-options="n for n in [] | range:0:1000" ng-change="listenersUpdate()"></select>
<tt>debug = {{confirmed}}</tt><br/>
<tt>counter = {{counter}}</tt><br/>
</div>
</body>
This is working as expected

Related

not able to call factory at controller

I have created a factory named paging that will return numbers for pagination.
expenseApp.factory('paging', function() {
this.pages = function(min, max, step) {
if (max <= 5) {
min = 1;
}
if (max > 5) {
min = max - 3;
}
step = step || 1;
var input = [];
for (var i = min; i <= max; i += step)
input.push(i);
return input;
};
I want to call this factory in my controller
expenseApp.controller('expenseController', function($scope, $http, paging) {
$scope.range = function() {
$scope.answer = paging.range(0, 10, 1);
}
});
but this code is not working.
I tried it here
var expenseApp = angular.module('expenseApp', []);
expenseApp.factory('paging', function() {
this.pages = function(min, max, step) {
if (max <= 5) {
min = 1;
}
if (max > 5) {
min = max - 3;
}
step = step || 1;
var input = [];
for (var i = min; i <= max; i += step)
input.push(i);
return input;
};
expenseApp.controller('expenseController', function($scope, $http, paging) {
$scope.pages = function() {
$scope.answer = paging.range(0, 10,1);
}
});
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
<link rel="stylesheet" href="style.css">
<script src="MyApp.js"></script>
<script src="MyCtrl.js"></script>
</head>
<body>
<div ng-app="expenseApp" ng-controller="expenseController">
<h1>Hello Plunker!</h1>
<ul class="pagination">
<li ng-repeat="a in pages">
<a ng-click="pagination(a)">{{a}}</a>
</li>
</ul>
</div>
</body>
</html>
var expenseApp = angular.module('expenseApp', []);
expenseApp.factory('paging', function() {
return {
pages: function(min, max, step) {
if (max <= 5) {
min = 1;
}
if (max > 5) {
min = max - 3;
}
step = step || 1;
var input = [];
for (var i = min; i <= max; i += step)
input.push(i);
return input;
}
}
});
expenseApp.controller('expenseController', ['$scope', '$http', 'paging', function($scope, $http, paging) {
$scope.pages = function() {
$scope.answer = paging.pages(0, 10, 1);
}
$scope.pages();
}]);
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
</head>
<body>
<div ng-app="expenseApp" ng-controller="expenseController">
<h1>Hello Plunker!</h1>
<ul class="pagination">
<li ng-repeat="a in answer">
<a ng-click="pagination(a)">{{a}}</a>
</li>
</ul>
</div>
</body>
</html>
Kindly check this snippet.
Changes I made:
index.html
<script src="MYApp.js"></script>
<ul class="pagination">
<li ng-repeat="a in answer">
<a ng-click="pagination(a)">{{a}}</a>
</li>
</ul>
MyCtrl.js
expenseApp.factory('paging', function() {
return {
pages: function(min, max, step) {
if (max <= 5) {
min = 1;
}
if (max > 5) {
min = max - 3;
}
step = step || 1;
var input = [];
for (var i = min; i <= max; i += step)
input.push(i);
return input;
}
}
});
expenseApp.controller('expenseController', ['$scope','$http', 'paging', function($scope, $http, paging) {
$scope.pages = function() {
console.log(paging)
$scope.answer = paging.pages(0, 10,1);
}
$scope.pages();
}]);
This is because you are getting error
Error: [$injector:undef] http://errors.angularjs.org/1.6.5/$injector/undef?p0=paging(…)
Which means that your factory is not returning any values. So, to resolve this you can use this code in your factory
expenseApp.factory('paging', function() {
var paging = {};
var range = function(min, max, step) {
if (max <= 5) {
min = 1;
}
if (max > 5) {
min = max - 3;
}
step = step || 1;
var input = [];
for (var i = min; i <= max; i += step)
input.push(i);
return input;
};
paging.range = range;
return paging;
});
Notice that var paging = {}; is a JSON object that will hold all the functionality provided by this factory like range so paging.range = range; will add a factory method range to the range key of the paging object. Then finally this object is returned from the service.
Now whenever you use the factory paging, then it is similar to using the JSON object paging. Thus, access paging.range(0, 10,1) will now invoke the factory method.
Your plunkr also does not work so here is the link to the working PLUNKR

Slow performance of $watch

I am using angular range slider in my project for having the extended Slider functionality.
I am enclosing the relevant code here.
The directive that I am using has this syntax in the minimal version:
<body ng-controller=“MainController as MC”>
<div range-slider
min="0”
max=“MC.maxPrice”
pin-handle="min”
model-max=“MC.price”
>
</div>
</body>
Consider the following code inside the controller:
this.maxPrice = '1000';
this.price = '69’;
$scope.$watch('MC.price', function (newVal) {
if (newVal || newVal === 0) {
for (var i = 0; i < 999; i++) {
console.log('Successful ouput #' + i);
}
}
});
This seems to be working. But it runs slow.
Could somebody suggest me some workaround or suggestion to improve the performance?
I think you can use a temporary model.
You can add a temporary model bound to change the working model on timeout:
<body ng-controller="MainController as MC">
<div range-slider
min="0"
max="MC.maxPrice"
pin-handle="min"
model-max="MC.priceTemporary"
>
</div>
</body>
and modify the controller as:
this.maxPrice = '100';
this.price = '55';
this.priceTemporary = '55';
$scope.$watch('MC.price', function (newVal) {
if (!isNaN(newVal)) {
for (var i = 0; i < 987; i++) {
console.log('Successful ouput #' + i);
}
}
});
var timeoutInstance;
$scope.$watch('MC.priceTemporary', function (newVal) {
if (!isNaN(newVal)) {
if (timeoutInstance) {
$timeout.cancel(timeoutInstance);
}
timeoutInstance = $timeout(function () {
$scope.MC.price = newVal;
}, 144);
}
});

Dynamic default values for input box in angularJs

I have a value which i get from a controller and two input box.
I need that whenever i enter any value in one input box. difference of the value retrieved from controller and input box get displayed in the other input box using angularJs.
e.g:-
{{sum}} --> is the value which I get from controller.
<input type="number" ng-model="firstnumber" />
<input type="number" ng-model="secondnumber"/>
What I tried was making service for setting and getting the sum value and watch to change the value every time a value is changed.
My service is :-
angular.module('myapp').service("cmModalService", function($scope){
var sum= ={};
getSum = function(){
return sum;
}
setSum = function(value){
sum=value;
};
});
In a controller I have defined
$scope.$watch('firstnumber', function(newValue, oldValue) {
var sum=cmModalService.getSum();
if(newValue!=null)
{ secondnumber = sum -firstnumber;
}
});
$scope.$watch('secondnumber', function(newValue, oldValue) {
var sum=cmModalService.getSum();
if(newValue!=null)
{ firstnumber = sum -secondnumber;
}
});
But whenever i change values in input box the flow never goes to watch method, and the values doesn't change.
Is there any other method also to achieve this.?
I have tried using ng-change also but still not able to get the exact result.
And inside controller i have defined the change methods as
$scope.changefirstnumber=function(firstnumber, sum){
$scope.secondnumber = sum- firstnumber;
};
$scope.changesecondnumber=function(secondnumber, sum){
$scope.firstnumber= sum- secondnumber;
};
and in html
[Plunker link]
You are not setting the scoped variable. Try this.
$scope.$watch('firstnumber', function(newValue, oldValue) {
var sum=cmModalService.getSum();
if(newValue!=null)
{ $scope.secondnumber = sum -$scope.firstnumber;
}
});
$scope.$watch('secondnumber', function(newValue, oldValue) {
var sum=cmModalService.getSum();
if(newValue!=null)
{ $scope.firstnumber = sum - $scope.secondnumber;
}
});
Working Plunkr
EDIT
With some new information you provided, is this what you're after? http://jsfiddle.net/37gv1kbe/
var app = angular.module('myApp',[]);
app.controller('MyController', function($scope,cmModalService)
{
$scope.firstnumber = 5;
$scope.secondnumber = 10;
$scope.$watch('firstnumber', function()
{
$scope.total = cmModalService.getSum() - $scope.firstnumber
});
$scope.$watch('secondnumber', function()
{
$scope.total = cmModalService.getSum() - $scope.secondnumber;
});
});
app.controller('MySecondController', function($scope,cmModalService)
{
$scope.rand = Math.round(Math.random() * 100);
cmModalService.setSum($scope.rand);
});
app.service('cmModalService', function()
{
var sum;
return {
getSum: function()
{
return sum;
},
setSum: function(value)
{
sum = value;
}
}
});
ORIGINAL ANSWER
regarding my comment, if you need to access the total in your controller, you can just save the val of firstnumber and secondnumber like so
http://jsfiddle.net/pvqm4tcw/
var app = angular.module('myApp',[]);
app.controller('MyController', function($scope)
{
$scope.firstnumber = 5;
$scope.secondnumber = 10;
$scope.$watch('firstnumber', function()
{
$scope.total = $scope.firstnumber + $scope.secondnumber;
});
$scope.$watch('secondnumber', function()
{
$scope.total = $scope.firstnumber + $scope.secondnumber;
});
});
html:
<body ng-app="myApp">
<div ng-controller="MyController">
<input type="number" ng-model="firstnumber" />
<br>
<input type="number" ng-model="secondnumber"/>
<br>
{{total}}
</div>
</body>
If you're using Angular 1.3+ they have a $watchGroup which can make the code even smaller
var app = angular.module('myApp',[]);
app.controller('MyController', function($scope)
{
$scope.firstnumber = 5;
$scope.secondnumber = 10;
$scope.$watchGroup(['firstnumber','secondnumber'], function()
{
$scope.total = $scope.firstnumber + $scope.secondnumber;
});
});

Alert() twice in simple angular app

Alert function is firing off twice, I can't figure out why: http://jsfiddle.net/ntzLrkmz/2/
It's going to alert when a !number is inserted at <input type="number">
EDIT: thanks all, I'll be playing with this useful information
This happens because angular evals the list when the times variable change and $diggest to build the ng-reapeat with the new value. You should use $watch instead:
angular.module('helloApp', [])
.controller('helloController', ['$scope', function ($scope) {
$scope.times = 1;
$scope.$watch('times', function (newValue, oldVaue) {
if (!angular.isNumber(newValue)) {
$scope.times = oldVaue;
alert('ENTER A VALID POSITIVE NUMBER PLEASE');
}
});
$scope.getTimes = function (n) {
if (angular.isNumber(n)) {
return new Array(n);
}
};
}]);
Working example here: http://jsfiddle.net/fals/75uv4ugb/
By restructuring your logic and a slight change to your ng-repeat you can solve this issue:
DEMO EXAMPLE
HTML:
<p ng-repeat="obj in array track by $index" ng-show="name.length">Welcome {{name}} !</p>
JS:
angular.module('helloApp', [])
.controller('helloController', ['$scope', function ($scope) {
$scope.array = [];
$scope.populateArray = function (n, t) {
$scope.array = [];
if (t > 0) {
for (i = 0; i < t; i++) {
$scope.array.push(n);
}
}
}
}]);

While lower than value

Say I have a variable x with a value of 7, I need to echo out this html
{{y}}
Where y is 1,2,3... until y == x. How do I do this in Angular?
Using this answer you can create a filter which does this for you:
HTML
<div ng-app='myApp' ng-controller="Main">
{{y}}
</div>
Controller
var myApp = angular.module('myApp', []);
function Main($scope){
$scope.range = function(min, max){
var input = [];
for (var i=min; i<=max; i++) input.push(i);
return input;
};
};
JSFiddle

Resources