Angular UI Bootstrap Datetimepicker with seconds - angularjs

I want to get bootstrap datetimepicker input value in angularjs controller. I am using following custom directive to achieve this . But i am getting the value is undefined. I have added the code related to html and angular code related to the issue.
HTML
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.43/css/bootstrap-datetimepicker.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.2/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.2/locale/en-gb.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.43/js/bootstrap-datetimepicker.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular-resource.js"></script>
<div class="form-group">
<div class='input-group date' id='datetimepickerFrom' datetimepicker
ng-model="fromDate" >
<input type='text' class="form-control" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
JS
'use strict';
var App = angular.module('app',['ngResource']);
App.directive('datetimepicker', function(){
return {
require: '?ngModel',
restrict: 'A',
link: function(scope, element, attrs, ngModel){
if(!ngModel) return; // do nothing if no ng-model
ngModel.$render = function(){
element.find('#datetimepickerFrom').val( ngModel.$viewValue || '' );
};
element.datetimepicker({
format : 'YYYY-MM-DD HH:mm:ss'
});
element.on('dp.change', function(){
scope.$apply(read);
});
read();
function read() {
var value = element.find('#datetimepickerFrom').val();
ngModel.$setViewValue(value);
console.log(ngModel.$setViewValue(value));
}
}
};
});
App.controller('myController', ['$scope', function($scope) {
$scope.fromDate = moment();
}]);

I have found a package for you to fix your problem which is in the link.
LINK
Easy way to achieve it follow these below steps
Add this markup.
You need to include the following scripts
//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js
//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.0.1.js
//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css
//cdn.rawgit.com/zhaber/datetimepicker/master/datetimepicker.js
//cdn.rawgit.com/zhaber/datetimepicker/master/datetimepicker.css
Controller will hold the model value in $scope.date which contains the date and time.
Update 1
This control does not support Seconds, I would suggest you to go with Angular UI Bootstrap as below
Include the above references expect last two and use the below markup.
<p class="input-group">
<input type="text" class="form-control" uib-datepicker-popup is-open="popup1.opened" ng-model="fromDate" datepicker-options="dateOptions" ng-required="true" close-text="Close" />
<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 uib-timepicker ng-model="fromTime" ng-change="changed()" hour-step="1" minute-step="1" show-meridian="ismeridian" show-seconds="true"></div>
Add this module as a dependency ui.bootstrap
Use the below code to combine your value
$scope.changed = function () {
var month = $scope.fromDate.getMonth()+1;
var day = $scope.fromDate.getDate();
var year = $scope.fromDate.getFullYear();
var hour = $scope.fromTime.getHours();
if (hour < 10)
hour = "0"+hour;
var min = $scope.fromTime.getMinutes();
if (min < 10)
min = "0"+min;
var sec = $scope.fromTime.getSeconds();
if (sec < 10)
sec = "0"+sec;
//put it all togeter
var dateTimeString = month+'/'+day+'/'+year+' '+hour+':'+min+':'+sec;
$scope.fromDateTime= dateTimeString;
};
Your live ng-model value combined together
fromDateTime:{{fromDateTime |date : 'yyyy-MM-dd HH:mm:ss'}}
So by this if the seconds value is changed only you will get the actual Date Time

Related

Bootstrap DateTimePicker with AngularJS: Passing directive ngModel value to controller

