Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Values disappearing with AngularJS / UI Bootstrap custom $validator and getterSetter

My goal is to create a UI Bootstrap datepicker that also has an input mask.

The datepicker directive only validates dates chosen with the popup window and not dates the user would type in by hand, so I looked up how to add custom validation for the text input.

I have all of this working in this Plunk.

Here are the important bits:

<!-- HTML -->
<span>Errors: {{myForm.myDate.$error}}</span>
<input 
    name="myDate"
    type="text" 
    class="form-control" 
    ng-class="{error: myForm.myDate.$invalid && myForm.myDate.$dirty}"
    datepicker-popup="MM/dd/yyyy" 
    ng-model="dt" 
    is-open="opened" 
    min-date="'09/01/2015'" 
    max-date="'11/11/2015'" 
    ng-required="true" 
    show-weeks="false"
    show-button-bar="false" />


// JavaScript
.controller('DatepickerDemoCtrl', function ($scope) {
  $scope.dt = undefined;

  $scope.open = function($event) {
    $scope.opened = !$scope.opened;
  };

  $scope.today = new Date();
})

.config(function($provide) {
  $provide.decorator('datepickerPopupDirective', function($delegate) {
    var directive = $delegate[0];
    var link = directive.link;

    directive.compile = function() {
      return function(scope, iEl, iAttrs, ctrls) {
        link.apply(this, arguments);

        // use custom validator to enforce date range on hand-entered text
        ctrls[0].$validators.inDateRange = function(modelValue, viewValue) {
          console.log(modelValue, viewValue);

          // use the ranges provided in the attributes for the validation
          var enteredDate = new Date(viewValue)
          ,   min = new Date(iAttrs.minDate)
          ,   max = new Date(iAttrs.maxDate);

          return ctrls[0].$isEmpty(modelValue) 
                 || (min <= enteredDate && enteredDate <= max);
        };

        // apply input mask to the text field
        iEl.mask('99/99/9999');
      };
    };

    return $delegate;
  });  
});

Now I want to do something simple, which is add a getterSetter to my input so I can do some work on the value before persisting it to the model.

I change the ng-model on my element, add ng-model-options to reference my getterSetter, and add the actual getterSetter method.

<!-- HTML -->
ng-model="getSetDate" 
ng-model-options="{getterSetter: true}"

// JavaScript
$scope.getSetDate = function(val) {
  if(angular.isDefined(val)) {
    $scope.dt = val;
  } else {
    return val;
  }
};

However, even this simple Plunk with getterSetter, which essentially does nothing introduces an error. If I:

  1. Type in an invalid day, say 09/10/2011
  2. Correct it to a valid day (by typing), say 09/10/2015
  3. The value disappears

I can't figure out why the introduction of this simple getterSetter is causing my value to be lost. Should I be implementing this in a different way?

like image 210
diplosaurus Avatar asked Nov 10 '22 01:11

diplosaurus


1 Answers

It looks like ng-model-options including the getterSetter option is not actually supported yet in the date picker, but is something they wish to implement.

https://github.com/angular-ui/bootstrap/issues/4837

edit: Also, I created a plunk that updates a secondary model through watching. I'm not sure if it is what you are looking for exactly, but seems to do a similar thing that you were attempting through the getterSetter. Essentially the following added to your working example.

  $scope.dt = undefined;
  $scope.newdt = undefined;

  $scope.$watch('dt', function(){
    if ($scope.dt) 
      $scope.newdt = $scope.dt;
  });
like image 156
Dave Avatar answered Nov 14 '22 21:11

Dave