Bootstrap-ui datepicker : how of have an empty ng-model? - angularjs

In an angular project, I have an bootstrap-ui datepicker which is used to provide info on the date when an invoice has been paid.
Initially, upon creating the invoice, as it has not been paid and so I should have an ng-model variable indicating null or something like that :
$scope.invoice.Payment_Date = null
The thing is, it appears that the datepicker needs to have a valid date object to work. When using everything this way, when I select a date in the datepicker to say my invoice has been paid, the datepicker indicates a correct date like Tuesday, February 15 2016, but the ng-model variable remains null.
If I initialize the variable as such :
$scope.invoice.Payment_Date = new Date();
then when changing the datepicker date, the ng-model is updated as it should.
The problem is, I may have to create/update the invoice without saying it has been paid, and doing so, I get a Payment_Date which has the value of the date said invoice has been created/updated.
Is there a way to leave this variable set to null or empty when the datepicker is left untouched and yet having it get the correct datepicker value when it's used ?
Hope someone can help !
Edit : here's the HTML code of the datepicker :
<form name="formFacture" novalidate rc-submit="modifierFacture()">
<div class="form-group">
<label>Date de paiement : </label>
<p class="input-group">
<input type="text" class="form-control" uib-datepicker-popup="dd MMMM yyyy" ng-model="facture.Date_Paiement" is-open="popupDatePaiement.opened" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" close-text="Fermer" clear-text="Effacer" current-text="Aujourd'hui" readonly="readonly" ng-click="openDatePaiement()" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="openDatePaiement()"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
<div class="container text-center">
<button type="submit" class="btn btn-primary">Enregistrer</button>
<div class="btn btn-primary" ng-click="ChangeLocation('prev', '/#factures')">Retour</div>
</div>
</form>
Here's the JS code :
$scope.facture = {};
$scope.dateOptions = {
startingDay: 1
};
$scope.popupDatePaiement = {
opened: false
};
var openDatePaiement = $scope.openDatePaiement = function() {
$scope.popupDatePaiement.opened = true;
};
$scope.modifierFacture = function(){
console.log($scope.facture);
return
}
After reviewing the code I found that :
I can get a valid date with the datepicker ( there was a slight error with the ng-model ) but if I change the date twice, the facture.Date_Paiement variable stays with the 1st choice, the 2nd choice does not get forwarded to it.
If I use the "clear" button inside the datepicker, the facture.Date_Paiement variable doesn't revert to null
I've tried adding this line :
$scope.Date_Paiement = null
inside the openDatePaiement function, but in this case, the facture.Date_Paiement staus null at all times.

Ok, after hours spent researching the whys of this question, I found an answer.
DO NOT rely on console.log(object) to tell you what is inside the object as it seems the function parsing the object to render it inside the console is bugged !
Instead, use console.log(JSON.stringify(object)) and you'll have the correct values.
My head still aches, what are we to do when such things are bugged ???

Related

Angular-ui-bootstrap datepicker is setting default calendar date to December 31 1969 when using with ng-required

I have a form where I have a conditionally required datepicker element. I can not initiate this element with any value as the user has to enter it. Datepicker format is dd/mm/yyyy. Issue is that it was working fine until I added ng-required. After ng-required condition added to the element, when user clicks on calendar, calendar default date is Dec 31 1969. It's very inconvenient to the user bringing that date to current date. I tried setting default date to today in datepicker options but no luck.
<div class="form-group col-md-3 required" ng-show="decision==true">
<label class="control-label">Test Date</label>
<div class="input-group">
<input name="testDate" type="text" class="form-control" datepicker-popup="dd/MM/yyyy" ng-model="testDate" is-open="dpOpened.testDateTo"
close-text="Close" onfocus="this.blur();" datepicker-options="dateOptions" ng-required="decision==true" required/>
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="datepickerPopup($event, 'testDateTo')">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</div>
</div>
--controller.js--
$scope.datepickerPopup = function($event, opened) {
$event.preventDefault();
$event.stopPropagation();
$scope.dpOpened[opened] = true;
}
$scope.dateOptions = {
showWeeks : false,
defaultDate : new Date()
};
$scope.dpOpened = {
testDateTo : false,
};
$scope.today = function() {
return new Date();
}
You have the ng-model set to testDate but I don't see where you have set that in your controller. Try setting testDate = new Date(). See this relevant pull request
I had the same issue.
You should NOT initialize the bsDatePicker field with new Date(). You must initialize with 'null' from formbuilder, even if it is a required field.

