在AngularJS指令

时间:2015-05-15 10:47:45

标签: javascript angularjs angular-directive

我有一个表单,我需要用户输入一个持续时间,在资源中这被保存为分钟(或毫秒,易于更改)。我需要指令取第二个/毫秒值,然后为分钟,秒和时间创建3个单独的输入。毫秒。

然后,用户可以修改每个组件,然后该指令将使用3个组件的秒/毫秒值更新模型。

我似乎能够获取模型值,创建3个输入并使用moment.js创建单独的时间组件。

指令

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

控制器

$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" />

这个Plunker希望有点清楚

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

现在我甚至不确定我是否已经使用$ watch on ngModel走上了正确的道路,我猜不会。据我所知,我需要指令做三件事:

  • 使用3个单独的输入替换元素,分钟,秒和毫秒
  • 使用创建的输入
  • 在创建的输入中向用户显示模型值
  • 当用户更改3个输入中的任何一个时,它会更新模型值,将3个单独的值重新设置为秒/毫秒

即使只是朝着正确的方向轻推,也会有很大的帮助

2 个答案:

答案 0 :(得分:1)

这是我设法提出的。不是确切的答案,但应该帮助你。

<强>模板

更新了模板并将单圈时间作为要通过指令范围检索的属性传递(参见指令部分)

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

<强>控制器

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

<强>指令

在模板中添加了第二个/毫秒输入字段。你可能不需要它,但我把它放在那里是出于视觉/调试的原因。

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

答案 1 :(得分:1)

好的,我已经设法使用ngModel执行此操作而不向控制器添加任何代码,因为我需要在多个位置使用此指令。我也能够进行验证标记。

angular.module('exampleApp')
.directive('lapTimeInput', function () {
 var tpl = '<div class="lap-time-input"> \
        <div class="input-group"> \
          <span class="input-group-addon"><label for="laps">Lap Time</label></span> \
          <input ng-model="lap_time.minutes" type="number" class="form-control minutes" name="minutes" placeholder="00" min="0" max="15" step="1"> \
        </div> \
        <span class="form-control lap-time-sep">:</span> \
        <input ng-model="lap_time.seconds" type="number" class="form-control seconds" placeholder="00" min="0" max="59" step="1"> \
        <span class="form-control lap-time-sep">.</span> \
        <input ng-model="lap_time.milliseconds" type="number" class="form-control milliseconds" placeholder="000" min="0" max="999" step="1"> \
      </div>';

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

                if (!ngModel) return;

                ngModel.$formatters.unshift(function(modelValue) {
                    if(!modelValue) return;

                    var duration = moment.duration(parseInt(modelValue));
                    return {
                        minutes: duration.minutes(),
                        seconds: duration.seconds(),
                        milliseconds: duration.milliseconds()
                    };
                });

                ngModel.$render = function() {
                    scope.lap_time = ngModel.$viewValue
                };

                ngModel.$parsers.unshift(function(modelVal) {           
                    var duration = moment.duration(scope.lap_time);

                  return duration.asMilliseconds();
                });

                ngModel.$validators.check = function(modelValue, viewValue) {           
                    if(viewValue) {
                        if(viewValue.minutes === undefined || viewValue.minutes > 15) {
                            return false;
                        }
                        if(viewValue.seconds === undefined || viewValue.seconds > 59) {
                            return false;
                        }
                        if(viewValue.milliseconds === undefined || viewValue.milliseconds > 999) {
                            return false;
                        }
                    }
                    return true;
                };

                scope.$watchCollection('lap_time', function(newVal) {
                  ngModel.$setViewValue(newVal);
                });

    }
  };
});

如果我在这里有问题,我当然欢迎反馈。