8

I am currently porting a large application over to a HTML5 based web app - I have started building the app in AngularJS and enjoying the power of the AngularJS framework - I have one issue standing in my way currently:

I have a directive that gives me a jQuery Datepicker however the binding to the model does not seem to be working.

http://jsfiddle.net/9BRNf/

I am probably misunderstanding the way directives work and would like to see if I can patch this part of my understanding of the framework. I have gone through loads of examples (including the angularui project on github but still not making sense of why the binding is not happening)

any assistance will be greatly appreciated.

5
  • 1
    ok well I seem to have a solution - jsfiddle.net/9BRNf/2 - would still like to know if this is a correct/best way of dealing with this issue. Commented May 23, 2012 at 22:26
  • I believe the onSelect of datepicker isn't needed. The values will already be bound into the model when the picker is changed. Commented May 24, 2012 at 2:18
  • @dj2 that's what I thought but check the fiddle in the original message - the model isn't binding. Commented May 24, 2012 at 5:24
  • Interesting, though I'd tried it this afternoon but I didn't catch you had to press the Run button to reload. Commented May 24, 2012 at 6:03
  • You should post your code into your question, not just rely on a link to JSFiddle. That way your answer is still useful if JSFiddle is unavailable for any reason. Commented Jul 25, 2012 at 15:44

7 Answers 7

6

For those Googling this issue (as I was), a simpler way of tying in the jQuery UI datepicker with Angular is to do this...

$.datepicker.setDefaults({
    // When a date is selected from the picker
    onSelect: function(newValue) {
        if (window.angular && angular.element)
            // Update the angular model
            angular.element(this).controller("ngModel").$setViewValue(newValue);
    }
});

Just place it prior to your .datepicker() initialisation code.