ui.bootstrap.datepicker: decoupling "displayed date format" from "ng-model date format"

I'm new to Angular and to JS, therefore I'm sorry if my problem is quite trivial.
I'm using ui.bootstrap.datepicker to modify a date property of my foo model. My foo.date is a string like '2000-01-31'. What I want is to visualize foo.date in the form as January 31, 2000, while preserving 'foo.date' format to '2000-01-31'.
Here there is my datepiker:
<div class="input-group">
<input type="text"
class="form-control"
datepicker-popup="MMMM dd, yyyy"
ng-model="foo.date"
is-open="opened"
ng-required="true"
show-weeks = 'false'
close-text="Close" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="pdfc.open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</div>
If I set datepicker-popup to "MMMM dd, yyyy", the original date format of the model is broken. I see something like this:
"2000-01-31T00:00:00.000Z"
...instead of this:
2000-01-31
I read some related solutions like this one, but the directive.directive('datepickerPopup', function (){...} is "overridden" by datepicker-popup in the form.
In this plnkr you can see my problem in action. Is there a nice way to decouple those two date formats?
Use date filter. Here is what it can do.
First inject filter service to your controller:
.controller('myCtrl',['$filter','$scope',function($filter,$scope){//..}]);
If you have other services to inject, read about dependency injection.
Second, assign new variable with date filter.
var dateView = $filter('date')($scope.foo.date,'MMMM d, yyyy');
Then you can show it:
(Controller)
$scope.foo.fDate = dateView;
(View)
{{foo.fDate}}
To observe it after change, set watch on it:
$scope.$watch(function() { return $scope.foo.date; },
function(n,o){
var dateView = $filter('date')($scope.foo.date,'MMMM d, yyyy');
$scope.foo.fDate = dateView;
});
It will listen for changes and change it.
It is better to show it in another variable. Of course you can set in watch instead of fDate, foo.date, but you may help problem with manual editing label, because variable will be changed after one letter is written.

How do I make an Angular UI Datepicker NOT Required

I have a form with many fields, including several datepickers (Angular UI Bootstrap).
<div name="mainForm" ng-form>
<div class="form-group">
<p class="input-group">
<input type="text" name="dt"
class="form-control"
ng-model="dt"
is-open="opened"
datepicker-popup="MM/dd/yyyy" />
<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>
<p class="text-danger" ng-show="mainForm.$invalid">Invalid!</p>
</div>
I'm using Angular validation w/ the form. We have some required fields, but the dates are not. If you enter a date and remove it, it marks the form invalid. I created a Plunkr to demonstrate this.
Is there a way around this?
Note: It also logs this error in the console when you clear the date out.
Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.
In the current version of the code there is a $datepickerSuppressError value that you can set to true which will hide the console error. You can see in the code that it checks if the date is NaN and then displays the console error if $datepickerSuppressError is still false.
However, having said that, there is still a way to work around the issue of the form being invalid. You will just need to add an additional check to see if mainForm.$error.date is set, or something similar to this.
For example you can change your button to have this instead:
ng-disabled="mainForm.$invalid && !mainForm.$error.date"
Which will leave your button enabled even though the directive has set an error on the date and it should disable if any other field is invalid.

Angular UI datepicker not updating

I have tried to extend the UI datepicker with previous and next day buttons.
As you can see from the plunker I can change the model either by using the datepicker or the prev/next buttons. But when the model is changed with the prev/next buttons, the datepicker ist not updated.
http://plnkr.co/edit/k1flklFny5BoX6zdwyWJ?p=preview
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control"
datepicker-popup="{{ctrl.format}}" ng-model="ctrl.dt"
is-open="ctrl.opened" datepicker-options="ctrl.dateOptions"
ng-required="true" close-text="Close" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="ctrl.open($event)">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</div>
</div>
I tried several approaches already (including $scope and the demonstrated controller as syntax) but it simply does not work. Any ideas?
PS: I tried very hard to have prev button, datepicker, next button in one line, centered, the datepicker occupying just enough space it needs. If anyone has an idea how to accomplish that, any help is greatly appreciated.
I don't know why, but seems that ngModel doesn't react when Date object changed itself. But it changed if you assign to scope property new instance of Date.
Try this:
this.prevDay = function() {
this.dt = getPrevNextDate(this.dt, -1);
};
this.nextDay = function() {
this.dt = getPrevNextDate(this.dt, 1);
};
function getPrevNextDate(date, increment)
{
var newDate = new Date();
newDate.setDate(date.getDate() + increment);
return newDate;
}
And better to cache this into some variable like var self = this at top of controller function and use self variable instead of this
This way you will avoid error in this line:
$log.log('GET api/v1/person/' + this.person.id + '/entry returned: ' + data.length + ' entries')

Datepicker not binding formatted value

This is probably an easy question, but I'm having a problem with this datepicker. The problem is I set the format to dd/mm/yyyy with data-date-format attribute. However, when checking my ng-model the value is the following: Wed Jul 17 2013 00:00:00 GMT+0000 (Greenwich Standard Time)
What I want is it to bind to dd/mm/yyyy format.
How can I fix this?
Here is my code:
<label for="inputDateFrom">Frá</label>
<div class="control-group input-append">
<input type="text" ng-model="booking.Booking.DateFrom" data-date-format="dd/mm/yyyy" bs-datepicker>
<button type="button" class="btn" data-toggle="datepicker"><i class="icon-calendar"></i></button>
</div>
Update 18.07.13:
According to rGil's answer I tried to use $scope.$watch. It works fine but first it gets the CORRECT date (from getBooking() service function), then it changes to the CURRENT date - which is not the date.
JavaScript code is following:
$scope.$watch('booking.Booking.DateFrom', function(v){ // using the example model from the datepicker docs
$scope.booking.Booking.DateFrom = moment(v).format();
alert(moment(v).format());
});
$scope.$watch('booking.Booking.DateTo', function(v){ // using the example model from the datepicker docs
$scope.booking.Booking.DateTo = moment(v).format();
alert(moment(v).format());
});
// Sækjum staka bókun
if(bookingID != null) {
BookingService.getBooking(bookingID).then(function(data) {
$scope.booking = data.data;
$scope.booking.Booking.DateFrom = moment($scope.booking.Booking.DateFrom);
$scope.booking.Booking.DateTo = moment($scope.booking.Booking.DateTo);
});
}
Then my HTML is the following:
<label for="inputDateFrom">Frá</label>
<div class="control-group input-append">
<input type="text" ng-model="booking.Booking.DateFrom" data-date-format="dd-mm-yyyy" bs-datepicker>
<button type="button" class="btn" data-toggle="datepicker"><i class="icon-calendar"></i></button>
</div>
<label for="inputDateTo">Til</label>
<div class="control-group input-append">
<input type="text" ng-model="booking.Booking.DateTo" data-date-format="dd-mm-yyyy" bs-datepicker>
<button type="button" class="btn" data-toggle="datepicker"><i class="icon-calendar"></i></button>
</div>
Looking over the AngularStrap source code, I found that if you set the (seemingly undocumented) attribute date-type to any value outside of "Date" (for example: String) this prevents bs-datpicker from returning the selected date as a date object and solves the issue. So in this case it would be:
<input type="text" ng-model="booking.Booking.DateFrom" data-date-format="dd/mm/yyyy" date-type="string" bs-datepicker>
Tested on AngularStrap v0.7.4 and v0.7.5
This can easily be done without a plugin. Using this post you can create a $scope variable with the correct formatting.
Example:
$scope.$watch('datepicker.date', function(v){ // using the example model from the datepicker docs
var d = new Date(v);
var curr_date = d.getDate();
var curr_month = d.getMonth() + 1; //Months are zero based
var curr_year = d.getFullYear();
$scope.modDate = curr_date + "/" + curr_month + "/" + curr_year;
console.log($scope.modDate)
})
FORKED DEMO - open console
There are ways to do it in a more elegant way, with AngularJS. Just use the date filter Angular. Like this:
$filter('date')(date, "yy/MM/yyyy", date.getTimezoneOffset())
$filter('date') gets the angularjs filter that take in args, the date, the template and the timezone, and returns a well formatted string.
08/03/2016

Resources