Wednesday, April 27, 2016

Using bootstrap-daterangepicker in an Angular directive

Leave a Comment

I'm having troubles using bootstrap-daterangepicker in an Angular directive. It works fine when initially loading the page, but when switching pages/states (I'm using ui-router) and going back to a page with a daterangepicker the plugin doesn't work anymore.

It throws this error:

TypeError: $(...).daterangepicker is not a function

It seems like the plugin has removed itself when changing states. Anyone an idea how to fix this?

app.directive("daterangepicker", function() {     return {       restrict: "A",       scope: false,       link: function($scope, $element, $attr){          $($element).daterangepicker({           format: "DD.MM.YYYY",           startDate: moment().subtract('days', 1),           endDate: new Date(),                     buttonClasses: ['btn-primary'],         }, function(from, to) {           $scope.date = {from: from, to: to};           $scope.$apply(); // I need apply() here to use the two-way-databinding         });       }     }   }); 

3 Answers

Answers 1

I would avoid reinventing the wheel, there is already a directive provided by several projects, use the https://angular-ui.github.io/bootstrap/

Import the module:

angular.module('myModule', ['ui.bootstrap']);

and the use it like that:

<!doctype html> <html ng-app="ui.bootstrap.demo">  <head>   <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.js"></script>   <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-animate.js"></script>   <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-1.3.2.js"></script>   <script src="example.js"></script>   <link href="//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"> </head>  <body>    <style>     .full button span {       background-color: limegreen;       border-radius: 32px;       color: black;     }      .partially button span {       background-color: orange;       border-radius: 32px;       color: black;     }   </style>   <div ng-controller="DatepickerPopupDemoCtrl">     <pre>Selected date is: <em>{{dt | date:'fullDate' }}</em></pre>      <h4>Popup</h4>     <div class="row">       <div class="col-md-6">         <p class="input-group">           <input type="text" class="form-control" uib-datepicker-popup="{{format}}" ng-model="dt" is-open="popup1.opened" datepicker-options="dateOptions" ng-required="true" close-text="Close" alt-input-formats="altInputFormats" />           <span class="input-group-btn">              <button type="button" class="btn btn-default" ng-click="open1()"><i class="glyphicon glyphicon-calendar"></i></button>            </span>         </p>       </div>        <div class="col-md-6">         <p class="input-group">           <input type="text" class="form-control" uib-datepicker-popup ng-model="dt" is-open="popup2.opened" datepicker-options="dateOptions" ng-required="true" close-text="Close" />           <span class="input-group-btn">              <button type="button" class="btn btn-default" ng-click="open2()"><i class="glyphicon glyphicon-calendar"></i></button>            </span>         </p>       </div>     </div>     <div class="row">       <div class="col-md-6">         <label>Format: <span class="muted-text">(manual alternate <em>{{altInputFormats[0]}}</em>)</span></label>         <select class="form-control" ng-model="format" ng-options="f for f in formats">           <option></option>         </select>       </div>     </div>      <hr />     <button type="button" class="btn btn-sm btn-info" ng-click="today()">Today</button>     <button type="button" class="btn btn-sm btn-default" ng-click="setDate(2009, 7, 24)">2009-08-24</button>     <button type="button" class="btn btn-sm btn-danger" ng-click="clear()">Clear</button>     <button type="button" class="btn btn-sm btn-default" ng-click="toggleMin()" uib-tooltip="After today restriction">Min date</button>   </div> </body>  </html> 

The controller:

angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']); angular.module('ui.bootstrap.demo').controller('DatepickerPopupDemoCtrl', function($scope) { $scope.today = function() { $scope.dt = new Date(); }; $scope.today();

  $scope.clear = function() {     $scope.dt = null;   };    $scope.inlineOptions = {     customClass: getDayClass,     minDate: new Date(),     showWeeks: true   };    $scope.dateOptions = {     dateDisabled: disabled,     formatYear: 'yy',     maxDate: new Date(2020, 5, 22),     minDate: new Date(),     startingDay: 1   };    // Disable weekend selection   function disabled(data) {     var date = data.date,       mode = data.mode;     return mode === 'day' && (date.getDay() === 0 || date.getDay() === 6);   }    $scope.toggleMin = function() {     $scope.inlineOptions.minDate = $scope.inlineOptions.minDate ? null : new Date();     $scope.dateOptions.minDate = $scope.inlineOptions.minDate;   };    $scope.toggleMin();    $scope.open1 = function() {     $scope.popup1.opened = true;   };    $scope.open2 = function() {     $scope.popup2.opened = true;   };    $scope.setDate = function(year, month, day) {     $scope.dt = new Date(year, month, day);   };    $scope.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate'];   $scope.format = $scope.formats[0];   $scope.altInputFormats = ['M!/d!/yyyy'];    $scope.popup1 = {     opened: false   };    $scope.popup2 = {     opened: false   };    var tomorrow = new Date();   tomorrow.setDate(tomorrow.getDate() + 1);   var afterTomorrow = new Date();   afterTomorrow.setDate(tomorrow.getDate() + 1);   $scope.events = [{     date: tomorrow,     status: 'full'   }, {     date: afterTomorrow,     status: 'partially'   }];    function getDayClass(data) {     var date = data.date,       mode = data.mode;     if (mode === 'day') {       var dayToCheck = new Date(date).setHours(0, 0, 0, 0);        for (var i = 0; i < $scope.events.length; i++) {         var currentDay = new Date($scope.events[i].date).setHours(0, 0, 0, 0);          if (dayToCheck === currentDay) {           return $scope.events[i].status;         }       }     }      return '';   } }); 

plunker: http://plnkr.co/edit/LZgUAZQkNKgDrUZAVWSa?p=preview

Answers 2

I finally found the solution to my problem!

To be clear: the same bug was happening with the angular-daterangepicker plugin.

It was actually caused because some other dependency loaded an extra jQuery. Because of this multiple jQuerys were loaded and this caused the bug.

Answers 3

Try adding this before initializing the daterangepicker in the directive.

if (!jQuery().daterangepicker) {      return; }  $($element).daterangepicker({...}); 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment