Reputation: 1019
I am getting an integer, representing a duration in minutes, but if larger than a specific value, I would like to display it as hours, or as days, but I would still like to keep the ng-model value in minutes, so if the user makes any change to the value, and my app reads it back, it should be in minutes.
For example: If I read '480 minutes', the display should say 8 (hours). If I read '1440 minutes', it should be 1 (day). If the user changes that to 0.5 (day), then the value in ng-model should be 720.
I would like to keep the number part in an input, while the measurement unit (minutes/hours/days) in a label on the right of the input.
I created a 'duration' filter that looks like this:
myApp.filter('duration', function() {
//Returns duration from minutes in hours
return function(minutes) {
var hours = Math.floor(minutes / 60);
return hours;
}
});
However, when I add it to the following element
...list iteration through fields, where textField is the current iteration object
<input type="number" class="text-input" ng-model="textField.CustomFieldValue | duration">
it shows an error message in the console:
[ngModel:nonassign] Expression 'textField.CustomFieldValue | duration' is non-assignable. Element: <input type="number" class="text-input ng-pristine ng-untouched ng-valid" ng-model="textField.CustomFieldValue | duration">
I know my filter is not correct (yet), but I just used it for a little testing.
I am not really that familiar with AngularJS, so I might be using the filter in a wrong way.
The filter IS working, however, so on a value of 480, I do get 8 hours displayed, but I am concerned about the error message in the console.
Upvotes: 2
Views: 2684
Reputation: 56600
I don't think attaching the filter
in the ng-model
is a good idea! It will give you a max-digest
error mostly. Here is my solution to this, Implement ng-model formatters and parsers
, Here is awesome article to get you started on this!
Basically for my solution, I create new directives which will implement the logic for hours
and days
, the formatters does the logic and the parser reverses the logic, else the ng-model
will loose the original value. Check my below snippet!
var app = angular.module('myApp', []);
app.controller('MyController', function MyController($scope) {
$scope.textField = 480;
});
app.directive('timeParser', function() {
return {
restrict: 'A',
require: 'ngModel',
scope: {
timeParser: "@"
},
link: function(scope, element, attr, ngModel) {
ngModel.$formatters.push(function(minutes) {
if (scope.timeParser === "hours") {
return Math.floor(minutes / 60);
} else if (scope.timeParser === "days") {
return Math.floor(minutes / (60 * 24));
} else {
return minutes;
}
});
ngModel.$parsers.push(function(minutes) {
if (scope.timeParser === "hours") {
return Math.floor(minutes * 60);
} else if (scope.timeParser === "days") {
return Math.floor(minutes * (60 * 24));
} else {
return minutes;
}
});
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller='MyController' ng-app="myApp">
Minutes
<input type="number" class="text-input" ng-model="textField">
<br> Hours
<input type="number" class="text-input" ng-model="textField" time-parser="hours">
<br> Days
<input type="number" class="text-input" ng-model="textField" time-parser="days">
</div>
Upvotes: 3