I am new to Angular 1 and need to implement Angular date picker to allow only year picker (graduation year) it should be from current year till 1950.
I tried using jQuery but it did not work and it seems its not compatible with Angular.
Please suggest how to implement it in Angular 1.5. The current implementation is from hard coded JSON object.
I made this plnkr for you, hope that helps you.
Two inputs, with bootstrap.
<input type="text" class="form-control date" id="from" placeholder="From" ng-click="app.dateFrom=true" datepicker-popup="{{app.format}}" ng-model="app.dtFrom" is-open="app.dateFrom" min-date="1970-04-06" max-date="'2017-04-06'" datepicker-options="myapp.dateOptions"
date-disabled="disabled(date, mode)" ng-required="true" close-text="Close">
<input type="text" class="form-control date" id="to" placeholder="To" ng-click="app.dateTo=true" datepicker-popup="{{app.format}}" ng-model="myapp.dtTo" is-open="app.dateTo" min-date="1970-04-06" max-date="'2017-04-07'" datepicker-options="app.dateOptions"
date-disabled="disabled(date, mode)" ng-required="true" close-text="Close">
And the script
angular.module('myapp', ['ui.bootstrap']);
angular.module('myapp').controller('myappCtrl', function() {
self = this;
self.someProp = 'Calendar'
self.opened = {};
self.open = function($event) {
$event.preventDefault();
$event.stopPropagation();
self.opened = {};
self.opened[$event.target.id] = true;
// log this to check if its setting the log
console.log(self.opened);
};
self.format = 'dd-MM-yyyy'
});
Regards!!
http://plnkr.co/edit/dphcFn4ghgCQqPqRxUhi?p=preview
You would need to make a directive as below
var app = angular.module('myApp', []);
app.directive('datepicker', function () {
return {
restrict: 'C',
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
$(element).datepicker({
dateFormat: 'dd, MM, yy',
onSelect: function (date) {
scope.date = date;
scope.$apply();
}
});
}
Y};
});
Taken from How to use datepicker in AngularJS using custom directive as a class?
Related
I have an app written in Angular 1.5.3.
Here is what I want to do:
I have a user form with 2 date input types. I need to add some custom validation to my form. I want to show an error message to the user when the "expiry date" on the form is greater than the "effective date" on the form.
I believe that I can do this with a custom directive and with ng-messages.
Here is my code snippet:
<form name="form.mainForm">
<div>
<span>Effective Date: </span>
<input required type="date" name="effectiveDate" ng-model="effectiveDate" />
<div>
<span>Expiry Date: </span>
<input
type="date"
name="expiryDate"
ng-model="expiryDate"
date-greater-than="{{ effectiveDate }}" />
</div>
</div>
</form>
app.directive('dateGreaterThan', function () {
return {
restrict: 'A',
require: 'ngModel',
scope: false,
link: function (scope, elm, attrs, ctrl) {
console.log(' here we are ');
function isValidDateRange(expiryDate, effectiveDate) {
console.log(expiryDate, effectiveDate);
if (effectiveDate == null || expiryDate == null ) {
return true;
}
return effectiveDate > expiryDate;
}
function validateDateRange(inputValue) {
var expiryDate = inputValue;
var effectiveDate = scope.effectiveDate;
var isValid = isValidDateRange(expiryDate, effectiveDate);
console.log("isValid: ", isValid);
ctrl.$setValidity('dateGreaterThan', isValid);
return inputValue;
}
ctrl.$parsers.unshift(validateDateRange);
ctrl.$formatters.push(validateDateRange);
attrs.$observe('dateGreaterThan', function () {
validateDateRange(ctrl.$viewValue);
});
}
};
I have attempted to solve the problem here but I can't get my directive to work properly. It doesn't seem to calculate the dates when they change and it doesn't integrate with ng-messages.
Here's my attempt:
http://jsfiddle.net/aubz88/q7n3abre/
The ngMessages module should be loaded from a cdn. Or installed with a package manager.
The ngMessages module is not included in AngularJS. https://code.angularjs.org/1.4.14/docs/api/ngMessages
var app = angular.module("hello", ['ngMessages']);
Some other points. Use the $validators from the ngModel.
ctrl.$validators.dateGreaterThan = validateDateRange;
Pass the other date with a scope property
scope: {dateGreaterThan: '='},
There is still a lot to improve I think. I did forgot some AngularJS stuff too.
f.e.: you could trigger the validation again when the first date changes. Check the $validate function of https://code.angularjs.org/1.4.14/docs/api/ng/type/ngModel.NgModelController .
You can check this fiddle for a basic setup: http://jsfiddle.net/hcjLkuzt/
I've got a simple directive 'wrapper' for a bootstrap datepicker widget.
module.exports = function () {
return {
restrict: 'E',
scope: {
dateModel: '=',
srText: '#',
minDate: '=',
maxDate: '=',
fieldName: '#',
formError: '=',
fieldError: '=',
inputRequired: '=',
validPattern: '='
},
replace:true,
template:
['<div class="pk-lp-calendar">',
'<input type="text"',
'name="{{fieldName}}"',
'id="{{fieldName}}"',
'remove-default-formatter',
'class="form-control"',
'datepicker-popup="MMM-yyyy"',
'datepicker-options="dateOptions"',
'datepicker-mode="\'year\'"',
'min-mode="\'month\'"',
'ng-model="dateModel"',
'is-open="opened"',
'min-date="minDate"',
'max-date="maxDate"',
'show-button-bar="false"',
'close-text="Close"',
'ng-required="inputRequired"',
'ng-pattern="validPattern"',
'ng-class="{\'invalidField\' : formError && fieldError}" />',
'<a href=""',
'class="gb-calendarIcon" ng-click="open($event)">',
'<span class="sr-only" ng-bind="srText"></span>',
'</a>',
'</div>'].join(' '),
controller:['$scope', function($scope){
$scope.date = $scope.dateModel;
$scope.open = function($event) {
console.log($scope.formError + ' : ' + $scope.fieldError);
$event.preventDefault();
$event.stopPropagation();
$scope.opened = !$scope.opened;
};
$scope.dateOptions = {
formatYear: 'yyyy',
startingDay: 1,
minMode: 'month',
datepickerMode: 'year'
};
}]
};
};
The text input field that is in the template needs to be validated if the user types the date rather than using the datepicker popup. It is required and has to be in the format mmm-yyyy. I'm passing in ng-pattern and ng-required to the directive's isolate scope (inputRequired and validPattern). The html looks like:
<lp-monthpicker date-model="goalModel.startDate" min-date="minimumStartDate"
form-error="goalModel.formError" field-name="startDateInput"
field-error="lpBuildGoalForm.startDateInput.$invalid"
input-required="true"
valid-pattern="goalModel.dateMatch">
</lp-monthpicker>
<div class="pk-lp-validationError" ng-show="goalModel.formError && lpBuildGoalForm.startDateInput.$invalid">Please complete goal form</div>
The regexp is:
goalModel.dateMatch =
/^(jan|Jan|JAN|feb|Feb|FEB|mar|Mar|MAR|apr|Apr|APR|may|May|MAY|jun|Jun|JUN|jul|Jul|JUL|aug|Aug|AUG|sep|Sep|SEP|oct|Oct|OCT|nov|Nov|NOV|dec|Dec|DEC)-(20\d\d)$/;
The node that gets rendered in the browser for the input field shows that the code is working - this is the rendered node from chrome:
<input type="text" name="startDateInput" id="startDateInput" remove-default-formatter=""
class="form-control ng-isolate-scope ng-valid-date ng-valid-required ng-invalid ng-invalid-pattern ng-dirty ng-valid-parse ng-touched"
datepicker-popup="MMM-yyyy" datepicker-options="dateOptions" datepicker-mode="'year'" min-mode="'month'" ng-model="dateModel" is-open="opened"
min-date="minDate" max-date="maxDate" show-button-bar="false" close-text="Close"
ng-required="inputRequired"
ng-pattern="/^(jan|Jan|JAN|feb|Feb|FEB|mar|Mar|MAR|apr|Apr|APR|may|May|MAY|jun|Jun|JUN|jul|Jul|JUL|aug|Aug|AUG|sep|Sep|SEP|oct|Oct|OCT|nov|Nov|NOV|dec|Dec|DEC)-(20\d\d)$/"
ng-class="{'invalidField' : formError && fieldError}"
required="required">
the default value from the 2 way binding for the datepicker is "Apr-2020". I get 'ng-invalid-pattern' right off the bat with the default. If I delete the text in the field it changes to ng-valid-pattern (weird). I've tested my regexp in 3 different online testing tools and it appears to be good. My ng-required works, ng-model works, ng-class works as expected. Is there some quirk with angular that I'm missing? I'm using another ng-pattern to validate a currency field and it works fine, but isn;t inside an isolate scope. Could that be the problem? Any help would be appreciated!
Thanks
In my current project I'm using this calendar.js javascript library together AngularJS.
I'm bind calendar.js widget and AngularJS ng-model to my input field in this way:
<input class="vDateField" type="text" ng-model="date" ng-init="date='{{ form.date.value | default_if_none:"" }}'"
vDateField is the class that bing calendars and {{ }} are backend template engine tags.
My problem is when I select the date with calendarjs picker, my input fied is updated but ng-model "date" doesn't.
Is there any solutions without modify calendarjs widget??
Here the rendered input tag:
<div>
<label class="required" for="id_date">Data contratto</label>
<input class="vDateField ng-pristine ng-valid ng-touched" type="text" ng-model="date" ng-init="date=''" name="date" placeholder="02/02/2015">
<span class="datetimeshortcuts"> Oggi | <img src="/static/admin/img/icon_calendar.gif" alt="Calendario"></span>
</div>
Here the javascript sources of the picker. DateTimeShortCuts.js contains the code for display mini link to setup current date time to my input field and a mini calendar icon to open up calendar widget.
I register the widget by adding class="vDateField" to my input tag as shown below.
DateTimeShortCuts.js
calendar.js
Had this same problem, solved it like this (example with jquery datepicker)
$('#myDateInput').datepicker({
dateFormat: 'yy-mm-dd',
onSelect: function (dateText) {
updateDate(dateText);
},
onClose: function (dateText) {
updateDate(dateText);
}
});
function updateDate(dateText) {
var date = angular.element('#myDateInput').val();
angular.element('#myDateInput').val(date);
if (dateText) {
$scope.object.date = dateText;
}
$scope.object.dateReadable = date;
$scope.safeApply(function (childScope) { });
}
// safely apply changes to the $scope
$scope.safeApply = function (fn) {
var phase = this.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
if (fn && (typeof (fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
Set date on page load
$("#myDateInput").datepicker("setDate", $scope.dateReadable);
HTML
<div class="form-group">
<label for="date" class="control-label">Date:</label>
<input type="date" name="date" id="myDateInput" class="form-control" />
</div>
The important thing here is that I use SafeApply to apply the changes to the $scope. Hope the example helps even tough it's a working sample for me.
Why do I have to do this? Well angular isn't aware of what happens outside its $scope, in this case jQUery. So we will have to tell it manually.
EDIT:
It might be a bit confusing with date and dateReadable but ignore the details and look at the safeApply that binds the changes to the $scope.
It will be helpful if you ask your question in more detail. However have you tried ng-init="date='{{ form.date.value | default_if_none:"" }}'" before input element?
I've solved with this directive and by set $('widget_element').trigger('change') on a callback function of 3d-part widget.
In this case, the widget is default Django Admin date widget.
contract_form_app.directive('vDateField', [function() {
return {
require: "ngModel",
restrict: "A",
link: function(scope, element, attrs, ngModelCtrl) {
element.addClass("vDateField");
var updateModel = function (dateText) {
scope.$apply(function () {
ngModelCtrl.$setViewValue(dateText);
});
};
django.jQuery('input').on('change', function() {
updateModel(element.val());
});
}
};
}]);
I'm using angular-ui datepicker and currently have the settings declared in a controller, eg:
$scope.date = new Date();
$scope.open = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened = true;
};
In order to be DRY, I want to declare this in one place, so that the datepicker can be used anywhere, without having to declare the settings each time.
I've tried putting them into a factory that would be injected into a controller, but with no success. I'm quite new to building factories/services.
I found this SO question that mentions declaring the settings under the config method, like this:
.config(['datepickerConfig', function(datepickerConfig) {
datepickerConfig.showWeeks = false;
}]);
But this doesn't work for me for some reason.
How can I declare the datepicker settings in once place to be used globally, or for injection?
To declare datepicker in 'one place' for easy re-use, I built a factory for the data/config:
.factory('datepickerService', function() {
var factory = {};
factory.date = new Date();
factory.open = function($event) {
$event.preventDefault();
$event.stopPropagation();
this.opened = true;
};
return factory;
});
Then a datepicker controller that injects the datepickerService, hooking the $scope up with the factory config.
.controller('datepickerCtrl', function ($scope, datepickerService) {
$scope.date = datepickerService.date;
$scope.open = datepickerService.open;
});
A directive:
.directive('supermanDatepicker', function () {
return {
templateUrl:'views/partials/datepicker.html'
};
});
HTML partial template with the standard ui-boostrap datepicker (but declaring the controller)
<div class="input-group" ng-controller="datepickerCtrl">
<input type="text"
class="form-control"
datepicker-popup="{{format}}"
ng-model="shortDate"
placeholder="dd-mm-yyyy"
is-open="opened"
min-date="minDate"
datepicker-options="dateOptions"
date-disabled="disabled(date, mode)"
ng-required="true"
close-text="Close" />
<span class="input-group-btn">
<button type="button"
class="btn"
ng-click="open($event)">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</div>
Then finally, it can be plugged into any view:
<div superman-datepicker></div>
Problem Question - I am trying to build a directive for the datepicker. But somehow it is not showing the calender popup box. I have tried and looked into most of the post out there. I know it something simple but can't figure this out. Below is my directive
angular.module('App').directive('myDatePicker',function(){
return{
restrict: 'AE',
template:'<input is-open="opened" type="text" datepicker-popup="d/m/yyyy" ng-model="Date" ng-required="true" />'+
'<button type="button" ng-click="open()"></button>',
controller: function($scope){
$scope.open = function () {
$scope.opened = true;
console.log('I am working');
};
}
};
});
HTML
<div my-date-picker></div>
Please guide me where I am making mistake.