Search code examples
javascriptangularjsangular-directiveangular-filters

Correcting users input in angularJS


I'm trying to create a filter that converts time to seconds, for example: 01:30:10 to 5410 and the other way around so in the end I only have seconds in my model, and the user gets to see a better representation.

So far I managed to create a working example using a directive, however now I want to try to correct typing errors, specifically this kind of error: user types 1:62:30 should be corrected to 2:02:30, the same with seconds.

The problem is that it seems like it doesn't update the view, but the model does get updated.

This is a simplified version of the code:

app.directive('timeFormatter', ['$filter', function($filter) {
    return {
        restrict: "A",
        require: 'ngModel',
        link: function(scope, element, attrs, ngModelController) {

            ngModelController.$parsers.push(function(formattedTime) {
                // here i return a Number usgin math and RegEx
            });

            ngModelController.$formatters.push(function(fullSeconds) {
                // here i return a String formatted like this:
                // return `${hours}:${minutes}:${seconds}`;
            });
        }
    };
}]);

here's the html:

<input class="small" type="text" time-formatter ng-model="answer.end">

And here there's a working fiddle: https://jsfiddle.net/shock/2ju3hfqu/2/


Solution

  • As you want to update the elements value inside directive, you can use element.val()

    you can check this eddited fiddle. as you type more than 60mins it will automagically change to proper minutes. you can do also with the hours and seconds if you want.

    See my logic below this is just a sample and you can change it if you want. I'm just giving you an idea bro

    --UPDATE-- added seconds will auto convert too like minutes --UPDATE-- can convert hundreds not only 2 digits

    app.directive('timeConverter', ['$filter', function($filter) {
    return {
    require: 'ngModel',
    link: function(scope, element, attrs, ngModelController) {
      ngModelController.$parsers.push(function(formattedTime) {
        let re = /^(?:(?:(?:(\d+):)?(\d{1,3})):)?(\d{1,3})$/,
            timeArray = re.exec(formattedTime),
            // Set some default if a number is not found it will be equal to undefined.
          hours = Number(timeArray[1]) || 0,
          minutes = Number(timeArray[2]) || 0,
          seconds = Number(timeArray[3]) || 0;
         hr = 0;
         mn = 0;
         console.log(hours,minutes,seconds);
         if(minutes >= 60 || seconds >= 60){
                hr = Math.floor(minutes / 60);
            mn = Math.floor(seconds / 60);
            if(hr >= 1 || mn >= 1){
                remMin = minutes % 60;
              remSec = seconds % 60;
              remSec = (remSec < 10)?'0'+remSec:remSec;
              newMin = mn+remMin;
              newMin = (newMin < 10)?'0'+newMin:newMin;
              newHour = hr+hours;
              newHour = (newHour < 10)?'0'+newHour:newHour;
              chngeFrmat = [newHour,newMin,remSec];
              console.log(chngeFrmat.join(':'));
              element.val(chngeFrmat.join(':'));
            }
         }
                console.log(minutes);
        console.log(timeArray);
    
        // Basic math, i use the brakets because its easier to read... dont judge.
        return ((hours * 60) * 60) + (minutes * 60) + seconds;
      });
    
      ngModelController.$formatters.push(function(fullSeconds) {
        let hours = Math.floor(fullSeconds / 60 /60),
          minutes = Math.floor(fullSeconds / 60) % 60,
          seconds = Math.floor(fullSeconds % 60);
          return `${hours}:${minutes}:${seconds}`;
            });
        }
    };
    }]);