Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating duration inputs (mm:ss:ms) in an AngularJS directive

I have a form where I need users to input a time duration, in the resource this is saved as minutes (or milliseconds, easy change). I need the directive to take the second/millisecond value then create 3 separate inputs for the minutes, seconds & milliseconds.

Users can then modify each of the components and the directive will then update the model with the seconds/millisecond value of the 3 components.

I seem to be able to take the model value, create the 3 inputs and using moment.js create the separate components of time.

Directive

angular.module('myExampleApp')
  .directive('lapTimeInput', function () {
     var tpl = '<div class="lap_time_input"> \
              <input ng-model="lap_time.minutes" type="number" class="minutes" placeholder="00" min="0" max="15" step="1"> \
            <span class="lap-time-sep">:</span> \
            <input ng-model="lap_time.seconds" type="number" class="seconds" placeholder="00" min="0" max="59" step="1"> \
            <span class="lap-time-sep">.</span> \
            <input ng-model="lap_time.milliseconds" type="number" class="milliseconds" placeholder="000" min="0" max="999" step="1"> \
            </div>';

    return {
        restrict: 'A',
        template: tpl,
        replace: true,
        require: 'ngModel',
        scope: {
        },
        link: function (scope, element, attrs, ngModel) {

            if (!ngModel) return;

            scope.$watch(function () {
                return ngModel.$modelValue;
             }, function(newValue) {
                // Using moment.js to extract min, sec & ms parts
                var duration = moment.duration(newValue, 'seconds');
                scope.lap_time = {
                    minutes: duration.minutes(),
                    seconds: duration.seconds(),
                    milliseconds: duration.milliseconds()
                }
             });
        }
    };
  });

Controller

$scope.lap = Lap.get({ id: 1 }); // $resource contains .lap_time property
// OR
$scope.lap = {
    lap_time: 90.999
}

HTML

<input type="text" lap-time-input ng-model="lap.lap_time" />

This Plunker will hopefully be a bit clearer

http://plnkr.co/edit/xmNtlItembSUFFZzaT9n?p=preview

Now I'm not even sure I've gone down the right path with using $watch on ngModel, I would guess not. As I understand it I need the directive to do 3 things:

  • Replace the element with 3 separate inputs for minutes, seconds and milliseconds
  • Show the model value to the user in the created inputs using the created inputs
  • When the user changes any of the 3 inputs, it updates the model value turning the 3 separate values back into seconds/milliseconds

Even just a nudge in the right direction would be a great help

like image 258
Sajax Avatar asked Nov 01 '22 04:11

Sajax


1 Answers

This is what I managed to come up with. Not exact answer but should help you on your way.

Template

Updated the template and passed in the lap time as an attribute to be retrieved via the directive scope (see directive section)

 <div lap-time-input="lap.lap_time"></div>

Controller

angular.module('myExampleApp')
    .controller('myExampleCtrl', function ($scope) {

        // This would usually be a $resouce return via a serice
        $scope.lap = {
            lap_time: 90.999
        };

        // watch value of lap time change here when you update minute/second/millisecond
        $scope.$watch('lap.lap_time', function (newLapTime) {
            console.log('newLapTime', newLapTime);
        });
});

Directive

Added the second/milliseconds input field to the template. You probably don't need it, but I put it there for visual/debug reason.

angular.module('myExampleApp')
    .directive('lapTimeInput', function () {
    var tpl = '<div class="lap_time_input"> \
              <input ng-model="lapTimeInput" type="number" placeholder="00.00"> \
              <input ng-model="lap_time.minutes" type="number" class="minutes" placeholder="00" min="0" max="15" step="1"> \
            <span class="lap-time-sep">:</span> \
            <input ng-model="lap_time.seconds" type="number" class="seconds" placeholder="00" min="0" max="59" step="1"> \
            <span class="lap-time-sep">.</span> \
            <input ng-model="lap_time.milliseconds" type="number" class="milliseconds" placeholder="000" min="0" max="999" step="1"> \
            </div>';

    return {
        restrict: 'A',
        template: tpl,
        replace: true,
        scope: {
            lapTimeInput: '='
        },
        link: function (scope) {

            // watch for changes in lapTimeInput and update the lap_time model/object
            scope.$watch('lapTimeInput', function (newValue) {
                var duration = moment.duration(newValue, 'seconds');
                scope.lap_time = {
                    minutes: duration.minutes(),
                    seconds: duration.seconds(),
                    milliseconds: duration.milliseconds()
                }
            });

            // watch for changes in the lap_time model/object
            scope.$watchCollection('lap_time', function (newTime, oldTime) {
                console.log(newTime);
                // convert back to lap time with momentjs here
                scope.lapTimeInput = moment.duration(newTime, 'seconds').asSeconds();

            });
        }
    };
});

JSFIDDLE

like image 132
dcodesmith Avatar answered Nov 12 '22 09:11

dcodesmith