(Taken from another answer I posted here: https://stackoverflow.com/a/17206242/195835)

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

Comments

4

First off, it's great that you are using angularjs, its a sweet framework. An offshoot project was started awhile back to deal with things like wrapping jquery-ui and creating ui modules.

Below is link to Peter Bacon Darwin's implementation.

https://github.com/angular-ui/angular-ui/tree/master/modules/directives/date

--dan

4 Comments

Thanks Dan - what is weird is that I actually tried AngularUI a day ago and it gave the exact same binding issue - I have however tried it again now jsfiddle.net/9BRNf/6 and it works perfectly.
This is still not working with latest AngularJS(1.0.2 & Angular-UI(took latest today) :-(
Sutikshan, can you post a fiddle/plunkr describing what is not working? And give more background, like browsers used. Dinesh example is working fine. I do know that there are some issues being reported but it does work.
this link is now showing 404, could you please update the url?
2

The angular-ui datepicker wasn't working with Angular 1.0.0, so I rewrote it. My fork gives you the ability to set how the date is formatted inside the input and how it gets saved back to the model.

Code: https://gist.github.com/2967979 jsFiddle: http://jsfiddle.net/m8L8Y/8/ (It's missing jquery-ui styles but works just the same)


// Code inspired by angular-ui https://github.com/angular-ui/angular-ui/blob/master/modules/directives/date/src/date.js
/*
Features:
* via the ui-date attribute:
    * Ability to say how model is parsed into a date object
    * Ability to say how input's value is parsed into a date object
    * Ability to say how a date object is saved to the model
    * Ability to say how a date object is displayed in the input
* via the ui-date-picker attribute
    * Ability to directly configure the jQuery-ui datepicker
*/


angular.module('ui.directives', [])
    .directive('uiDate', function () {
        return {
            require: '?ngModel',
            //scope: {},
            link: function ($scope, element, attrs, ngModel) {
                // Date Handling Functions
                var dateHandler = $.extend({ model: {}, view: {} }, $scope.$eval(attrs.uiDate));

                // This will attempt to use preferredParser to parse a date.
                function defaultDateParse(date, preferredParser) {
                    if (!preferredParser)
                        return new Date(date);
                    return preferredParser(date);
                }

                // This will attempt to use preferredFormatter to format a date, otherwise use 'mm/dd/yy'.
                function defaultDateFormatter(date, preferredFormatter) {
                    if (!preferredFormatter)
                        preferredFormatter = "mm/dd/yy";

                    if (typeof preferredFormatter == 'string')
                        return $.datepicker.formatDate(preferredFormatter, date);
                    else
                        return preferredFormatter(date);
                }

                // Functions for Parsing & Formatting on the Model & View
                function parseDateFromModel(date) {
                    return defaultDateParse(date, dateHandler.model.parse)
                }
                function parseDateFromView(date) {
                    return defaultDateParse(date, dateHandler.view.parse)
                }
                function formatDateForModel(date) {
                    return defaultDateFormatter(date, dateHandler.model.format)
                }
                function formatDateForView(date) {
                    return defaultDateFormatter(date, dateHandler.view.format)
                }

                var defaultDateViewFormat = (
                    typeof dateHandler.view.format == 'string'
                    ? dateHandler.view.format
                    : 'mm/dd/yy'
                )

                // Initialize the jQuery-ui datePicker
                var datePickerSettings = $.extend({ dateFormat: defaultDateViewFormat }, $scope.$eval(attrs.uiDatePicker))
                var oldOnSelect = datePickerSettings.onSelect;
                datePickerSettings.onSelect = function (dateVal) {
                    $scope.$apply(function () {
                        element.focus().val(dateVal);
                        updateModel();
                    })
                    if (oldOnSelect)
                        oldOnSelect.apply(this, arguments)
                }

                element.datepicker(datePickerSettings);

                if (ngModel) {
                    // Specify how UI should be updated
                    ngModel.$render = function () {
                        element.val(ngModel.$viewValue || '');
                    };

                    // Listen for change events to enable binding
                    element.bind('blur keyup change', function () {
                        $scope.$apply(updateModel);
                    });

                    // Write data to the model
                    function updateModel() {
                        ngModel.$setViewValue(element.val());
                    }

                    // Convert the model into a string value
                    ngModel.$formatters.push(function (v) {
                        if (v != "" && v != null)
                            return formatDateForView(parseDateFromModel(v));
                        return null;
                    });

                    // Convert the string value into the model
                    ngModel.$parsers.push(function (v) {
                        if (v != "" && v != null)
                            return formatDateForModel(parseDateFromView(v))
                        return null;
                    });
                }

            }
        };
    })

1 Comment

Post your code into your answer, as then your answer is still useful if Gist or JSFiddle are unavailable for any reason.
2

Similar to praveepd (using their's as a base), but this will include deep model selection.

http://jsfiddle.net/c8PMa/

var myApp = angular.module('myApp', ['myApp.directives']);

function MainCtrl($scope) {

    $scope.deepValue = {
        fromDate: null,
        toDate: null
    }

}

angular.module('myApp.directives', [])
  .directive('myDatepicker', function() {
    return function(scope, element, attrs) {     

       element.datepicker({
         changeYear : true,
         changeMonth : true,
         appendText : '(yyyy-mm-dd)',
         dateFormat : 'yy-mm-dd', 
                onSelect: function(dateText) {                    
                    var mdlAttr = $(this).attr('ng-model').split(".");

                    if (mdlAttr.length > 1) {

                        var objAttr = mdlAttr[mdlAttr.length-1];
                        var s = scope[mdlAttr[0]];

                        for (var i=0; i < mdlAttr.length-2; i++) {
                            s = s[mdlAttr[i]];
                        }

                        s[objAttr] = dateText;
                    } else {
                        scope[mdlAttr[0]] = dateText;
                    }

                    scope.$apply();
                }                
        });

    }
});​

1 Comment

To improve the quality of your post please include how/why your post will solve the problem.
1

http://jsfiddle.net/9BRNf/74/ here is the solution :)

code:

     var myApp = angular.module('myApp', ['myApp.directives']);


    function MainCtrl() {

    }

    angular.module('myApp.directives', [])
      .directive('myDatepicker', function() {
          return {
             require: '?ngModel',
                link: function (scope, element, attrs, ngModelCtrl) {
          element.datepicker({
             changeYear : true,
             changeMonth : true,
             appendText : '(yyyy-mm-dd)',
             dateFormat : 'yy-mm-dd',
              onSelect: function(date) {
                  ngModelCtrl.$setViewValue(date);
                            scope.$apply();
              }
          });
        }
      }

  });

Comments

0

Old question, but this was the first hit for me in google search for this. Anyways, I used dual datepickers working together using jquery and angular directives, so I thought I'd share to help anyone else trying to do this.

Here's the plunker for it:

http://plnkr.co/edit/veEmtCM3ZnQAhGTn5EGy?p=preview

Basically it initializes the form using json. The datepickers have their own conditions like mindate's, etc. The first select box if true = disables sundays on the calendars, else enables them.

The viewmodel get's updates when 'done' is clicked. Here's a bit of the code for one of the datepickers:

Html:

<input id="StartDate" data-ng-model="viewModel.startdate" date-from />

Directive:

app.directive('dateFrom', function() {
    return function (scope, element, attrs) {
        var doDate = $('#EndDate');
        element.datepicker({
          dateFormat: 'dd-M-yy', showOtherMonths: true, 
          selectOtherMonths: true, minDate: '0',
          beforeShowDay: function (date) {
              var day = date.getDay();
              console.log(scope.nosunday);
              if (scope.nosunday === 'true') return [(day !== 0), '']; // disable sundays
              else return [true, ''];
          },
          onSelect: function (selectedDate) {
              var toDate = new Date(element.datepicker("getDate"));
              toDate.setDate(toDate.getDate() + 1);
              doDate.datepicker('option', 'minDate', toDate);
              scope.viewModel.startdate = selectedDate;
              scope.viewModel.enddate = doDate.val();
          }
        });
    }
})

Feel free to optimize it further. Post a comment with a forked plunk if you do :)

Comments

0

I had just trimmed the code, have a look at this: http://jsfiddle.net/YU5mV/

HTML

<input id="date1" value="1/1/1980"  ng-model="fromDate" my-datepicker />
<input id="date2" value="1/1/1980" ng-model="toDate" my-datepicker />

JavaScript

angular.module('myApp.directives', [])
  .directive('myDatepicker', function() {
    return function(scope, element, attrs) {     

       element.datepicker({
         changeYear : true,
         changeMonth : true,
         appendText : '(yyyy-mm-dd)',
         dateFormat : 'yy-mm-dd', 
            onSelect: function(dateText) {                    
                var mdlAttr = $(this).attr('ng-model');
                scope[mdlAttr] = dateText;                    
                scope.$apply();                                                   
            }                
        });

    }
  });

1 Comment

Please post your code into your answer, as then your answer is still useful if JSFiddle is unavailable for any reason.

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.