Validate start date and end date on AngularJS Bootstrap date picker? - angularjs

I am new to Angular JS and I am trying to implement validation for date time picker in my Angular project.
I am using bootstrap date picker.
My HTML is :
<div>
<form id="edit-profile" novalidate name="editReservationForm" autocomplete="off" class="form-horizontal">
<fieldset>
<div class="control-group">
<label class="control-label" for="reservation.reservedFrom">Reserved From<sup>*</sup></label>
<div class="controls input-group date" data-provide="datepicker">
<input type="text" class="span4" style="width:150px" name="reservedFrom" placeholder="Reserved From" data-ng-model="reservation.reservedFrom"
validator="required" required-error-message="Date is required" valid-method="watch" id="startDate"/>
<div class="input-group-addon">
<span class="glyphicon glyphicon-th"></span>
</div>
</div> <!-- /controls -->
</div> <!-- /control-group -->
<div class="control-group">
<label class="control-label" for="reservation.reservedTill">Reserved Till<sup>*</sup></label>
<div class="controls input-group date" data-provide="datepicker">
<input type="text" style="width:150px" class="span4" name="reservedTill" placeholder="Reserved Till" data-ng-model="reservation.reservedTill"
validator="required" required-error-message="Date is required" valid-method="watch" id="endDate" ng-change='checkErr(startDate,endDate)'/>
<div class="input-group-addon">
<span class="glyphicon glyphicon-th"></span>
</div>
<span>{{errMessage}}</span>
</div> <!-- /controls -->
</div> <!-- /control-group -->
</fieldset>
</form>
</div>
My Controller is :
myApp.controller('editReservationController', ['$scope', '$filter', 'reservationResolved', 'pocResolved', 'accountResolved', 'reservationServices', '$location', '$state',
function ($scope, $filter, reservationResolved, pocResolved, accountResolved, reservationServices, $location, $state) {
$scope.reservation = new Object();
$scope.accounts = accountResolved.data;
$scope.pocs = pocResolved.data;
$scope.reservation.employee = reservationResolved.data;
$scope.updateReservation = function () {
if ($scope.editReservationForm.$valid) {
reservationServices.updateReservation($scope.reservation).then(function (result) {
$scope.data = result.data;
if (!result.data.error) {
$state.transitionTo('employeeTalentPool', {
id: $state.params.id
});
}
});
}
};
$scope.checkErr = function (startDate, endDate) {
$scope.errMessage = '';
var curDate = new Date();
if (new Date(startDate) > new Date(endDate)) {
$scope.errMessage = 'End Date should be greater than start date';
return false;
}
if (new Date(startDate) < curDate) {
$scope.errMessage = 'Start date should not be before today.';
return false;
}
};
$scope.cancel = function () {
$location.path("/reservations");
}
}]);
I am totally new to Angular and I'm trying to understand it by doing projects. Can anyone have a check and provide a solution?

There is no need to pass in the startDate and endDate variables into the ng-change method on your second datepicker; you are already tracking those variables on your $scope with ng-model.
$scope.checkErr = function() {
var start = new Date($scope.reservation.reservedFrom),
end = new Date($scope.reservation.reservedTill);
if (end < start) {
$scope.errorMsg = "End must be after start";
}
... other logic ...
};
Additionally, it may be best to just prevent a user from making bad choices.
The two errors you seem to want to guard against are: 1) the user chooses a startDate before today and 2) the user chooses an endDate before the startDate.
Both of the errors above can be prevented by modifying the minDate option within datepicker-options. Check out the $watch in this plunker -- each time we select a new start date, we can modify the minDate option for the end date and prevent user input issues.
Update (per request)
The plunker shows two datepickers, both of which have their own custom datepicker-options bound as $scope variables -- we'll be able to modify these datepicker-options to change the behavior of each datepicker.
Defaulting startDateOptions "minDate" to today (within the CTRL) makes it impossible for a user to pick a startDate before today (solving the first issue you were trying to prevent).
Placing a $watch on the startDate allows us to update the endDateOptions after any a change of the startDate. This allows us to restrict a users choices for the endDate input by setting minDate to whatever the startDate is (solving the second issue of choosing an endDate before a startDate).
There is also some logic in the $watch to adjust endDate where it makes sense (like if we first selected a valid endDate, but then selected a new startDate that would make that endDate invalid).

Related

issue with converting date and time to millisecond format in angularjs