I am trying to get angular bootstrap datetimepicker input value using a custom directive like shown below. I am able to get the value in directive. How can i access this directive scope value in angular controller.
HTML
<div class='input-group date' id='datetimepickerId' datetimez ng-model="dueDate" >
<input type='text' class="form-control" />
</div>
Controller
App.directive('datetimez', function(){
return {
require: '?ngModel',
restrict: 'A',
link: function(scope, element, attrs, ngModel){
if(!ngModel) return;
ngModel.$render = function(){
element.find('#datetimepickerId').val( ngModel.$viewValue || '' );
};
element.datetimepicker({
format : 'YYYY-MM-DD HH:mm:ss'
});
element.on('dp.change', function(){
scope.$apply(read);
});
read();
function read() {
var value = element.find('#datetimepickerId').val();
ngModel.$setViewValue(value);
console.log(scope.dueDate);
}
}
};
});
App.controller('myController', ['$scope', function($scope) {
console.log($scope.dueDate);
}]);
Log inside the directive prints value successfully. But log inside controller does not.
Here you go.
I checked the documentation of the bootstrap datetimepicker and come to know there are two implementation.
One with a icon to click and show the datetimepicker
Another one just with a textbox without a icon
For the first one, you have to use the parent div to initiate the plugin and for the second option, you have to use the textbox to initiate the plugin
You have used the second option but used the parent div to initiate the plugin with a directive.
Also, div elements won't support the ngModel, hence directive should be used with the input element.
I have extended your directive to handle both scenarios and also the date format and other options can be passed from the controller.
You can give a try with the below working snippet.
var App = angular.module('App', []);
App.directive('datetimez', function(){
return {
require: '?ngModel',
restrict: 'A',
link: function(scope, element, attrs, ngModel){
if(!ngModel) return;
ngModel.$render = function(){
element.val( ngModel.$viewValue || '' );
};
function read() {
var value = element.val();
ngModel.$setViewValue(value);
//console.log(scope.dueDate);
}
var options = scope.$eval(attrs.datetimez) || {};
if(element.next().is('.input-group-addon')) {
var parentElm = $(element).parent();
parentElm.datetimepicker(options);
parentElm.on('dp.change', function(){
scope.$apply(read);
});
} else {
element.datetimepicker(options);
element.on('dp.change', function(){
scope.$apply(read);
});
}
read();
}
};
});
App.controller('myController', ['$scope', function($scope) {
$scope.datePickerOptions = {
format : 'YYYY-MM-DD HH:mm:ss'
};
$scope.$watch('dueDate1', function(){
console.log($scope.dueDate1);
});
$scope.$watch('dueDate2', function(){
console.log($scope.dueDate2);
});
}]);
angular.bootstrap(document, ['App']);
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.43/css/bootstrap-datetimepicker.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.16.0/moment.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.43/js/bootstrap-datetimepicker.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="container" ng-controller="myController">
<div class="row">
<div class='col-md-6'>
<div class="form-group">
<div class='input-group date' id='datetimepicker1'>
<input type='text' class="form-control" datetimez="datePickerOptions" ng-model="dueDate1" />
</div>
</div>
</div>
</div>
<div class="row">
<div class='col-md-6'>
<div class="form-group">
<div class='input-group date' id='datetimepicker1'>
<input type='text' class="form-control" datetimez="datePickerOptions" ng-model="dueDate2" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
</div>
</div>

Odd behaviour with multiple datepickers using AngularJS and UI Bootstrap

