4

I need a directive which will parse user input to date and validate it. So I wrote the following:

myDirectives.directive('myDate', function($filter) {
    'use strict';
    return {
        require:'ngModel',
        restrict:'A',
        link:function (scope, elem, attrs, ctrl) {
            var dateFormat = attrs.myDate ? attrs.myDate : 'shortDate';

            ctrl.$formatters.unshift(function(modelValue) {
                return $filter('date')(modelValue, dateFormat);
            });
            ctrl.$parsers.unshift(function(viewValue) {
                var date = new Date(viewValue);

                if (isNaN(date)) {
                    ctrl.$setValidity('date', false);
                    return undefined;
                } else {
                    var dateString = $filter('date')(date, dateFormat);
                    if (dateString !== viewValue) {
                        ctrl.$setViewValue(dateString);
                    }
                    ctrl.$setValidity('date', true);
                    return date;
                }
            });
        }
    };
});

Parsing need to occur only after when input loses focus, so I use another directive, which I found here. The problem is

ctrl.$setViewValue(dateString);

won't work, because as indicated in angularjs documentation, setViewValue() must be called from within a DOM event handler. What should I do to reflect back parsing result?

4 Answers 4

2

Instead of

ctrl.$setViewValue(dateString);

I needed to write

elem.val(dateString);

and the problem was solved. So, my directive now looks like below:

myDirectives.directive('myDate', function ($filter) {
    'use strict';
    return {
        require: 'ngModel',
        restrict: 'A',
        link: function (scope, elem, attrs, ctrl) {
            var dateFormat = attrs.myDate ? attrs.myDate : 'shortDate';
            ctrl.$formatters.unshift(function (modelValue) {
                return (modelValue) ? $filter('date')(modelValue, dateFormat) : '';
            });
            ctrl.$parsers.unshift(function (viewValue) {
                var date = new Date(viewValue);
                if (isNaN(date)) {
                    ctrl.$setValidity('date', false);
                    return undefined;
                } else {
                    var dateString = $filter('date')(date, dateFormat);
                    if (dateString !== viewValue) {
                        elem.val(dateString);
                    }
                    ctrl.$setValidity('date', true);
                    return date;
                }
            });
            elem.unbind('input').unbind('keydown').unbind('change');
            elem.bind('blur', function () {
                scope.$apply(function () {
                    ctrl.$setViewValue(elem.val()); //this method name is misleading; 
                                                    //it actually sets model value?!
                });
            });
        }
    };
});

Note, that I incorporated the code from another directive which was responsible for pushing view value to model, when focus is lost.

Sign up to request clarification or add additional context in comments.

1 Comment

Just to comment on your comment in the last row, the $setViewValue() function does indeed do that: setting the view value, after which it proceeds to call all the registered $parsers in the pipeline to end up with the model value which is then set in the model linked by the ngModel attribute.
2

I've created a date parser that converts string to Date objects. You can also provide date formats you're using, as well as your date locale. It returns a Date object, valid or otherwise depending on the input.

There's also a directive that implements this parser so you can use it on an input field, for example.

https://github.com/dnasir/angular-dateParser

Comments

0

This should work:

var setter = $parse('ngModel').assign;
setter($scope,valueToSet);
$scope.$apply() // This may be needed depending on where its done.

Refenece: http://docs.angularjs.org/api/ng.$parse

1 Comment

There's a typo: $prase -> $parse. Even then, it doesn't solve the problem.
-1

on html:

<input class="form-control""
type="date"
string-to-date
ng-model="val.VAL">

On Controller create a directive

.directive('stringToDate', function() {
    return {
      require: 'ngModel',
      link: function(scope, element, attrs, ngModel) {
        ngModel.$parsers.push(function(value) {
          return new Date(value);
        });
        ngModel.$formatters.push(function(value) {
          var fechaactual = new Date(value);
          return fechaactual;
        });
      }
    };
  })

note that the directive call stringToDate and you have to call it as string-to-date in the html. Dont not why :)

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.