I am working on an angularjs web application which uses REST layer to communicate with the backend. I have to display the date and time of a job but I receive it in milliseconds format. How do I convert the value to display the date and time on the UI.
1479982860000 // input
11/24/16 //output date
10:21 AM //output time
Both have to be stored in DataModel.date and DataModel.time.
Also the user enters a date and a time which I have to combine and send it in the same milliseconds format to the REST layer. How do I do that?
<input type="time" id="exampleInput1" ng-model="DataModel.time"
placeholder="HH:mm:ss" required/>
<input type="date" id="exampleInput2" ng-model="DataModel.date"
placeholder="yyyy-mm-dd" required/>
I have to combine the two and send it as Datamodel.date in the controller. Please help.
According to the documentation, you can convert the value in your controller.
$scope.date = new Date($scope.DataModel.time);
$scope.date= $filter('date')(new Date($scope.DataModel.time), 'yyyy-mm-dd');
and the view:
<input type="date" id="exampleInput2" ng-model="date" placeholder="yyyy-mm-dd" required/>
Don't forget to add $filter in your dependencies:
app.controller('YourController', ['$scope','$filter', function($scope, $filter) {
}]);
[This may work for your issue]
https://docs.angularjs.org/api/ng/filter/date
Here is a simple example to achieve what you need,
use
(new Date($scope.milli_seconds)) to get the full date.
(new Date($scope.milli_seconds)).toDateString() to get the date from it
(new Date($scope.milli_seconds)).toTimeString() to get the time from it
(new Date($scope.milli_seconds)).getTime() to convert bact to milliseconds
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
"milliseconds" : {{milli_seconds}} <br>
"full_date" : {{full_date}} <br>
"date" : {{date}} <br>
"time" : {{time}} <br>
"millisecondsreverse" : {{milli_seconds_reverse}} <br>
<br><br>
<input type="time" id="exampleInput1" ng-model="DataModel.time"
placeholder="HH:mm:ss" required/>
<input type="date" id="exampleInput2" ng-model="DataModel.date"
placeholder="yyyy-mm-dd" required/>
<input type="submit" ng-click="submit_values()" value="getmilliseconds"/> <br>
<span ng-if="milli">Your milliseconds: {{milli}}</span>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.DataModel = {}
$scope.milli_seconds = 1479982860000;
$scope.full_date = (new Date($scope.milli_seconds))
$scope.date = $scope.full_date.toDateString()
$scope.time = $scope.full_date.toTimeString()
$scope.milli_seconds_reverse = $scope.full_date.getTime();
$scope.submit_values = function()
{
date = new Date($scope.DataModel.time).toTimeString()
time = new Date($scope.DataModel.date).toDateString()
date_time = (new Date($scope.DataModel.date).toDateString())+" "+ (new Date($scope.DataModel.time).toTimeString())
alert(new Date(date_time).getTime());
$scope.milli = new Date(date_time).getTime();
}
});
</script>
</body>
</html>
Please run the above snippet
You can just convert it into different formats you like, using the filters.
Here is a fiddle
Have a look at moment.js
Add configuration in your JS file
/*Configuration to change the date format*/
angular.module('myapp')
.config(function($mdDateLocaleProvider) {
$mdDateLocaleProvider.formatDate = function(date) {
return date ? moment(date).format('DD/MM/YYYY') : '';
};
$mdDateLocaleProvider.parseDate = function(dateString) {
var m = moment(dateString, 'DD/MM/YYYY', true);
return m.isValid() ? m.toDate() : new Date(NaN);
};
})
Change the format which ever way you want
var newFormatDate =moment(oldFormatDate).format();
EDITS
If you want to set specific timezone,
moment().tz("America/Los_Angeles");
MOMENT.JS DOCS
Also look at timezone identifier

Date picker validation in angularJS not working