I'm writing an app using AngularJS and UI Bootstrap, and I'm trying to implement a modal where the user can choose a start date and an end date for an event. The problem I'm having is that when the user is chosing an end date, the start date is affected as well, leading to incorrect values.
I have made a minimal test case here: http://147.75.205.135/test/
(I tried to reproduce it using Plunkr, but for some reason I didn't get the same behaviour there)
Plunker link: http://plnkr.co/edit/kika1viHi8csXMuklw8Z
To recreate the issue, click the "Launch" button, open up the datepicker for the start date, and click the right arrow to go to the next month and choose a date. Then for the end date, click the right arrow to go to the next month and pick any date. Then click "Save". An alert box will show up displaying the start and end date, but the start date does not correspond to the one chosen in the datepicker, it is set to the 1st of the month chosen for the end date.
I have nailed it down to the following function in http://147.75.205.135/test/script/angular/main.js:
$scope.adjustEndDate = function() {
if ($scope.endDate < $scope.startDate) {
console.log("Adjusting end date to " + $scope.startDate);
$scope.endDate = $scope.startDate;
}
};
It is called from ng-change on the start date picker. Commenting it out makes the odd behaviour go away. But I don't understand why it would cause this issue. I need this function so that when the user has chosen a start date, the end date is automatically adjusted so that it is never before the start date.
Complete code:
index.html
<!doctype html>
<html>
<head>
<title>Test page</title>
<link rel="stylesheet" href="bootswatch-dist/css/bootstrap.min.css"></link>
<link rel="stylesheet" href="css/main.css"></link>
<script>
var conf = {
templates: {
datepickModal: "script/angular/templates/datepickModal.html"
}
};
</script>
<script src="angular/angular.js" ></script>
<script src="jquery/dist/jquery.min.js"></script>
<script src="angular-animate/angular-animate.js"></script>
<script src="angular-bootstrap/ui-bootstrap.js"></script>
<script src="angular-bootstrap/ui-bootstrap-tpls.js"></script>
<script src="script/angular/main.js"></script>
</head>
<body data-ng-app="mainApp">
<div id="main" ng-controller="testCtrl">
<button ng-click="openModal()">Launch modal</button>
</div>
</body>
</html>
main.js
+function(angular, d3) {
"use strict";
var app = angular.module('mainApp', ['ui.bootstrap']);
app.controller('datepickCtrl', ['$scope', '$rootScope', '$uibModalInstance', function($scope, $rootScope, $uibModalInstance) {
$scope.startDate = new Date();
$scope.endDate = new Date();
$scope.startOpened = false;
$scope.endOpened = false;
$scope.name = '';
$scope.mode = 'list';
$scope.save = function () {
alert("Saving dates start: " + $scope.startDate + " and end " + $scope.endDate);
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
$scope.toggleStartCalendar = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.startOpened = !$scope.startOpened;
};
$scope.toggleEndCalendar = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.endOpened = !$scope.endOpened;
};
$scope.dateOptions = {
formatYear: 'yy',
startingDay: 1
};
$scope.setMode = function(mode) {
$scope.mode = mode;
}
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
$scope.adjustEndDate = function() {
if ($scope.endDate < $scope.startDate) {
console.log("Adjusting end date to " + $scope.startDate);
$scope.endDate = $scope.startDate;
}
};
$scope.adjustStartDate = function() {
if ($scope.startDate > $scope.endDate) {
console.log("Adjusting start date to " + $scope.endDate);
$scope.startDate = $scope.endDate;
}
};
}]);
app.controller('testCtrl', ['$scope', '$rootScope', '$uibModal', function($scope, $rootScope, $uibModal) {
$scope.openModal = function() {
if (conf.suspended) {
return;
}
var modalInstance = $uibModal.open({
animation: true,
templateUrl: conf.templates.datepickModal,
controller: 'datepickCtrl',
size: 'md'
});
};
}]);
}(window.angular, window.d3);
modal.html
<div class="modal-header">
<h3 class="modal-title">Datepick tester</h3>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-6">
<p class="input-group">
<label for="startdate">Start date</label><p class="input-group">
<input type="text" class="form-control" uib-datepicker-popup ng-model="startDate" ng-change="adjustEndDate()" is-open="startOpened" ng-required="true" uib-datepicker-options="dateOptions" name="startdate" ng-click="toggleStartCalendar($event)"/>
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="toggleStartCalendar($event)"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
<div class="col-md-6">
<p class="input-group">
<label for="enddate">End date</label><p class="input-group">
<input type="text" class="form-control" uib-datepicker-popup ng-model="endDate" is-open="endOpened" ng-change="adjustStartDate()" ng-required="true" uib-datepicker-options="dateOptions" name="enddate" ng-click="toggleEndCalendar($event)"/>
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="toggleEndCalendar($event)"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="save()">Save</button>
<button class="btn btn-warning" ng-click="cancel()">Close</button>
</div>
Versions used
AngularJS: 1.4.8
JQuery: 2.1.4
UI-bootstrap: 1.2.4
I had the same problem. The issue is that you are copying the Date object here:
$scope.endDate = $scope.startDate
Just change it to:
$scope.endDate = new Date($scope.startDate.getTime())

