How to get value when model value lower than ng-min? - angularjs

$scope.total < ng-min, $scope.total is undefined.
But i need to get that value to shown as change.
for example : if change -50, then cashier can easy to talk to customer if he need 50 more.
angular.module('app', [])
.controller('MainCtrl', function($scope) {
$scope.pay = null;
$scope.total = 1000;
$scope.change = 0;
$scope.check = function() {
$scope.change = $scope.pay - $scope.total;
console.log('pay = ' + $scope.pay + ' , total = ' + $scope.total + ' , change = ' + $scope.change);
};
});
<body ng-app="app" ng-controller="MainCtrl">
Total = {{ total }}
<input type="number" ng-model="pay" ng-min="total" ng-change="check()">
Change = {{ change }}
</body>
here my plunkr http://plnkr.co/edit/4C9AuBI4q97VXXvXM59B?p=preview

You don't need to use ng-min at all, because of this directive will pass only correct values, just add a condition to change-function. E.g
if($scope.change < 0){
//do something
}
Also, better to change $scope.pay = null; to $scope.pay = 0; if You want to avoid the type-errors

Related

How to show model and view differently in AngularJS

I am implementing a functionality in AngularJS.
When the user enters 1.5, In view, it should show as 01:30, but when I fetch this scope value in the controller it should return as 1.5.
I have added code in plunker. Please find here.
Index.html:
<!DOCTYPE html>
<html ng-app="wbTimeConverter">
<head>
<link rel="stylesheet" href="style.css">
<script src="https://code.angularjs.org/1.5.8/angular.js"></script>
<script src="script.js"></script>
<script src="wbNumberToTime.js"></script>
</head>
<body ng-controller="AppController">
<h1>Hello Plunker!</h1>
<input type="text" md-maxlength="5" wb-number-to-time-convert ng-model="task" placeholder="task" ng-blur="onDataChange();" />
<input type="text" md-maxlength="5" wb-number-to-time-convert ng-model="project" placeholder="project" ng-blur="onDataChange();" />
<br>
<label>Task : {{task}}</label><br>
<label>Project : {{project}}</label><br>
<label>TotalResult : {{totalHours}}</label>
</body>
</html>
Controller - Script.js
var app = angular.module('wbTimeConverter', []);
app.controller('AppController', function($scope) {
$scope.onDataChange = onDataChange;
function onDataChange(){
console.log("res");
$scope.totalHours= parseFloat($scope.task) + parseFloat($scope.project, 10);
}
});
directive:
// 'use strict';
// /**
// * This directive is convert number into hours and minutes format-HH:MM
// * This will trigger when we change value in input element and gives respective value in time format
// */
app.directive('wbNumberToTimeConvert', function ($filter, $browser) {
return {
require: 'ngModel',
link: function ($scope, $element, $attrs, ngModelCtrl) {
var listener = function () {
var value = $element.val();
var result = convertToTime(value);
$element.val(result.timeFormat);
$element.attr('attr-hrs', result.decimalFormat);
};
// This runs when we update the text field
ngModelCtrl.$parsers.push(function (viewValue) {
return viewValue;
});
$element.bind('change', listener);
$element.bind('keydown', function (event) {
var key = event.keyCode;
// FIXME to handle validations
});
$element.bind('paste cut', function () {
$browser.defer(listener);
});
function convertToTime(value) {
var res = { 'timeFormat': '', 'decimalFormat': '' };
var inputValue = value;
if (inputValue.indexOf(':') > -1) {
inputValue = convertToNumberFormat(inputValue);
res.decimalFormat = inputValue;
} else {
res.decimalFormat = value;
}
inputValue = inputValue.split('.');
var hoursValue = inputValue[0];
if (inputValue.length > 1) {
var hrs = parseInt(hoursValue, 10);
hrs = isNaN(hoursValue) ? 0 : hrs;
hrs = (hrs < 10) ? '0' + hrs : hrs;
var minutesValue = inputValue[1];
var mins = parseInt(minutesValue, 10);
mins = (minutesValue.length < 2 && (mins < 10)) ? Math.round(mins * 6) : Math.round(mins * 0.6);
mins = (mins < 10) ? ('0' + mins) : mins;
inputValue = hrs + ':' + mins;
res.timeFormat = inputValue;
} else {
inputValue = (parseInt(inputValue, 10) < 10) ? '0' + parseInt(inputValue, 10) : parseInt(inputValue, 10);
inputValue = inputValue + ':' + '00';
res.timeFormat = inputValue;
}
return res;
}
function convertToNumberFormat(inputValue) {
var timeValue = inputValue.split(':');
var hours = parseInt(timeValue[0], 10);
var mins = parseInt(timeValue[1], 10);
if (isNaN(hours)){
hours = '00';
}
if (isNaN(mins)) {
mins = '00';
}
mins = Math.round(mins / 0.6);
if (mins < 10) {
mins = '0' + mins;
}
var number = hours + '.' + mins;
return number;
}
}
};
});
Here is the plunker link:
https://plnkr.co/edit/76lwlnQlGC0wfjixicCK?p=preview
On textbox blur, it is working fine of value differ in View and Controller on first time and from second time on blur in textbox, it is showing same value 01:30 in both view and controller. How can I resolve it?
You can keep your input inside the ng-model myValue and call a function format(value) to display what you need
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.myValue = "1.5";
$scope.format = function(value) {
var hrs = parseInt(Number(value));
var min = Math.round((Number(value) - hrs) * 60);
return hrs + ':' + min;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<input type="text" ng-model="myValue">
<br>Formatted Value : {{format(myValue)}}
<br>Base value : {{myValue}}
</div>
It's really easy using a directive! Take this as an example: JSFiddle
If you have a directive that requires ngModelController you can manipulate the viewValue really easily.
ngModelController has two properties that we're interested in, $modelValue and $viewValue. $modelValue is the value that you use on the scope and $viewValue is the one the user sees.
ngModelController also has a property $formatters which is an array of formatters that convert a modelValue to viewValue. So if the modelValue changes on the side of the controller it will go through the formatters until the end, and this will change the viewValue. If you want to create your own formatter, simply add it the array!
//This formatter will convert the modelValue to display as uppercase in the viewValue
ngModelController.$formatters.push(function(modelValue) {
if (modelValue) {
return modelValue.toUpperCase();
}
});
but the $formatters property only works for when the modelValue gets changed, so if the user is typing something into the input field, the viewValue is getting changed, the easiest way to handle this is to attach to the onBlur event in which we will alter the viewValue using another function provided by the ngModel controller. $setViewValue(value) will change the viewValue. If you change the viewValue in the directive, the view won't automatically update, so you need to call the $render function provided by the ngModelController
element.on('blur', function() {
ngModelController.$setViewValue(convertDoubleToTimeString(ngModelController.$modelValue));
ngModelController.$render();
});
For more information about this you can read this.
EDIT:
In this example I haven't written a parser that converts a viewValue (1:30) to a modelValue (1,5). So let's add one. I also have an updated JSFiddle
ngModelController.$parsers.unshift(function(viewValue) {
if (viewValue && viewValue.indexOf(':') < 0) {
return viewValue;
} else {
return convertTimeStringToDouble(viewValue)
}
});
Unshifting the parsers onto the $parsers array means it will be the first one to execute, this isn't really necessary, but why not, eh?
There are other ways of not changing the modelValue when the viewValue changes, but this one is the most correct one.
An alternative would be to just set the $viewValue directly without going through $setViewValue().
//ngModelController.$setViewValue(ngModelController.$modelValue.toUpperCase());
ngModelController.$viewValue = ngModelController.$modelValue.toUpperCase();
In that last line, it wont go through the usual steps of going through all the parsers and validators, so it's the less ideal solution.
You can declare a function in controller to return the calucalted value and in html you can call that function and pass the scope variable.
$scope.calculate = function(value){
var calculatedValue = /*Your operation*/;
return calculatedValue;
}
<input type="text" ng-model="value"\>
<p>{{calculate(value)}}</p>
If you want real time update of the calculated value with respect to the input value then you can use another scope variable to store the calculate value.
$scope.calculate = function(value){
$scope.calculatedValue = /*Your operation*/;
}
<input type="text" ng-model="value" ng-change="calculate(value)"\>
<p>{{calculatedValue}}</p>

Angular - ngOptions model value not updating

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

ng-select with lazy population

It's an edit form with parent record first populated then dependent select list is populated, and then it's expected the value from parent record pre-select the combo box.
html
<select ng-model="data.trackId" >
<option ng-repeat="track in tracks" value="{{track.id}}">{{track.name}}</option>
initial result once parent record is pulled.
if(data) {
this.$scope.data.id = data.id;
this.$scope.data.name = data.name;
this.$scope.data.room = data.room;
this.$scope.data.start = data.start;
this.$scope.data.end = data.end;
this.$scope.data.dayId = data.day_id;
this.$scope.data.trackId = data.track_id;
this.$scope.data.color = data.color;
this.$scope.data.description = data.description;
this.$scope.$apply();
this.$element[0].removeAttribute("style");
}
//later track results were pulled
trackResult: function(data, status, headers, config) {
for(var i=0; i<data.length; i++) {
this.$scope.tracks.push(data[i]);
}
this.$scope.$apply();
},
Problem:
List gets populated from the second call trackResult but default value from the $scope.trackId never sets the combo box to a value.
Edit: Controller Body
controller: function($scope, $element) {
var self = this;
this.$scope = $scope;
this.$element = $element;
this.$scope.data = {};
this.$scope.days = [];
this.$scope.tracks = [];
this.$scope.submit = function() {self.submit()};
this.$scope.cancel = function() {self.cancel()};
},
Edit : Updated with setting the data from outside the scope (OP request)
Use ng-options & ng-model
this is how i think it should be done in angularjs.
use the built in databinding capabilities to simplify your code and make it less complicated
for binding a list into a <select> and controlling the selected item, this snippet below should do the trick.
http://jsfiddle.net/72em40j4/
js
var myapp = angular.module('myapp', []);
myapp.controller('Ctrl', function ($scope) {
$scope.options = [];
$scope.selectedOption = null;
});
html
<script>
function clickFromOutside() {
var controllerElement = document.getElementById('container');
var controllerScope = angular.element(controllerElement).scope();
var firstTrack = {
id: 1,
first: 'First',
last: 'Track'
};
var secondTrack = {
id: 2,
first: 'Second',
last: 'Track'
};
controllerScope.options.push(firstTrack);
controllerScope.options.push(secondTrack);
controllerScope.selectedOption = secondTrack;
controllerScope.$apply();
}
</script>
<button onclick="clickFromOutside();">outside</button>
<div ng-app="myapp">
<fieldset id="container" ng-controller="Ctrl">
<select ng-options="p.first + ' ' + p.last for p in options" ng-model="selectedOption"></select> <pre>{{ selectedOption }}</pre>
</fieldset>
</div>

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;
});
});