I am trying to implement validations for my date time picker. I have a 'From' date picker and a 'To' datepicker in an Angular partial view. I want the 'From' date picker to display error message if a past date is selected and the 'To' date picker should display error message if the selected date is before the 'From' date. The error messages are supposed to appear on selection of the date.
My HTML is :
<div>
<form id="edit-profile" novalidate name="editReservationForm" autocomplete="off" class="form-horizontal">
<fieldset>
<div class="control-group">
<label class="control-label" for="reservation.reservedFrom">Reserved From<sup>*</sup></label>
<div class="controls input-group date" data-provide="datepicker">
<input type="text" class="span4" style="width:150px" name="reservedFrom" placeholder="Reserved From" ng-model="reservation.reservedFrom"
validator="required" required-error-message="Date is required" valid-method="watch" id="startDate" />
<div class="input-group-addon">
<span class="glyphicon glyphicon-th"></span>
</div>
</div> <!-- /controls -->
</div> <!-- /control-group -->
<div class="control-group">
<label class="control-label" for="reservation.reservedTill">Reserved Till<sup>*</sup></label>
<div class="controls input-group date" data-provide="datepicker">
<input type="text" style="width:150px" class="span4" name="reservedTill" placeholder="Reserved Till" ng-model="reservation.reservedTill"
validator="required" required-error-message="Date is required" valid-method="checkErr" id="endDate" ng-change='checkErr()' />
<div class="input-group-addon">
<span class="glyphicon glyphicon-th"></span>
</div>
<span>{{errMessage}}</span>
</div> <!-- /controls -->
</div> <!-- /control-group -->
</fieldset>
</form>
</div>
Controller :
myApp.controller('editReservationController', ['$scope', '$filter', 'reservationResolved', 'pocResolved', 'accountResolved', 'reservationServices', '$location', '$state',
function ($scope, $filter, reservationResolved, pocResolved, accountResolved, reservationServices, $location, $state) {
$scope.reservation = new Object();
$scope.accounts = accountResolved.data;
$scope.pocs = pocResolved.data;
$scope.reservation.employee = reservationResolved.data;
$scope.updateReservation = function () {
if ($scope.editReservationForm.$valid) {
//TODO: fix it properly
$scope.reservation.reservedTill = '';
$scope.reservation.reservedFrom = '';
$scope.reservation.reservedFrom = $('#startDate').val();
$scope.reservation.reservedTill = $('#endDate').val();
reservationServices.updateReservation($scope.reservation).then(function (result) {
$scope.data = result.data;
if (!result.data.error) {
$state.transitionTo('employeeTalentPool', {
id: $state.params.id
});
}
});
}
};
$scope.cancel = function () {
$location.path("/reservations");
};
$scope.checkErr = function () {
var startDate = new Date($scope.reservation.reservedFrom),
endDate = new date($scope.reservation.reservedTill);
$scope.errMessage = '';
if (startDate < new Date()) {
$scope.errMessage = 'Start Date should be greater than or equal today';
return false;
}
if (new Date(endDate) < new Date()) {
$scope.errMessage = 'End Date should be greater than or equal today';
return false;
}
if (endDate < startDate) {
$scope.errorMsg = "End must be after start";
return false;
}
return true;
};
}]);
I am totally new to Angular and I'm trying to understand it by doing projects. Can anyone have a check and provide a solution?
Thanks in advance...
A different approach without displaying any error message and satisfying selection criteria as mentioned in problem statement
Here is the plunker of working solution bit slightly different from your implementation,I've used bootstrap datepicker for this example which is almost similar to datetimepicker. Hope this will give you an understanding.
In the controller we can control when and what from and to dates should be disabled on their corresponding selection.Using minDate provided by datepicker we can change the min date of To date field to From date's.
By doing this we can eliminate the display of error message and which will also satisfy your selection criteria of From & To dates.
angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('DatepickerPopupDemoCtrl', function($scope) {
$scope.datePicker = {};
$scope.start = new Date();
$scope.end = new Date();
$scope.datePicker.minStartDate = new Date();
// $scope.datePicker.maxStartDate = $scope.end;
$scope.datePicker.minEndDate = $scope.start;
// $scope.datePicker.maxEndDate = $scope.end; //fixed date same as $scope.maxStartDate init value
// watcher to watch the "From" date and set the min date for 'To' datepicker
$scope.$watch('start', function(v) {
$scope.datePicker.minEndDate = v;
$scope.dateOptions2.minDate = v;
});
$scope.dateOptions1 = {
//dateDisabled: disabled,
formatYear: 'yyyy',
// maxDate: $scope.datePicker.maxStartDate,
minDate: $scope.datePicker.minStartDate,
startingDay: 1
};
$scope.dateOptions2 = {
//dateDisabled: disabled,
formatYear: 'yyyy',
// maxDate: $scope.datePicker.maxEndDate,
minDate: $scope.datePicker.minEndDate,
startingDay: 1
};
// Disable weekend selection
function disabled(data) {
var date = data.date,
mode = data.mode;
return mode === 'day' && (date.getDay() === 0 || date.getDay() === 6);
}
$scope.open1 = function() {
$scope.popup1.opened = true;
};
$scope.open2 = function() {
$scope.popup2.opened = true;
};
$scope.formats = ['dd.MM.yyyy'];
$scope.format = $scope.formats[0];
$scope.altInputFormats = ['M!/d!/yyyy'];
$scope.popup1 = {
opened: false
};
$scope.popup2 = {
opened: false
};
});
In your HTML you can display like below
<div ng-controller="DatepickerPopupDemoCtrl">
<h5>From Date</h5>
<p class="input-group">
<input type="text"
class="form-control"
uib-datepicker-popup="{{format}}"
ng-model="start"
is-open="popup1.opened"
datepicker-options="dateOptions1"
close-text="Close"
readonly="true" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open1()">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</p>
<hr>
<h5>To Date</h5>
<p class="input-group">
<input type="text"
class="form-control"
uib-datepicker-popup="{{format}}"
ng-model="end"
is-open="popup2.opened"
datepicker-options="dateOptions2"
close-text="Close"
readonly="true"/>
<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>