Creating a time range UI with angularjs and UI bootstrap

I'm using a datepicker and two timepickers to create a time range within the given day (resulting in two date objects).
The datepicker's ng-model points to the start date and copies the date portion to the end date on ng-change. So far so good.
But: Modifying the end time reverts the end date to its original value!
Markup:
<!doctype html>
<html ng-app="ui.bootstrap.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.12.0.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.9.0/moment.min.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="TimepickerDemoCtrl">
<h1>Purpose: UI for a time range within a day</h1>
<p>Issue: Updating the date sets the correct end date BUT updating the end time reverts the end date back to its original value.</p>
<div class="input-group" style="width:150px">
<input type="text" required ng-model="item.startDate" ng-change="setEndDate()" class="form-control" datepicker-popup="yyyy-MM-dd" is-open="datePicker" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="openPicker($event, 'datePicker')"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</div>
<timepicker ng-model="item.startDate" show-meridian="false"></timepicker>
<timepicker ng-model="item.endDate" show-meridian="false"></timepicker>
<pre class="alert alert-info">start is: {{item.startDate | date:'yyyy-MM-dd HH:mm' }}<br/>end is: {{item.endDate | date:'yyyy-MM-dd HH:mm' }}<br/>Duration: {{item.duration() | number:2}}</pre>
</div>
</body>
</html>
Script:
angular.module('ui.bootstrap.demo', ['ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('TimepickerDemoCtrl', function ($scope, $log) {
var starttime = new Date();
starttime.setHours(8);
starttime.setMinutes(0);
var endtime = new Date();
endtime.setHours(17);
endtime.setMinutes(0);
$scope.item = {
startDate: starttime,
endDate: endtime,
duration: function () { return moment.duration(moment(this.endDate) - moment(this.startDate)).asHours() }
}
$scope.setEndDate = function() {
$scope.item.endDate.setDate($scope.item.startDate.getDate());
$scope.item.endDate.setMonth($scope.item.startDate.getMonth());
$scope.item.endDate.setFullYear($scope.item.startDate.getFullYear());
}
$scope.openPicker = function ($event, pickerInstance) {
$event.preventDefault();
$event.stopPropagation();
$scope[pickerInstance] = true;
};
});
http://plnkr.co/edit/zCFgf0mt4WOZeG9MPA9d
In some reason UI Bootstrap datepicker don't observe endDate value modification in your case.
Instead of modifying endDate you can copy startDate object and link to endDate:
$scope.setEndDate = function() {
$scope.item.endDate = angular.copy($scope.item.startDate);
};

Angular UI Bootstrap datepicker malfunctioning

I am using Angular Ui Datepicker in my app. Strange thing is happening, may be a bug. The date picker is not functioning (not showing) if there is a child element inside the datepicker element.
In my example below if I put span (or any other) tag inside a tag - where I have put my datepicker - it will not work, but if there is not child element inside of it , it works as expected.
Is this a bug or I am missing something ?
Edit : Created A Fiddle Also
var app = angular.module('app', ['ui.bootstrap']);
app.controller("TestController", function($scope) {
$scope.isOpen = false;
$scope.isOpen2 = false;
$scope.isOpen3 = false;
$scope.popupOptions = {};
});
<link href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet" />
<div ng-app="app">
This will show Date picker
<br />
<a href="javascript://" ng-model="deadline2" is-open="isOpen2" ng-click="isOpen2 = !isOpen2" datepicker-popup="popupOptions"> <span> This will not </span>
</a>
<br />
<a href="javascript://"> <span ng-model="deadline2" is-open="isOpen3" datepicker-popup="popupOptions" ng-click="isOpen3 = !isOpen3"> This will also show </span>
</a>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.min.js"></script>
Looks like the datepicker can only be set on the innermost elements. It might be that way by design as I found no examples where datepicker is set on a parent element.
Also, you code works if the datepicker is set on span(or any other child element).
<a href="javascript://">
<span ng-model="deadline" is-open="isOpen" ng-click="isOpen = !isOpen" datepicker-popup="popupOptions">datepicker set on span inside anchor</span>
</a>
Plnkr
Here is an example to use the directive with a bootstrap input, displaying a calendar button
HTML
<p class="input-group">
<input type="text" class="form-control" datetime-picker="dd MMM yyyy HH:mm" ng-model="myDate" is-open="isOpen" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="openCalendar($event, prop)"><i class="fa fa-calendar"></i></button>
</span>
</p>
JAVASCRIPT
app.controller('MyController', function() {
var that = this;
this.isOpen = false;
this.openCalendar = function(e) {
e.preventDefault();
e.stopPropagation();
that.isOpen = true;
};
});
See demo : https://github.com/Gillardo/bootstrap-ui-datetime-picker

