最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - AngularJs - Directive to modify input formatting - Stack Overflow

programmeradmin6浏览0评论

I want to do the following:

I have a date object in my controller model and I want to let the user modify it. The user should be given two input fields. The first Input field should modify the date, the other the time. Both input field should work on the same date model.

<input ng-model="model.date" date-format="YYYY-MM-DD">
<input ng-model="model.date" date-format="HH:mm:SS">

I didn't find literature about this binding. Normally the ng-model directive takes care of the value of the input field. Now I want to overwrite this value with my own formatting. Also, if the user changes the input, the changes should be parsed and put back into the date object.

As date manipulation in vanilla js is kind of weird, I used moment.js to format and parse the dates and strings.

My current approach looks like this:

app.directive('dateFormat', function() {
    return {
        restrict: 'A',
        link: function(scope, el, at) {
            var format = at.dateFormat;
            scope.$watch(at.ngModel, function(date) {
                var result = moment(date).format(format);
                el.val(result);
            });
        }
    };
});

However this will break as soon as I want to change the input value in the browser. I get some NaN:NaN...

My questions are:

  • How can I model this?
  • Is this approach valid with the angular philosophy or am I doing something weird here?
  • Can I use ng-model and my date-format directive together?
  • Is there an easier way to do this?

I want to do the following:

I have a date object in my controller model and I want to let the user modify it. The user should be given two input fields. The first Input field should modify the date, the other the time. Both input field should work on the same date model.

<input ng-model="model.date" date-format="YYYY-MM-DD">
<input ng-model="model.date" date-format="HH:mm:SS">

I didn't find literature about this binding. Normally the ng-model directive takes care of the value of the input field. Now I want to overwrite this value with my own formatting. Also, if the user changes the input, the changes should be parsed and put back into the date object.

As date manipulation in vanilla js is kind of weird, I used moment.js to format and parse the dates and strings.

My current approach looks like this:

app.directive('dateFormat', function() {
    return {
        restrict: 'A',
        link: function(scope, el, at) {
            var format = at.dateFormat;
            scope.$watch(at.ngModel, function(date) {
                var result = moment(date).format(format);
                el.val(result);
            });
        }
    };
});

However this will break as soon as I want to change the input value in the browser. I get some NaN:NaN...

My questions are:

  • How can I model this?
  • Is this approach valid with the angular philosophy or am I doing something weird here?
  • Can I use ng-model and my date-format directive together?
  • Is there an easier way to do this?
Share Improve this question asked Sep 12, 2013 at 15:42 user524824user524824 1
  • So, did you ever find a good solution to this? :) I'm in a similar position where I want to keep the model property as a Date object but still allow the user to edit it in an edit field with a date mask applied. – Lasse Christiansen Commented Nov 16, 2014 at 21:00
Add a comment  | 

2 Answers 2

Reset to default 16

A filter is what you are looking for:

//In your controller
$scope.modelDate = $filter('date')(dateToFormat, "YYYY-MM-DD");

//In your view
<input ng-model="modelDate" type="text">

That being said, what you are trying to do was not too "off", because whenever the user writes to the input, the formatting will break. You need to use ngModel, which has a special way to work with Directives (an API) and can be browsed directly as a fourth argument in the linking process.

So for your code it would be something like this:

return {
  require: 'ngModel',
  link: function(scope, element, attrs, ngModelController) {
    ngModelController.$parsers.push(function(data) {
      //View -> Model
      return data;
    });
    ngModelController.$formatters.push(function(data) {
      //Model -> View
      return $filter('date')(data, "YYYY-MM-DD");
    });
  }
}

More information here

I had the same problem, and after some research and testing, I've come up with the following solution. It performs the desired formatting and validation on 'blur' not during every keystroke. Look at the comment tags for info on each step. You will need moment.js to perform the validation of dates.

myApp.directive('validDate', function ($filter, $window, $parse, $timeout) {
return {
    require: '?ngModel',
    restrict: 'A',
    compile: function () {
        var moment = $window.moment;
        var getter, setter;
        return function (scope, element, attrs, ngModel) {
            //Declaring the getter and setter
            getter = $parse(attrs.ngModel);
            setter = getter.assign;
            //Set the initial value to the View and the Model
            ngModel.$formatters.unshift(function (modelValue) {
                if (!modelValue) return "";
                var retVal = $filter('date')(modelValue, "MM/dd/yyyy");
                setter(scope, retVal);
                console.log('Set initial View/Model value from: ' + modelValue + ' to ' + retVal);
                return retVal;
            });

            // If the ngModel directive is used, then set the initial value and keep it in sync
            if (ngModel) {
                element.on('blur', function (event) {
                    var date = moment($filter('date')(element.val(), "MM/dd/yyyy"));
                    // if the date entered is a valid date then save the value
                    if (date && moment(element.val(), "MM/DD/YYYY").isValid() && date <= moment() && date >= moment("01/01/1900")) {
                        element.css('background', 'white');
                        element[0].value = $filter('date')(date.toDate(), "MM/dd/yyyy");
                        console.log('change value to ' + element.val());
                        var newValue = element.val();
                        scope.$apply(function () {
                            setter(scope, newValue);
                        });
                    } else { //show an error and clear the value
                        console.log('INCORRECT VALUE ENTERED');
                        element.css('background', 'pink');
                        element[0].value = "";
                        scope.$apply(function () {
                            setter(scope, '');
                        });
                    }
                });
             }
         };
      }
  }; });

And the directive can be used in the View like the following:

<input type="text" ng-model="member.BirthDate" required valid-date />
发布评论

评论列表(0)

  1. 暂无评论