angular date input (html) model (value) does not get updates when input is changed

H have 2 angular date inputs. dateFrom and DateTo. they are both date objects but when i change the input to another day, the scope still shows the "new Date" value... not the updated value?
JS
//set dates
$scope.getFromDate = function() {
$scope.dateFrom = new Date();
}
$scope.getToDate = function() {
$scope.dateTo = new Date();
}`
VIEW
<div>
<label class="item item-input" style="margin-left:0">
<span class="input-label">van</span>
<input type="date" ng-model="dateFrom" ng-init="getFromDate()">
</label>
<label class="item item-input" style="margin-left:0">
<span class="input-label">tot</span>
<input type="date" ng-model="dateTo" ng-init="getToDate()">
</label>
{{dateFrom}}
later in another function i send the dateFrom and dateTo variable as follow
$scope.getComp = function() {
var dateTo = $scope.dateTo.getDate()+'-'+$scope.dateTo.getMonth()+1+'-'+$scope.dateTo.getFullYear();
var dateFrom = $scope.dateFrom.getDate()+'-'+$scope.dateFrom.getMonth()+1+'-'+$scope.dateFrom.getFullYear();
but even if I have changed the to inputs on the view to another dates.. dateFrom and dateTo still show the "current" date?
You don't need ng-init in your inputs.
Also date input expects a date in yyyy-MM-dd format so it's better to initialize it with $scope.dateFrom = $filter("date")(new Date(), 'yyyy-MM-dd');
So simply:
function Ctrl($scope, $filter) {
$scope.dateFrom = $filter("date")(new Date(), 'yyyy-MM-dd');
$scope.dateTo = $filter("date")(new Date(), 'yyyy-MM-dd');
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<div ng-app>
<div ng-controller="Ctrl">
<label class="item item-input" style="margin-left:0">
<span class="input-label">van</span>
<input type="date" ng-model="dateFrom">
</label>
<div>dateFrom : {{dateFrom}}</div>
<Br/>
<label class="item item-input" style="margin-left:0">
<span class="input-label">tot</span>
<input type="date" ng-model="dateTo">
</label>
<div>dateTo : {{dateTo}}</div>
</div>
</div>

Angular expression in text input "value"

I have a form that user will have to fill in. Some fields are dates and i don't want user to have to type in today's date.
My Form
<div class="row" ng-controller="JobOrderController as jOrder">
<form class="form-inline" ng-submit>
<div class="form-group">
<label for="todaysDate"><h4><span class='glyphicon glyphicon-flag'></span> Date</h4>Date </label>
<input type="text" class="form-control" id="todaysDate" ng-model="jOrder.orderData.date" value="{{ 2 + 4 }}" >
</div>
......... more code .........
My Controller
angular.module('jobOrderCtrl', ['jobOrderService'])
.controller('JobOrderController', function(Jobs, socketio) {
var vm = this;
vm.createOrders = function() {
vm.message = '';
Jobs.createOrders(vm.orderData)
.success(function(data) {
vm.orderData = '';
vm.message = data.message;
});
};
});
I try out using js to write to that date input field, but is not showing due to angular data binding.
So what i want is the date input value field to be today's date. So how do i go about and do this?
Where do you set the date?
orderData should be an object with the form fields - NOT a string
initialize the orderData:
var vm = this;
vm.orderData = { date : new Date()};
and remove the value property form the html input field. Also set type to date
<input type="date" class="form-control" id="todaysDate" ng-model="jOrder.orderData.date" >

Multiple regular expression pattern on one text area in angular js

I have a text area field where it inputs 4 types of personal details separated by commas. I need to validate each of those 4 values using regular expression. This is my approach but it is not much of the angular way to do the validations.
var form = angular.module('form', []);
form.controller('helloController', ['$scope', function($scope){
var submitted = false;
var validNumber = new RegExp('numberRegExp');
var validArea = new RegExp('areaRegExp');
var validCity = new RegExp('cityRegExp');
$scope.submit = function(hello){
$scope.number = false;
$scope.area = false;
$scope.city = false;
if (issue){
$scope.submitted = true;
var splittedDetails = hello.details.split(",");
var trimmedDetails = $.map(splittedDetails, $.trim);
if (!validNumber.test(trimmedDetails[0])) {
$scope.inputversion.jiraIssue.$invalid = true;
$scope.number = true;
}else if (!validArea.test(trimmedDetails[1])) {
$scope.inputversion.jiraIssue.$invalid = true;
$scope.area = true;
}else if (!validCity.test(trimmedDetails[2])) {
$scope.inputversion.jiraIssue.$invalid = true;
$scope.city = true;
}else{
alert("Form now submitting");
}
}
};
}]);
<form class="form-horizontal" name="helloForm" ng-controller="helloController" ng-submit="submit(hello)" novalidate ng-app="form">
<div class="form-group" ng-class="{ true:'has-error'}[submitted && helloForm.personal-details.$invalid]">
<label for="helloForm" class="col-sm-2 control-label">Details</label>
<div class="col-sm-10">
<textarea class="form-control" rows="5" ng-model="hello.details" placeholder="number, area, city, details ex: 90********, XYX, XYZ" name="personal-details" required></textarea>
<p ng-show="submitted && helloForm.personal-details.$error.required" class="help-block"> Details are required.</p>
<p ng-show="submitted && number" class="help-block">Please check the format of issue number</p>
<p ng-show="submitted && area" class="help-block">Please check the format of product area</p>
<p ng-show="submitted && city" class="help-block">Please check the format of priority</p>
</div>
</div>
</form>
This approach can validate only one detail at a time. But ideally it should validate dynamically in much of the angular way. Please suggest your ideas.
Thanks
No offense, but this seems like a really bad way to validate 3 bits of expected data. Comma delimiting will only work if and only if the user puts 2 and only 2 commas into the field.
Assuming you want persisted data from the form (transfers from one page to another) you will want a Model for this module. The best way to do this is via the .service (since there is only one instance of each named service in a module in Angular). I'll also be using the format that will actually work with minified code and best practices, careof John Papa.
It also assumes you have declared the module elsewhere (declare uses brackets [] while recall does not).
angular.module('form')
.service("DataService", DataService)
DataService.$inject = ["$rootScope"];
function DataService($rootScope) {
var vm = this; //security in declaring (root)scope objects
vm.phone = {value: '', placeholder: 'Enter your phone number'};
vm.area = '';
vm.city = '';
};
Your controller would have little in it aside from the use of the $scope/$rootScope variables (with 2-way binding to fields and the Model) and your submit function for when the user tries to submit.
angular.module('form')
.controller('FormController', FormController);
FormController.$inject = ['$scope', 'DataService'];
function FormController($scope, DataService) {
var vm = this;
vm.phone = DataService.phone;
vm.area = DataService.area;
vm.city= DataService.city;
function submit() {
//persist the data to the next page/controller/etc.
DataService.number = vm.number;
DataService.area = vm.area;
DataService.city = vm.city;
//do work here
};
You can do all of your validation within your HTML, using Angular's 2-way binding of data. Assuming you're also using BootStrap, each field should look similar to the below:
<!-- phone field (required/validated) -->
<div class="row form-group" ng-class="{'has-warning': helloForm.phone.$invalid && helloForm.phone.$dirty,'has-error': helloForm.phone.$error.required && helloForm.phone.$touched}">
<label for="phone" class="col-md-3 control-label">Phone:</label>
<div class="col-md-9">
<input type="text" id="phone" name="phone" ng-model="vm.phone.value" placeholder="{{vm.phone.placeHolder}}" value="{{vm.phone.value}}" ng-required="true"class="skinny form-control" ng-pattern="/^\+?[-0-9)(]{8,31}[0-9x]{0,6}$/i" />
<p class="required" ng-show="helloForm.phone.$invalid || helloForm.phone.$error.required">*</p>
<p class="good" ng-show="helloForm.phone.$valid">✔</p>
</div>
<p class="help-block" ng-show="helloForm.phone.$error.pattern && helloForm.phone.$dirty">Phone format: +15558675309x52 or (555)867-5309x52</p>
<p class="help-block" ng-show="helloForm.phone.$error.required && helloForm.phone.$touched">Phone is a required field</p>
</div><br />
Rather than my E.164 (for international numbers) and American Standard phone combination validation (regex inside the ng-pattern field), you can use curly braces to declare your variable regex comparable. I hope this helps or at least points you in the right direction.
Thanks for reading,
C§

Resources