Kees de Kooter
Kees de Kooter

Reputation: 7195

Custom directive using ngModelController not updating UI value

I am trying to create a directive that formats a decimal value to a time value h:mm. If a user enters a time value the model should be updated with the decimal representation. If a user enters a decimal value his input should be replaced with the formatted value.

I am using the directive as follows:

<input type="text" hour-input ng-model="vm.hours"/>

Here is the relevant code:

app.directive('hourInput', hourInput);

function hourInput() {
  var directive = {
    link: link,
    restrict: 'A',
    require: 'ngModel'
  };

  return directive;

  function link(scope, element, attrs, ngModelController) {
    // model -> view
    ngModelController.$formatters.push(function (value) {
      return formatTime(value);
    });

    // view -> model
    ngModelController.$parsers.push(function (value) {
      var result;
      if (!/^\d?[\d,\.]*$/.test(value)) {
        result = parseTime(value);
      } else {
        result = parseFloat(value);
      }
      return result;
    });
  }
}

function parseTime(value) {
  // code removed for brevity
  return hours + minutes / 60;
}

function formatTime(value) {
  // code removed for brevity
  return result;
}

Here is the plunker. The interaction with the model is working. However the formatted time is not updated in the UI.

Upvotes: 1

Views: 120

Answers (1)

Andre Paap
Andre Paap

Reputation: 751

ngModelController.$parsers parses your value with every keystroke. Since you do not know when the user is ready with entering the value, you can't really parse the value on every update. Assuming you want to allow the values

  • 5
  • 5.
  • 5.5
  • 5:30

the parser is not the way you want to go. I think that when you attach the function on the blur or change event you get the desired behavior.

Something like

element.bind('blur', function () {
      element.val(formatTime(element.val()));
    });

Upvotes: 1

Related Questions