Angular bootstrap datepicker date format does not format ng-model value

I am using bootstrap date-picker in my angular application. However when I select a date from that date-picker underlying ng-model that I have bind gets updated I want that ng-model in one date format 'MM/dd/yyyy'. but it every times makes date like this
"2009-02-03T18:30:00.000Z"
instead of
02/04/2009
I have created a plunkr for the same plunkr link
My Html and controller code is like below
<!doctype html>
<html ng-app="plunker">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.0.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="DatepickerDemoCtrl">
<pre>Selected date is: <em>{{dt | date:'MM/dd/yyyy' }}</em></pre>
<p>above filter will just update above UI but I want to update actual ng-modle</p>
<h4>Popup</h4>
<div class="row">
<div class="col-md-6">
<p class="input-group">
<input type="text" class="form-control"
datepicker-popup="{{format}}"
ng-model="dt"
is-open="opened" min-date="minDate"
max-date="'2015-06-22'"
datepicker-options="dateOptions"
date-disabled="disabled(date, mode)"
ng-required="true" close-text="Close" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event)">
<i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
<!--<div class="row">
<div class="col-md-6">
<label>Format:</label> <select class="form-control" ng-model="format" ng-options="f for f in formats"><option></option></select>
</div>
</div>-->
<hr />
{{dt}}
</div>
</body>
</html>
Angular controller
angular.module('plunker', ['ui.bootstrap']);
var DatepickerDemoCtrl = function ($scope) {
$scope.open = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened = true;
};
$scope.dateOptions = {
formatYear: 'yy',
startingDay: 1
};
$scope.format = 'dd-MMMM-yyyy';
};
UPDATE
I am calling below method for posting my data and VAR is array of size 900 which contains date-picker variables.
public SaveCurrentData(formToSave: tsmodels.ResponseTransferCalculationModelTS) {
var query = this.EntityQuery.from('SaveFormData').withParameters({
$method: 'POST',
$encoding: 'JSON',
$data: {
VAR: formToSave.VAR,
X: formToSave.X,
CurrentForm: formToSave.currentForm,
}
});
var deferred = this.q.defer();
this.manager.executeQuery(query).then((response) => {
deferred.resolve(response);
}, (error) => {
deferred.reject(error);
});
return deferred.promise;
}
Although similar answers have been posted I'd like to contribute what seemed to be the easiest and cleanest fix to me. Assuming you are using the AngularUI datepicker and your initial value for the ng-Model does not get formatted simply adding the following directive to your project will fix the issue:
angular.module('yourAppName')
.directive('datepickerPopup', function (){
return {
restrict: 'EAC',
require: 'ngModel',
link: function(scope, element, attr, controller) {
//remove the default formatter from the input directive to prevent conflict
controller.$formatters.shift();
}
}
});
I found this solution in the Github AngularUI issues and therefore all credit goes to the people over there.
You can make use of $parsers as shown below,this solved it for me.
window.module.directive('myDate', function(dateFilter) {
return {
restrict: 'EAC',
require: '?ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$parsers.push(function(viewValue) {
return dateFilter(viewValue,'yyyy-MM-dd');
});
}
};
});
HTML:
<p class="input-group datepicker" >
<input
type="text"
class="form-control"
name="name"
datepicker-popup="yyyy-MM-dd"
date-type="string"
show-weeks="false"
ng-model="data[$parent.editable.name]"
is-open="$parent.opened"
min-date="minDate"
close-text="Close"
ng-required="{{editable.mandatory}}"
show-button-bar="false"
close-on-date-selection="false"
my-date />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="openDatePicker($event)">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</p>
I ran into the same problem and after a couple of hours of logging and investigating, I fixed it.
It turned out that for the first time the value is set in a date picker, $viewValue is a string so the dateFilter displays it as is. All I did is parse it into a Date object.
Search for that block in ui-bootstrap-tpls file
ngModel.$render = function() {
var date = ngModel.$viewValue ? dateFilter(ngModel.$viewValue, dateFormat) : '';
element.val(date);
updateCalendar();
};
and replace it by:
ngModel.$render = function() {
ngModel.$viewValue = new Date(ngModel.$viewValue);
var date = ngModel.$viewValue ? dateFilter(ngModel.$viewValue, dateFormat) : '';
element.val(date);
updateCalendar();
};
Hopefully this will help :)
The format specified through datepicker-popup is just the format for the displayed date. The underlying ngModel is a Date object. Trying to display it will show it as it's default, standard-compliant rapresentation.
You can show it as you want by using the date filter in the view, or, if you need it to be parsed in the controller, you can inject $filter in your controller and call it as $filter('date')(date, format). See also the date filter docs.
You may use formatters after picking value inside your datepicker directive.
For example
angular.module('foo').directive('bar', function() {
return {
require: '?ngModel',
link: function(scope, elem, attrs, ctrl) {
if (!ctrl) return;
ctrl.$formatters.push(function(value) {
if (value) {
// format and return date here
}
return undefined;
});
}
};
});
LINK.
With so many answers already written, Here's my take.
With Angular 1.5.6 & ui-bootstrap 1.3.3 , just add this on the model & you are done.
ng-model-options="{timezone: 'UTC'}"
Note: Use this only if you are concerned about the date being 1 day behind & not bothered with extra time of T00:00:00.000Z
Updated Plunkr Here :
http://plnkr.co/edit/nncmB5EHEUkZJXRwz5QI?p=preview
All proposed solutions didn't work for me but the closest one was from #Rishii.
I'm using AngularJS 1.4.4 and UI Bootstrap 0.13.3.
.directive('jsr310Compatible', ['dateFilter', 'dateParser', function(dateFilter, dateParser) {
return {
restrict: 'EAC',
require: 'ngModel',
priority: 1,
link: function(scope, element, attrs, ngModel) {
var dateFormat = 'yyyy-MM-dd';
ngModel.$parsers.push(function(viewValue) {
return dateFilter(viewValue, dateFormat);
});
ngModel.$validators.date = function (modelValue, viewValue) {
var value = modelValue || viewValue;
if (!attrs.ngRequired && !value) {
return true;
}
if (angular.isNumber(value)) {
value = new Date(value);
}
if (!value) {
return true;
}
else if (angular.isDate(value) && !isNaN(value)) {
return true;
}
else if (angular.isString(value)) {
var date = dateParser.parse(value, dateFormat);
return !isNaN(date);
}
else {
return false;
}
};
}
};
}])
I can fix this by adding below code in my JSP file. Now both model and UI values are same.
<div ng-show="false">
{{dt = (dt | date:'dd-MMMM-yyyy') }}
</div>
Steps to change the default date format of ng-model
For different date formats check the jqueryui datepicker date format values here for example I have used dd/mm/yy
Create angularjs directive
angular.module('app', ['ui.bootstrap']).directive('dt', function () {
return {
restrict: 'EAC',
require: 'ngModel',
link: function (scope, element, attr, ngModel) {
ngModel.$parsers.push(function (viewValue) {
return dateFilter(viewValue, 'dd/mm/yy');
});
}
}
});
Write dateFilter function
function dateFilter(val,format) {
return $.datepicker.formatDate(format,val);
}
In html page write the ng-modal attribute
<input type="text" class="form-control" date-type="string" uib-datepicker-popup="{{format}}" ng-model="src.pTO_DATE" is-open="popup2.opened" datepicker-options="dateOptions" ng-required="true" close-text="Close" show-button-bar="false" show-weeks="false" dt />
The datepicker (and datepicker-popup) directive requires that the ng-model be a Date object. This is documented here.
If you want ng-model to be a string in specific format, you should create a wrapper directive. Here is an example (Plunker):
(function () {
'use strict';
angular
.module('myExample', ['ngAnimate', 'ngSanitize', 'ui.bootstrap'])
.controller('MyController', MyController)
.directive('myDatepicker', myDatepickerDirective);
MyController.$inject = ['$scope'];
function MyController ($scope) {
$scope.dateFormat = 'dd MMMM yyyy';
$scope.myDate = '30 Jun 2017';
}
myDatepickerDirective.$inject = ['uibDateParser', '$filter'];
function myDatepickerDirective (uibDateParser, $filter) {
return {
restrict: 'E',
scope: {
name: '#',
dateFormat: '#',
ngModel: '='
},
required: 'ngModel',
link: function (scope) {
var isString = angular.isString(scope.ngModel) && scope.dateFormat;
if (isString) {
scope.internalModel = uibDateParser.parse(scope.ngModel, scope.dateFormat);
} else {
scope.internalModel = scope.ngModel;
}
scope.open = function (event) {
event.preventDefault();
event.stopPropagation();
scope.isOpen = true;
};
scope.change = function () {
if (isString) {
scope.ngModel = $filter('date')(scope.internalModel, scope.dateFormat);
} else {
scope.ngModel = scope.internalModel;
}
};
},
template: [
'<div class="input-group">',
'<input type="text" readonly="true" style="background:#fff" name="{{name}}" class="form-control" uib-datepicker-popup="{{dateFormat}}" ng-model="internalModel" is-open="isOpen" ng-click="open($event)" ng-change="change()">',
'<span class="input-group-btn">',
'<button class="btn btn-default" ng-click="open($event)"> <i class="glyphicon glyphicon-calendar"></i> </button>',
'</span>',
'</div>'
].join('')
}
}
})();
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-animate.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-sanitize.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.5.0.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body ng-app="myExample">
<div ng-controller="MyController">
<p>
Date format: {{dateFormat}}
</p>
<p>
Value: {{myDate}}
</p>
<p>
<my-datepicker ng-model="myDate" date-format="{{dateFormat}}"></my-datepicker>
</p>
</div>
</body>
</html>
Defining a new directive to work around a bug is not really ideal.
Because the datepicker displays later dates correctly, one simple workaround could be just setting the model variable to null first, and then to the current date after a while:
$scope.dt = null;
$timeout( function(){
$scope.dt = new Date();
},100);
After checking the above answers, I came up with this and it worked perfectly without having to add an extra attribute to your markup
angular.module('app').directive('datepickerPopup', function(dateFilter) {
return {
restrict: 'EAC',
require: 'ngModel',
link: function(scope, element, attr, ngModel) {
ngModel.$parsers.push(function(viewValue) {
return dateFilter(viewValue, 'yyyy-MM-dd');
});
}
}
});
Finally I got work around to the above problem. angular-strap has exactly the same feature that I am expecting. Just by applying date-format="MM/dd/yyyy" date-type="string" I got my expected behavior of updating ng-model in given format.
<div class="bs-example" style="padding-bottom: 24px;" append-source>
<form name="datepickerForm" class="form-inline" role="form">
<!-- Basic example -->
<div class="form-group" ng-class="{'has-error': datepickerForm.date.$invalid}">
<label class="control-label"><i class="fa fa-calendar"></i> Date <small>(as date)</small></label>
<input type="text" autoclose="true" class="form-control" ng-model="selectedDate" name="date" date-format="MM/dd/yyyy" date-type="string" bs-datepicker>
</div>
<hr>
{{selectedDate}}
</form>
</div>
here is working plunk link

Resources