0

I'm using angular js to handle the processing of data on my form. It uses ng-keyup to listen to changes to the input values, and display messages as a result.

To enter their date of birth, the user can either type directly into three text boxes or use a jquery plugin called pickaday, which allows the user to pick a date and then writes the date out to the three text boxes. Since I can add the ng-keyup attribute to the text boxes, processing of the date of birth is straightforward if the user types it rather than using the pickaday plugin.

The initialisation script of the pickaday plugin allows you to specify a callback function for whenever the user chooses a date. I need to somehow get this callback to run the code in my controller, so that the same code runs when the user picks a date from the plugin as if he had typed it in.

Is there a way I can do this?

NB: I tried simply using ng-change rather than ng-keyup for the three text boxes, hoping that ng-change would pick up on changes to the text boxes made by the pickaday plugin, but that didn't work. :(

3
  • 1
    How are you initializing the plugin? A certain way to have access to the controller from the plugin would be to use a directive. This directive would create all the fields, install the plugin and register callbacks. Commented Oct 24, 2013 at 9:39
  • Can you provide an example? Commented Oct 24, 2013 at 10:10
  • I think the principle is in the answer from Eugenio Cuevas. Commented Oct 24, 2013 at 10:29

2 Answers 2

1

The correct way to do this is a directive. Sounds like you would like two-way databinding working between angular and the jQuery plugin. I'm just guessing how the plugin works but I think you get the idea

app.directive('pickday', function() {
    return {
        scope: {
            // note you can also pass a function
            value: '='
        },
        // watch for changes on controller value
        controller: function ($scope, $element) {
            $scope.$watch('value', function(newVal, oldVal) {
                angular.element($element).pickday({
                    value :parseInt($scope.value, 10)
                });
            });
        },
        // initialize pickday
        link: function ($scope, $element, attr) {
        $element.pickday({
            value: parseInt($scope.value, 10),
            //use the callback from pickday, note apply to trigger angular digest
            change: function(event, ui) {
                if (event.originalEvent) {
                    $scope.value = ui.value;
                    $scope.$apply();
                }
            }
        });
    },
    template: '<div class="pickday"></div>'
    };
});

Then use the directive on your view like this:

<pickday value="value.fromScope"></pickday>
Sign up to request clarification or add additional context in comments.

5 Comments

Actually, I don't need two way databinding. I just need the controller to be aware when the user picks a date from the plugin. Thank you.
Then, you only have to skip the controller part, the link part still applies
And can I just paste this code anywhere, or does it go somewhere in the controller or module?
I suggest you read the linked docs in angular about directives first, they should be defined in its own file
It's not even replacing the pickaday tag with a div.
0

Eventually, I got it working just fine like this:

.directive('datepicker', function() {
        return {
            link: function (scope) {
                var minYear = moment().year() - 90,
                maxYear = moment().year() - 13,
                today = moment().subtract('years', 13);

                var picker = new Pikaday({
                    field: document.getElementById('datepicker'),
                    trigger: document.getElementById('date-button'),
                    defaultDate: today.toDate(),
                    maxDate: today.toDate(),
                    yearRange: [minYear, maxYear],
                    onSelect: function() {
                        scope.$apply(function() {
                            scope.dayOfBirth.value = picker.getMoment().date();
                            scope.monthOfBirth.value = picker.getMoment().month() + 1;
                            scope.yearOfBirth.value = picker.getMoment().year();
                            scope.dateOfBirth.validate();
                        });
                    }
                });

            }
        };
    });

The directive can be triggered with the following HTML:

<div datepicker></div>

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.