Extend Angular-UI Datepicker directive - angularjs

I have been using the ui-datepicker from Angular-ui-bootstrap a lot, but every time I use it, I need to set it up, the same way I do every time.
So I was wondering if I could create a directive called custom-datepicker I could use like
<custom-datapicker>
So that I can set the settings in the directive once, and then reuse it everywhere on my site.
I tried to create a directive like this one below
app.directive('customDatapicker', function () {
return {
restrict: 'E',
require: 'ngModel',
templateUrl: function (elem, attrs) {
return '/AngularJS/Directives/customDatapicker.html'
},
link: function (scope, element, attrs, ngModel) {
$scope.inlineOptions = {
showWeeks: true
};
$scope.dateOptions = {
formatYear: 'yy',
startingDay: 1
};
$scope.open = function () {
$scope.opened = true;
};
$scope.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate'];
$scope.format = $scope.formats[0];
$scope.selected = {
opened: false
};
},
});
I am also trying to use a template, so that i can do some custom html wrapper around it. So far I have got nothing besides the sample html from
TemplateHTML
<p class="input-group">
<input type="text" class="form-control" uib-datepicker-popup="{{format}}" ng-model="ngModel" is-open="selected.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="open()"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
In the Template html I'm trying to make the binding between my directive's input model in the datepicker's ng-model by doing ng-mode='ngModel', which i don't think is the right way.
I use my directive in my html page like this, where data is a JS Date Object
<custom-datapicker ng-model='data'>
Can this be done?

Instead of using ng-model on your custom directive, define a custom attribute, then pass that value into the ng-model attribute of the datepicker.
<custom-datepicker customAttrib="val" ...
Then in the template:
<input ng-model="{{customAttrib}}" ...

Interestingly I have been looking at something very similar today. You can pass your model using a two way binding and it mostly works.
<my-datepicker ng-model="myDateModel"></my-datepicker>
Directive:
scope: {
ngModel: '='
}
Template:
<input type="text" ng-model="ngModel" />
The issue is that if you manipulate the model outside of using the datepicker the model classes (ng-valid, ng-touched, etc) on your directive don't update. The classes on the input and the form do...

Related

z-index not working in Angular UI Datepicker

In this plunk I have an Angular UI Datepicker inside a div (the div has orange background). The problem is that the Datepicker is truncated, even though I set z-index: 99999. If I remove from the div overflow-y:auto the Datepicker is shown, however I need the div to scroll when there's an overflow. How to fix this problem?
HTML:
<div style="height:200px;padding:30px;background-color:orange;overflow-y:auto">
<p class="input-group" style="z-index:99999">
<input type="text" class="form-control" ng-model="dt" is-open="config.opened"
uib-datepicker-popup popup-placement="top-left" 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>
Javascript:
var app = angular.module('app', ['ui.bootstrap']);
app.controller('ctl', function ($scope) {
$scope.opened = false;
$scope.dateOptions = {
showWeeks: false
};
$scope.open1 = function(){
$scope.opened = true;
};
});
app.directive('dir2', function () {
return {
restrict: 'EA',
scope: {
someVar: '='
},
templateUrl: 'dir2.html',
link: function (scope, element, attrs) {
scope.config = {};
scope.config.opened = true;
}
}
});
This is very common case with tooltip, datepicker or popover in such cases it is better choice to append the content to body so the current element styling doesn't matter. Basically in this case you could append datepicker to body by setting below datepikcer-append-to-body to true.
datepicker-append-to-body="true"
Don't go for setting z-index, it may work by tweaking few things, but it could unintentionally break other piece of software.
Plunker Demo

Creating a wrapper directive for Bootstrap-UI's uib-datepicker-popup

I'm trying to create a wrapper AngularJS directive for Bootstrap-UI's uib-datepicker-popup so I don't have to recreate a bunch of boilerplate each time I need to select a date. I've been working off an example I found here which was written for an earlier version of Angular, and am running into some oddities getting this working.
I've gotten the directive to a point where it displays a popup, however the two-way data binding seems to be broken; the date value in the field's model doesn't propagate into the directive, and when you click on the popup and select a date, it doesn't propagate back out. Does anyone have any ideas on what's going on here?
I've created a Plunker demonstrating the issue here.
Directive code:
app.directive('myDatepicker', function() {
return {
restrict: 'E',
scope: {
model: "=",
myid: "#"
},
templateUrl: 'datepicker.html',
require: 'ngModel',
link: function(scope, element) {
scope.popupOpen = false;
scope.openPopup = function($event) {
$event.preventDefault();
$event.stopPropagation();
scope.popupOpen = true;
};
scope.open = function($event) {
$event.preventDefault();
$event.stopPropagation();
scope.opened = true;
};
}
};
});
Template code:
<div class="row">
<div class="col-md-6">
<p class="input-group">
<input type="text" class="form-control" id="{{myid}}" uib-datepicker-popup ng-model="model" is-open="opened" ng-required="true" />
<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>
You're using ng-model in the directive code, but you're looking for model in the directive template.
<my-datepicker ng-model="selected" myid="someid"></my-datepicker>
And here you are looking for an attribute called model:
app.directive('myDatepicker', function() {
return {
restrict: 'E',
scope: {
//this line should be ngModel
model: "=",
myid: "#"
},
Here's a working plunker: https://plnkr.co/edit/s5CT4xGqXtUxgCH8vw8q?p=preview
In general, I try to avoid using names like "model" and "ng-model" on custom directives, as built-in angular attributes should be distinguished from custom attributes.

How do I get my dual binding to work properly with bootstrap datetime picker? [duplicate]

Here is the html for the date field :
<div class='form-group'>
<label>Check out</label>
<input type='text' ng-model='checkOut' class='form-control' data-date-format="yyyy-mm-dd" placeholder="Check out" required id="check-out">
</div>
<script>
$('#check-out').datepicker();
</script>
The datepicker shows up in the input field. However if I do this in my controller :
console.log($scope.checkOut);
I get undefined in the javascript console.
How to solve this ?
Is there a better way to use bootstrap-datepicker with angularjs ?
I don't want to use angular-ui/angular-strap since my project is bloated with javascript libraries.
As #lort suggests, you cannot access the datepicker model from your controller because the datepicker has its own private scope.
If you set: ng-model="parent.checkOut"
and define in the controller: $scope.parent = {checkOut:''};
you can access the datepicker using: $scope.parent.checkOut
I am using bootstrap 3 datepicker https://eonasdan.github.io/bootstrap-datetimepicker/ and angularjs, I had the same problem with ng-model, so I am getting input date value using bootstrap jquery function, below is the code in my controller, it's worked for me.
Html
<input class="form-control" name="date" id="datetimepicker" placeholder="select date">
Controller
$(function() {
//for displaying datepicker
$('#datetimepicker').datetimepicker({
viewMode: 'years',
format: 'DD/MM/YYYY',
});
//for getting input value
$("#datetimepicker").on("dp.change", function() {
$scope.selecteddate = $("#datetimepicker").val();
alert("selected date is " + $scope.selecteddate);
});
});
I just found a solution to this myself. I just pass in the model name to the directive (which I found most of online). This will set the value of the model when the date changes.
<input data-ng-model="datepickertext" type="text" date-picker="datepickertext" />{{datepickertext}}
angular.module('app').directive('datePicker', function() {
var link = function(scope, element, attrs) {
var modelName = attrs['datePicker'];
$(element).datepicker(
{
onSelect: function(dateText) {
scope[modelName] = dateText;
scope.$apply();
}
});
};
return {
require: 'ngModel',
restrict: 'A',
link: link
}
});
I am using Angular JS 1.5.0 and Bootstrap 3 Datetimepicker from https://eonasdan.github.io/bootstrap-datetimepicker/
After some time and struggling, I finally found a solution how to make it work for me :)
JSFiddle: http://jsfiddle.net/aortega/k6ke9n2c/
HTML Code:
<div class="form-group col-sm-4" >
<label for="birthdate" class="col-sm-4">Birthday</label>
<div class="col-sm-8">
<div class="input-group date" id="birthdate" ng-model="vm.Birthdate" date-picker>
<input type="text" class="form-control netto-input" ng-model="vm.Birthdate" date-picker-input>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
<div class="form-group col-sm-4">
<label for="birthdateText" class="col-sm-4">Model:</label>
<div class="col-sm-8">
<input type="text" class="form-control netto-input" ng-model="vm.Birthdate">
</div>
</div>
</body>
App.js:
Simply a controller setting the viewmodels Birtdate attribute:
var app = angular.module('exampleApp',[]);
app.controller('ExampleCtrl', ['$scope', function($scope) {
var vm = this;
vm.Birthdate = "1988-04-21T18:25:43-05:00";
}]);
The first directive is initializing the datetimepicker and listening to the dp.change event.
When changed - the ngModel is updated as well.
// DatePicker -> NgModel
app.directive('datePicker', function () {
return {
require: 'ngModel',
link: function (scope, element, attr, ngModel) {
$(element).datetimepicker({
locale: 'DE',
format: 'DD.MM.YYYY',
parseInputDate: function (data) {
if (data instanceof Date) {
return moment(data);
} else {
return moment(new Date(data));
}
},
maxDate: new Date()
});
$(element).on("dp.change", function (e) {
ngModel.$viewValue = e.date;
ngModel.$commitViewValue();
});
}
};
});
The second directive is watching the ngModel, and triggering the input onChange event when changed. This will also update the datetimepicker view value.
// DatePicker Input NgModel->DatePicker
app.directive('datePickerInput', function() {
return {
require: 'ngModel',
link: function (scope, element, attr, ngModel) {
// Trigger the Input Change Event, so the Datepicker gets refreshed
scope.$watch(attr.ngModel, function (value) {
if (value) {
element.trigger("change");
}
});
}
};
});
I have the same problem and resolve like this
added in html part
<input class="someting" id="datepicker" type="text" placeholder="Dae" ng-model=""/>
and simple in Controller call
$scope.btnPost = function () {
var dateFromHTML = $('#datepicker').val();
Have you tried AngularUI bootstrap? It has all the bootstrap modules rewritten in angular(including datepicker): http://angular-ui.github.io/bootstrap/
One of ways around: set the id field to the input, then call document.getElementById('input_name').value to get the value of the input field.
Using this datepicker I had the same problem. I solved it using a little trick.
In the inputs tag I added a new attribute (dp-model):
<input class="form-control dp" type="text" dp-model="0" />
<input class="form-control dp" type="text" dp-model="1" />
...
And then in the js file I forced the binding in this way:
$scope.formData.dp = []; // arrays of yours datepicker models
$('.dp').datepicker().on('changeDate', function(ev){
$scope.formData.dp[$(ev.target).attr('dp-model')] = $(ev.target).val();
});
This worked for me:
set ng-model="date"
on your angular controller:
$scope.date = '';
$('#check-out').datepicker().on('changeDate', function (ev) {
$scope.date= $('#check-out').val();
$scope.$digest();
$scope.$watch('date', function (newValue, oldValue) {
$scope.date= newValue;
});
});
My actual trouble was that the value of the model was not reflected till another component on the scope was changed.
im using this , and my code :
this.todayNow = function () {
var rightNow = new Date();
return rightNow.toISOString().slice(0,10);
};
$scope.selecteddate = this.todayNow();
$(function() {
//for displaying datepicker
$('.date').datepicker({
format: 'yyyy-mm-dd',
language:'fa'
});
//for getting input value
$('.date').on("changeDate", function() {
$scope.selecteddate = $(".date").val();
});
});
To solve this, I have my HTML looking like this:
<div class='input-group date' id='datetimepicker1'>
<input type='text' ng-model="date.arrival" name="arrival" id="arrival"
class="form-control" required />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
My ng-model wouldn't update, so I used this to fix it:
$("#datetimepicker1").on("dp.change", function (e) {
$scope.date.arrival = $("#arrival").val(); // pure magic
$('#datetimepicker2').data("DateTimePicker").minDate(e.date); // this line is not relevant for this example
});

Not getting value of input type created through a directive in angularJS

I am using a directive for datepicker in angularJS. Below is my code for directive. It works well and it shows datepicker when I add datepicker directive in a div.now I want to use the selected date in my form when I send data in controller and from controller I pass it to php api via $http. when I check the data in php it does not shows date. Rest all fields are working fine only the field created with directive is not showing the values. I am pasting the code for directive, controller and form.
app.directive('datepicker', function () {
return {
restrict: 'A',
controller: 'datepickerCtrl',
controllerAs: 'dp',
template: '<div id="dob" ng-controller="profileCtrl" dob class="input-group date" data-date-format="dd-mm-yyyy" ><input class="from_to_input" name="1" type="text" ng-class={inputError:dp.validDate==false} class="form-control input-sm" ng-model="profile.value"/><span class="input-group-addon"><span class="glyphicon glyphicon-th"></span></span></div>',
scope: {
'value': '='
},
link: function (scope, element, attribute) {
// scope.variable = attribute.value;
}
};
});
below is code for controller for datepicker
app.controller('datepickerCtrl', function ($scope) {
$('.date').datepicker({ autoclose: true, todayHighlight: true });
var inputDate = new Date(moment($scope.value));
$scope.value = moment(inputDate).format("DD-MM-YYYY");
$('.date').datepicker('setDate', inputDate);
$scope.$watch('value', function (newVal) {
});
});
below is code for my form page
<form name="profileForm" role="form">
<input type="email" id="" name="email" ng-model="profile.email" class="login_input_area" placeholder="Email">
<div class="col-xs-2" datepicker value="date2"></div>
<input type="submit" value="Submit" ng-click="saveprofile(profile)" class="submit_btn">
</form>
My friend!
Please check online video tutorials for Angular directives!
Anyway, in your directive you have ng-model="profile.value", that should be "value" I think
second: remove ng-controller="profileCtrl" from directive template. Directives has they own local scope.
third: I prefer using restrict: "E", so you can use as custom tag, more readable on my opinion
one more: scope: { value : "="} , not scope: { 'value' : "="}
couple more: remove both controller: 'datepickerCtrl', controllerAs: 'dp'

Angular Bootstrap Datepicker directive to minimize html elements

We are using Angular UI bootstrap implementation for date picker in our project. I need to write many HTML element for date picker, would it be a good idea to write a directive for such tasks? If yes please help me to provide sample code for any such directive.
<p class="input-group">
<input type="text" class="form-control" datepicker-popup ng-model="leaveSearch.td" is-open="$parent.dtLeaveToOpen" ng-required="true" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="datePickerOpen($event,'dtLeaveTo','dtLeaveToOpen')"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
How can wrap all this into single html element, I think using Angular directive we can achieve this. I am looking for similar idea.
Finally I wrote below directive which worked for me:
angularStartDirectives.directive('espireDate', function () {
return {
restrict: 'E',
scope: {
show: '=',
ngModel: '=',
ngClass: '=',
ngRequired:'='
},
replace: true, // Replace with the template below
transclude: true, // we want to insert custom content inside the directive
require: 'ngModel',
link: function (scope, element, attrs) {
scope.open = false;
scope.dpOpen = function () {
scope.open = true;
};
},
template: '<div><div class="input-group input-group-lg" ng-click="dpOpen()" >'
+ ' <input id="attrs.id" readonly="true" type="text" class="form-control" data-is-open="open" datepicker-popup data-ng-model="ngModel" ng-class="ngClass" ng-required="ngRequired" />'
+ ' <span class="input-group-addon">'
+ '<span class="glyphicon glyphicon-calendar"></span>'
+ '</span></div></div>'
};
});

Resources