1

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.

6
  • 1
    Please include the relevant parts of the code into your question instead of just providing a plunker link. That way your question stays valid even if the plunker link is dead Commented Jun 17, 2015 at 9:45
  • After updating the value in the controller, have you tried calling scope.$apply(); ? Im no Angular wizard, but I found that to work for me when updating values in a directive and the results not updating in the UI. Commented Jun 17, 2015 at 9:51
  • @LouisLewis where in the code would that $apply go? Commented Jun 17, 2015 at 9:53
  • 1
    Can I suggest this link for a possible better explanation than I could offer. alexperry.io/angularjs/2014/12/10/… Commented Jun 17, 2015 at 10:04
  • You will see he is using setViewValue() and calling render(), I believe that render and apply eventually both will cause a digest to occur, which would update the value. As I said, I am no Angular wizard, just going from what I have battled with. Commented Jun 17, 2015 at 10:06

1 Answer 1

1

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()));
    });
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.