AngularJs. Cycle in $scope.$watch

I can't understand whats wrong. I need create array of hours and minutes and show him.
HTML:
<div ng-app="test">
<div ng-controller="timeCtrl" ng-init="opentime='9';closetime='24'">
<div ng-repeat="time in times">
{{time}}
</div>
</div>
</div>
JS:
var app = angular.module('test', []);
app.controller('timeCtrl', ['$scope', function ($scope) {
$scope.$watch('opentime', function () {
$scope.times = [];
for (var hours = $scope.opentime; hours < $scope.closetime; hours++) {
console.log(hours);
for (var minutes = 0; minutes < 4; minutes++) {
var linkMinutes = minutes * 15;
if (linkMinutes === 0) {
linkMinutes = "00";
}
console.log(linkMinutes);
$scope.times.push(hours + ':' + linkMinutes);
}
}
});
}])
Why console.log is empty, but vars opentime and closetime with value?
Fiddle: http://jsfiddle.net/Zoomer/mj8zv2qL/
that because your scope variable opentime never been changed to fire watcher
I'v updated the example and simulated the variable change
scope.$watch will execute only when opentime change value please see more here https://docs.angularjs.org/api/ng/type/$rootScope.Scope
and that demo http://jsfiddle.net/oprhy6te/enter link description here
CTRL:
app.controller('timeCtrl', ['$scope', function ($scope) {
$scope.$watch('opentime', function () {
$scope.updateTimes();
});
$scope.updateTimes = function () {
$scope.times = [];
for (var hours = $scope.opentime; hours < $scope.closetime; hours++) {
console.log(hours);
for (var minutes = 0; minutes < 4; minutes++) {
var linkMinutes = minutes * 15;
if (linkMinutes === 0) {
linkMinutes = "00";
}
console.log(linkMinutes);
$scope.times.push(hours + ':' + linkMinutes);
}
}
}
function activate() {
$scope.opentime = 9;
$scope.closetime = 13;
$scope.updateTimes();
}
activate();
}])
HTML:
<div ng-app="test">
<div ng-controller="timeCtrl">
<input type="text" ng-model="opentime" />
<div ng-repeat="time in times"> {{time}}
</div>
</div>
</div>

Resources