1
votes

I'm new to angular and have been having issues getting a datepicker directive working. The jsFiddle at http://jsfiddle.net/jGU95/9/ illustrates some of the problems I haven't been able to overcome.

The form is very simple:

<div ng-app="myApp" ng-controller="Ctrl">
    <br>
    Date 1
    <input type="text" datepicker1={{pickeropts}} ng-model="date1" /> {{date1 | date:MM/dd/yyyy}}
    <br>
    Date 2
    <input type="text" datepicker2={{pickeropts}} ng-model="date2" /> {{date2 | date:MM/dd/yyyy}}
    <br>
    Date 3
    <input type="text" datepicker1 data-date-format="{{format}}" ng-model="date3" /> {{date3 | date:MM/dd/yyyy}}        
</div>

The datepicker1 directive's original rendering of the date is in the wrong format and the actual date picker is not tied to the date, i.e., when the Date 1 text field is selected, the datepicker is launched with today's date instead of the date from 1975. Once a date is selected from the datepicker, the control behaves as expected, including displaying the output date string in the proper format.

Here is the datepicker1 directive:

.directive('datepicker1', function(){
    return {
        require: '?ngModel',
        link: function($scope, element, attrs, controller) {
            var originalRender;
            var updateModel = function(ev) {
                return $scope.$apply(function() {
                    return controller.$setViewValue(ev.date);
                });
            };
            if (controller != null) {
                originalRender = controller.$render;
                controller.$render = function() {
                    originalRender();
                    return element.datepicker.ddate = controller.$viewValue;
                };
            }
            return attrs.$observe('datepicker1', function(value) {
                var options;
                options = {};
                if (angular.isObject(value)) {
                    options = value;
                }
                if (typeof(value) === "string" && value.length > 0) {
                    options = angular.fromJson(value);
                }
                return element.datepicker(options).on('changeDate', updateModel);
            });
        }
    };
})

datepicker2 also has an issue with the original rendering of the date, and also ignores the specified format options. This appears to be caused by the instantiation of the datepicker element in the controller.$render function, which occurs before the attrs.$observe function.

Here is the datepicker2 directive

.directive('datepicker2', function(){
    return {
        require: '?ngModel',
        link: function($scope, element, attrs, controller) {
            var updateModel = function(ev) {
                return $scope.$apply(function() {
                    return controller.$setViewValue(ev.date);
                });
            };
            if (controller !== null) {
                controller.$render = function() {
                    element.datepicker().data().datepicker.date = controller.$viewValue;
                    element.datepicker('setValue');
                    element.datepicker('update');
                    return controller.$viewValue;
                };
            }
            return attrs.$observe('datepicker2', function(value) {
                var options;
                options = {};
                if (angular.isObject(value)) {
                    options = value;
                }
                if (typeof(value) === "string" && value.length > 0) {
                    options = angular.fromJson(value);
                }
                return element.datepicker(options).on('changeDate', updateModel);
            });
        }
    };
});

Finally, the datepicker for Date 3 isn't functional because the $scope.format value is not being properly interpolated into a string prior to being sent to the datepicker.

Please help me figure out how to fix any of these...

Steve

1

1 Answers

1
votes

If you are not familiar with it yet, I would have a look into the angularjs concept of 'isolate scope'. This makes a fresh scope for your directive, preventing messing with the 'global' scope. It also allows binding to your attribute values either as strings, bi-directional binding or expressions.

the official doc, search for 'isolate'. Your eyes might glaze over: http://docs.angularjs.org/guide/directive

a better explanation: http://onehungrymind.com/angularjs-sticky-notes-pt-2-isolated-scope/

And for some video action, check out the 5 short and clear explanation videos at egghead.io (start with video nr 16). I would have included the link but my StackOverflow reputation isn't high enough yet.