<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-smart-table/2.1.8/smart-table.js"></script>
<script type="text/javascript" src="mw-datepicker-range.js"></script>
<script src="controller.js"></script>
<style>
.uib-day.selected .btn {
color : #fff;
background :#5bc0de none;
border-color : #46b8da;
}
div{
outline:none;
}
</style>
</head>
<body ng-app="app" style="width:90%; margin:auto;">
<div ng-controller="MainCtrl" class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div class="col-xs-5 col-sm-5 col-md-5 col-lg-5">
<h3>Daterange picker</h3>
<div class="col-md-12">
<div uib-datepicker ng-model='activeDate3' mw-multi-select='selectedDates3' datepicker-options='options3'></div>
</div>
<div class="col-md-12">
<span>{{parsed_date2|json}}</span>
</div>
</div>
<div class="col-xs-5 col-sm-5 col-md-5 col-lg-5">
<h3>Daterange picker Popup</h3>
<div class="col-md-12">
<p class="input-group">
<input type="text" class="form-control" ng-model="activeDate" mw-multi-select="selectedDates" uib-datepicker-popup="dd/MM/y" is-open="opened" datepicker-options="options"/>
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open()"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<span>{{parsed_date|json}}</span>
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<button ng-click="parse_date()">Parse Range</button>
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div class="col-xs-5 col-sm-5 col-md-5 col-lg-5">
<h3>Date picker standard</h3>
<div class="col-md-6">
<div uib-datepicker ng-model='activeDate4' datepicker-options='options4'></div>
</div>
<div class="col-md-6">
<span>Date: {{activeDate4}}</span>
</div>
</div>
<div class="col-xs-5 col-sm-5 col-md-5 col-lg-5">
<h3>Date picker Popup standard</h3>
<div class="col-md-6">
<p class="input-group">
<input type="text" class="form-control" ng-model="activeDate2" uib-datepicker-popup="dd/MM/y" is-open="opened2" datepicker-options="options2"/>
<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 class="col-md-6">
<span>Date: {{activeDate2}}</span>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<h3>SmartTable support</h3>
<table st-set-filter="customFilter" st-table="rowCollection" class="table table-striped">
<thead>
<tr>
<th>first name</th>
<th>last name</th>
<th>birth date</th>
<th>balance</th>
<th>email</th>
</tr>
<tr>
<th>
<st-date-range predicate="birthDate" selected-dates></st-date-range>
</th>
<th colspan="3">
<input st-search placeholder="global search" class="input-sm form-control" type="search"/>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in rowCollection">
<td>{{row.firstName}}</td>
<td>{{row.lastName}}</td>
<td>{{row.birthDate}}</td>
<td>{{row.balance}}</td>
<td>{{row.email}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
var app = angular.module('app', [
'ui.bootstrap',
'smart-table',
'mw-datepicker-range'
]);
app.controller('MainCtrl',['$scope', 'mwMultiSelectService', function($scope, mwMultiSelectService) {
//datepicker range popup
$scope.activeDate = null;
$scope.selectedDates = [];
$scope.open = function() {
$scope.opened = true;
};
$scope.opened = false;
$scope.options = {
minDate:new Date()
};
$scope.parsed_date = {};
//datepicker popup
$scope.activeDate2 = null;
$scope.open2 = function() {
$scope.opened2 = true;
};
$scope.opened2 = false;
$scope.options2 = {
minDate:new Date()
};
//datepicker range
$scope.activeDate3 = null;
$scope.selectedDates3 = [new Date().setHours(0, 0, 0, 0)];
$scope.options3 = {
startingDay:1,
minDate:new Date()
};
$scope.parsed_date2 = {};
//datepicker
$scope.activeDate4 = null;
$scope.options4 = {
startingDay:1,
minDate:new Date()
}
$scope.parse_date = function(){
"use strict";
$scope.parsed_date = mwMultiSelectService.parse($scope.selectedDates, 'dd.MM.y');
$scope.parsed_date2 = mwMultiSelectService.parse($scope.selectedDates3);
}
$scope.rowCollection = [
{firstName: 'Laurent', lastName: 'Renard', birthDate: '2017-05-21', balance: 102, email: 'whatever@gmail.com'},
{firstName: 'Blandine', lastName: 'Faivre', birthDate: '2017-04-25', balance: -2323.22, email: 'oufblandou@gmail.com'},
{firstName: 'Francoise', lastName: 'Frere', birthDate: '2017-08-27', balance: 42343, email: 'raymondef@gmail.com'}
];
}]);
/**
* @version 1.1.0
* @license MIT
* @Author MrWook
*/
(function (angular) {
'use strict';
var app = angular.module('mw-datepicker-range', ['ui.bootstrap.datepicker', 'ui.bootstrap.datepickerPopup']);
app.config(['$provide', '$injector', function($provide, $injector){
// extending datepicker (access to attributes and app scope through $parent)
var datepickerDelegate = function($delegate, mwMultiSelectService){
var directive = $delegate[0];
// Override compile
var link = directive.link;
directive.compile = function(){
return function(scope, elem, attrs, ctrls){
link.apply(this, arguments);
scope.selected_dates = [];
var multi_select;
var id = mwMultiSelectService.get_last_datepicker();
if(attrs.mwMultiSelect === undefined){
var multi_select_element = angular.element(document.getElementById(id));
//watch for datepickerpopup
multi_select = multi_select_element.attr('mw-multi-select');
if(multi_select !== undefined){
multi_select_element.scope().$watchCollection(multi_select, function(value_new){
scope.selected_dates = value_new || [];
});
}
}else{
multi_select = attrs.mwMultiSelect;
//watch for datepicker
scope.$parent.$watchCollection(multi_select, function (value_new){
scope.selected_dates = value_new || [];
});
}
if(multi_select !== undefined){
attrs.$observe('mwMultiSelectType', function(value_new){
scope.selected_type = !!value_new && value_new !== "false";
});
scope.selected_type = true;
var ngModelCtrl = ctrls[1];
function change_listener() {
var value_new = ngModelCtrl.$$scope[attrs.ngModel];
if(!value_new && multi_select_element !== undefined){
value_new = ngModelCtrl.$$scope.date;
}
if(!value_new)
return;
var value_date = Math.round(+value_new.setHours(0, 0, 0, 0)),
selected_dates = scope.selected_dates;
if(scope.selected_type){
// reset range
if(!selected_dates.length || selected_dates.length > 1 || selected_dates[0] == value_date)
return selected_dates.splice(0, selected_dates.length, value_date);
selected_dates.push(value_date);
var value_temp = new Date(Math.min.apply(null, selected_dates));
var value_max = new Date(Math.max.apply(null, selected_dates));
// Start on the next day to prevent duplicating the first date
value_temp = new Date(value_temp.setDate(value_temp.getDate() + 1));
while(value_temp < value_max){
selected_dates.push(Math.round(+value_temp.setHours(0, 0, 0, 0)));
// Set a day ahead after pushing to prevent duplicating last date
value_temp = new Date(value_temp.setDate(value_temp.getDate() + 1));
}
}
}
//only add the event listener once
var check_listener = true;
for(var i = 0; i < ngModelCtrl.$viewChangeListeners.length; i++){
if(''+ngModelCtrl.$viewChangeListeners[i] == ''+change_listener){
check_listener = false;
}
}
if(check_listener)
ngModelCtrl.$viewChangeListeners.push(change_listener);
}
};
};
return $delegate;
};
if ($injector.has('uibDatepickerDirective'))
$provide.decorator('uibDatepickerDirective', ['$delegate', 'mwMultiSelectService', datepickerDelegate]);
// extending datepicker popup (access to attributes and app scope through $parent)
var datepickerPopupDelegate = function ($delegate, $filter, $timeout) {
var directive = $delegate[0];
// Override compile
var link = directive.link;
directive.compile = function(){
return function (scope, elem, attrs, ctrls) {
link.apply(this, arguments);
var ngModelCtrl = ctrls[0];
var multi_select = attrs.mwMultiSelect;
if(multi_select !== undefined){
//override change listener
ngModelCtrl.$viewChangeListeners = [function(){
scope[attrs.ngModel] = ngModelCtrl.$modelValue;
}];
//override formatter
ngModelCtrl.$formatters = [function(value){
set_view_value(value);
}];
//override parser
ngModelCtrl.$parsers = [function(value){
set_view_value(value);
}];
function set_view_value(value){
multi_select = attrs.mwMultiSelect;
var date_format = attrs.uibDatepickerPopup || 'dd.MM.y';
//inside timeout so that multi_select is set correctly
$timeout(function(){
var array = ngModelCtrl.$$scope[multi_select];
if(array === undefined)
array = [];
var from = '';
var to = '';
if(array.length > 0){
from = $filter('date')($filter('orderBy')(array)[0], date_format);
if(array.length > 1)
to = ' - '+$filter('date')($filter('orderBy')(array, '-')[0], date_format);
}
ngModelCtrl.$setViewValue(from+to);
ngModelCtrl.$render();
}, 0);
}
var old_select_function = scope.select;
scope.select = function(date, evt){
old_select_function(date, evt);
var multi_select = attrs.mwMultiSelect;
if(date === null)
ngModelCtrl.$$scope[multi_select] = [];
else if(date === 'today')
ngModelCtrl.$$scope[multi_select] = [new Date().setHours(0, 0, 0, 0)];
}
}
};
};
return $delegate;
};
if ($injector.has('uibDatepickerPopupDirective'))
$provide.decorator('uibDatepickerPopupDirective', ['$delegate', '$filter', '$timeout', datepickerPopupDelegate]);
}]);
//add template for smartTable support
app.run(['$templateCache', function($templateCache) {
$templateCache.put('stDateRange.html', '<div class="input-group"><input title="" type="text" class="form-control" ng-model="date" mw-multi-select="selectedDates" datepicker-append-to-body="true" uib-datepicker-popup="yyyy/MM/dd" is-open="is_open" datepicker-options="dateOptions"/><span class="input-group-btn"><button type="button" class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button></span></div>');
}]);
app.directive('mwMultiSelect', ['$compile', 'mwMultiSelectService', function mwMultiSelect($compile, mwMultiSelectService){
return{
priority: 1001,
terminal: true,
compile: function (elem, attr) {
var multi_select = attr.mwMultiSelect;
var options = attr.datepickerOptions;
var id = attr.id;
if(id === undefined){
id = 'mwDatePickerRange-'+Math.floor(Math.random()*1000);
elem.attr('id', id);
}
//never close the date on selection
elem.attr('close-on-date-selection', false);
//block to write into the input field
elem.attr('onkeypress', 'return false;');
elem.attr('readonly', '');
var compiled = $compile(elem, null, 1001);
return function linkFn(scope) {
if(scope[options] === undefined){
scope[options] = {};
}
scope.$watch(attr.isOpen, function(val_new){
if(val_new)
mwMultiSelectService.set_last_datepicker(id);
});
//add users customClass
if(scope[options].customClass !== undefined)
var users_custmClass = scope[options].customClass;
var return_value = '';
//add daterangerpicker custom class
scope[options].customClass = function(data){
if(users_custmClass !== undefined)
return_value = users_custmClass(data);
if(scope[multi_select] === undefined)
scope[multi_select] = [];
var temp_unix = Math.round(+data.date.setHours(0, 0, 0, 0));
if(scope[multi_select].indexOf(temp_unix) > -1 || scope[multi_select].indexOf(temp_unix+3600000) > -1) {
return return_value+' selected';
}
return return_value;
};
compiled(scope)
}
}
}
}]);
//service to return formatted value
app.service('mwMultiSelectService', ['$filter', function mwMultiSelectService($filter) {
var service = {};
service.parse = function(data, format) {
if(data === undefined)
data = [];
var return_value = {};
if(data.length > 0){
return_value.before = $filter('orderBy')(data)[0];
if(format !== undefined)
return_value.before = $filter('date')(return_value.before, format);
if(data.length > 1){
return_value.after = $filter('orderBy')(data, '-')[0];
if(format !== undefined)
return_value.after = $filter('date')(return_value.before, format);
}
}
return return_value
};
var id;
service.set_last_datepicker = function(datepicker) {
id = datepicker;
};
service.get_last_datepicker = function() {
return id
};
return service;
}]);
app.directive('stDateRange', ['$filter', function ($filter) {
return {
restrict: 'E',
require: '^stTable',
scope: {
selectedDates: '='
},
templateUrl: 'stDateRange.html',
link: function (scope, element, attr, table) {
var predicateName = attr.predicate;
scope.open = function ($event) {
$event.preventDefault();
$event.stopPropagation();
scope.is_open = !scope.is_open;
};
scope.$watch('is_open', function(val_new){
"use strict";
if(!val_new){
var query = {};
if(scope.selectedDates === undefined)
scope.selectedDates = [];
if(scope.selectedDates.length > 1){
query.before = $filter('date')($filter('orderBy')(scope.selectedDates)[0], 'y-MM-dd');
query.after = $filter('date')($filter('orderBy')(scope.selectedDates, '-')[0], 'y-MM-dd');
}else{
query = $filter('date')($filter('orderBy')(scope.selectedDates)[0], 'y-MM-dd');
}
table.search(query, predicateName);
}
});
}
}
}]);
app.filter('customFilter', ['$filter', function ($filter){
var filterFilter = $filter('filter');
var standardComparator = function standardComparator(obj, text){
text = ('' + text).toLowerCase();
return ('' + obj).toLowerCase().indexOf(text) > -1;
};
return function customFilter(array, expression){
function customComparator(actual, expected){
var itemDate;
var queryDate;
if(angular.isObject(expected)){
var before = expected.before;
var after = expected.after;
//date range
if(before && after){
try {
itemDate = new Date(actual);
queryDate = new Date(before);
if(itemDate < queryDate){
return false;
}
itemDate = new Date(actual);
queryDate = new Date(after);
if(itemDate > queryDate){
return false;
}
return true;
}catch(e){
return false;
}
}
return standardComparator(actual, expected);
}
return standardComparator(actual, expected);
}
return filterFilter(array, expression, customComparator);
};
}]);
})(window.angular);