In this plunk I have an Angular UI date picker and a message that should be shown only when the date is valid. The problem is that the message is always shown, even when form.$valid is true. Note that if you enter a valid or invalid date and then click on Validate, an alert will display correctly that the date is valid or invalid respectively.
Why is the validation message shown all the time, even when form.$valid is true?
Javascript
var app = angular.module('ui.bootstrap.demo', ['ui.bootstrap']);
app.controller('ctl', function ($scope) {
$scope.dtFrom = new Date ();
$scope.config1 = {};
$scope.config1.opened = false;
$scope.open1 = function(event){
event.preventDefault();
event.stopPropagation();
$scope.config1.opened = true;
};
$scope.validate = function(form){
if (!form.$valid) {
alert("Date invalid");
}
else {
alert("Date valid");
}
}
});
HTML
<div ng-controller="ctl">
<form name="form1" ng-submit="validate(form1)" novalidate>
<p class="input-group" name="dtFrom" style="width:160px;margin-bottom:0px;">
<input type="text" class="form-control" ng-model="dtFrom"
is-open="config1.opened" uib-datepicker-popup="MM-dd-yyyy"
close-text="Close" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open1($event)">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</p>
<span ng-show="!form1.dtFrom.$valid">Invalid Date</span>
<br/>
<button type="submit">Validate</button>
</form>
</div>
You should create name for the input
<input type="text" class="form-control" ng-model="dtFrom"
is-open="config1.opened" uib-datepicker-popup="MM-dd-yyyy"
close-text="Close" name="date" />
<span ng-show="!form1.date.$valid">Invalid Date</span>
Here is plnkr
http://plnkr.co/edit/gc0Oefhok6Gjim66UG0K?p=preview
Related
My angularjs validation in .NET MVC cshtml files isnt working.
Below is my code:
cshtml code:
<div id="addEditItem" class="modal" role="dialog">
<form novalidate role="form" name="frmItem">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Add Item Details</h4>
</div>
<div class="modal-body">
<input type="hidden" class="form-control" ng-model="id">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" class="form-control" id="name" ng-model="name" maxlength="50" ng-required="true">
<span style="color:red" class="help-block" ng-if="frmItem.name.$error.required && frmItem.name.$dirty">*</span>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><i class="fa fa-close"></i> Close</button>
<button type="submit" class="btn btn-success" ng-click="SaveItem()"><i class="fa fa-save"></i> Submit</button>
</div>
</div>
</div>
</form>
</div>
Controller Code:
medApp.controller("itemController", function ($scope, itemService) {
$scope.SaveItem = function () {
var itemModel = {
Id: $scope.id,
Name: $scope.name,
Description: $scope.description,
Manufacturer: $scope.manufacturer,
BatchNo: $scope.batchNo,
ExpiryDate: $scope.expiryDate
};
if (!CheckIsValid()) {
alert('Please fill the detail!');
return false;
}
var requestResponse = itemService.AddEdit(itemModel);
Message(requestResponse);
};
function CheckIsValid() {
var isValid = true;
if ($('#name').val() === '' || $('#description').val() === '' || $('#manufacturer').val() === '' || $('#batchNo').val() === '') {
isValid = false;
}
return isValid;
}
});
The addEditItem is a modal dialog. If I click on submit the alert('Error in getting records'); is shown.
I want the validation to happen at cshtml level rather than the java alert.
I am going to remove the CheckIsValid function. I want the validation to happen only in cshtml file.
Any idea what's going on?
In your attached cshtml code I could find the "name" id only, but your check function is also checking"description", "manufacturer" and "batchNo". All of those item must be exist otherwise the function returns with false.
The CheckIsValid() function will return true when all items exists and contains at least one character. Anyway the good start is to put a breakpoint into your check code and see why returns with false.
Wordking fiddle
<form name="myForm">
<input type="hidden" class="form-control" ng-model="id">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" class="form-control" name="name" ng-model="name" maxlength="50" ng-required="true">
<span style="color:red" class="help-block" ng-show="myForm.name.$error.required && !myForm.name.$valid">*</span>
</div>
<button ng-click="display()">Log</button>
</form>
Would like to add that you need to add:
Use name on inputs to be accesable from the scope
Use ng-show/ng-hide for validation since it changes alot
I have a simple code, 2 dates with uib-datepicker-popup:
<div>
<p class="input-group">
<input type="date" class="form-control" uib-datepicker-popup ng-model="adSearch.initDate" is-open="status1.opened" close-text="Close" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event, 'initDate')"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
<div>
<p class="input-group">
<input type="date" class="form-control" uib-datepicker-popup ng-model="adSearch.endDate" is-open="status2.opened" close-text="Close" min-date="{{minEndDate}}" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event, 'endDate')"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
I need to dynamically set a minimum date in the second date from the first date.
I have tried different ways and no one of them work
$scope.open = function($event, date) {
if(date === 'initDate'){
$scope.status1.opened = true;
}else if(date === 'endDate'){
$scope.status2.opened = true;
}
};
$scope.status1 = {
opened: false
};
$scope.status2 = {
opened: false
};
$scope.adSearch.initDate = null;
$scope.minEndDate = $scope.adSearch.initDate;
$scope.$watch('adSearch.initDate', function(v){
console.log(v);
$scope.minEndDate = v;
});
This is what i have in my controller at this moment, it is something I have found that works for datepicker from ui-bootstrap, but does not work for uib-datepicker.
<html ng-app="ui.bootstrap.demo">
<head>
<link rel="stylesheet" href="bootstrap.css">
<script src="angular.js"></script>
<script src="angular-animate.js"></script>
<script src="ui-bootstrap-tpls-1.1.1.js"></script>
<script>
angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('DatepickerDemoCtrl', function ($scope) {
$scope.minDate = new Date();
$scope.open1 = function() {
$scope.popup1.opened = true;
};
$scope.open2 = function() {
$scope.minDate = $scope.dt;
$scope.popup2.opened = true;
};
$scope.dateOptions = {
formatYear: 'yy',
startingDay: 1
};
$scope.format = 'dd-MMMM-yyyy';
$scope.popup1 = {
opened: false
};
$scope.popup2 = {
opened: false
};
});
</script>
</head>
<body>
<div ng-controller="DatepickerDemoCtrl">
<div class="row">
<div class="col-md-6">
<p class="input-group">
<input type="text" class="form-control" uib-datepicker-popup="{{format}}" ng-model="dt" is-open="popup1.opened" show-button-bar="false" />
<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>
<div class="col-md-6">
<p class="input-group">
<input type="text" class="form-control" uib-datepicker-popup ng-model="dt" is-open="popup2.opened" show-button-bar="false" min-date="minDate" />
<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>
</div>
</div>
</body>
</html>
check this. the minDate var in $scope is set when open2() fn is called(i.e when the end date popup is popped. Use ng-Click()
This is an old question but some people might still find this useful for the newer versions. I am currently using angular-ui-bootstrap, version 2.2.0.
Arrive Date
<p class="input-group">
<input type="text" class="form-control" uib-datepicker-popup="{{formatDate}}" datepicker-options="arriveDateOptions"
ng-model="arriveDatePicked"
is-open="arriveDateCalendarOpened"
close-text="Close"/>
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="openArriveDateCalendar()">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</p>
Departure Date
<p class="input-group">
<input type="text" class="form-control" uib-datepicker-popup="{{formatDate}}" datepicker-options="departureDateOptions"
ng-model="departureDatePicked"
is-open="departureDateCalendarOpened"
close-text="Close"/>
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="openDepartureDateCalendar()">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</p>
My controller looks like this:
$scope.formatDate = 'dd-MMMM-yyyy';
$scope.arriveDateCalendarOpened = false;
$scope.departureDateCalendarOpened = false;
var today = new Date();
var minDepartureDate = new Date();
minDepartureDate.setDate(today.getDate() + 7);
$scope.arriveDatePicked = today;
$scope.departureDatePicked = minDepartureDate;
$scope.arriveDateOptions = {
maxDate: new Date(2020, 5, 22),
minDate: today
};
$scope.departureDateOptions = {
maxDate: new Date(2020, 5, 22),
minDate: today
};
I am not sure about the old versions of ui-boostrap and how they used to work, but in this version we can set the minimum and the maximum date in the datepicker-options attribute.
In order to update the departureDate on the fly when the arriveDate changes, we need to force that when we open the departureDate calendar. (in my case, when the openDepartureDateCalendar() function is called)
$scope.openArriveDateCalendar = function () {
$scope.arriveDateCalendarOpened = true;
};
$scope.openDepartureDateCalendar = function () {
$scope.departureDateOptions.minDate = $scope.arriveDatePicked;
$scope.departureDateCalendarOpened = true;
};
you need to update your ui bootstrap version to atleast release 0.14.0
here
is the migration info from old version to new.
uib-datepicker has a big problem when you want to update the model from another date, I changed my mind and tried something different that works for angular too (using jquery-ui datepicker).
this are the 2 directives that i used and worked well:
.directive('startDateCalendar', [
function() {
return function(scope, element) {
scope.$watch('filterDate.endDate', (function(newValue) {
element.datepicker('option', 'maxDate', newValue);
}), true);
return element.datepicker({
dateFormat: 'dd-mm-yy',
numberOfMonths: 1,
maxDate: scope.filterDate.endDate,
changeMonth: true,
changeYear: true,
showOtherMonths: true,
selectOtherMonths: true,
onSelect: function(date) {
scope.filterDate.initDate = date;
var dateHelper = date.split('-');
scope.adSearch.initDate = new Date(dateHelper[2]+'-'+dateHelper[1]+'-'+dateHelper[0]);
scope.dateSearch();
scope.$apply();
}
});
};
}])
.directive('endDateCalendar', [
function() {
return function(scope, element) {
scope.$watch('filterDate.initDate', (function(newValue) {
element.datepicker('option', 'minDate', newValue);
}), true);
return element.datepicker({
dateFormat: 'dd-mm-yy',
numberOfMonths: 1,
changeMonth: true,
changeYear: true,
showOtherMonths: true,
selectOtherMonths: true,
minDate: scope.filterDate.initDate,
onSelect: function(date) {
scope.filterDate.endDate = date;
var dateHelper = date.split('-');
scope.adSearch.endDate = new Date(dateHelper[2]+'-'+dateHelper[1]+'-'+dateHelper[0]);
scope.dateSearch();
return scope.$apply();
}
});
};
}])
this is the html:
<input type="text" start-date-calendar="" ng-model="filterDate.initDate" placeholder="Start Date" class="form-control" readonly="readonly" />
<input type="text" end-date-calendar="" ng-model="filterDate.endDate" placeholder="End Date" class="form-control" readonly="readonly"/>
I was having a similar issues setting the minDate in version 2.5.0.
I tried all the answers here and none of them worked for me, I was able to get the minDate to update dynamically just by casting it to a new Date().
HTML:
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label id="lbl"></label>
<p class="input-group" style="max-width:280px;">
<input type="text" class="form-control" uib-datepicker-popup="dd-MMMM-yyyy" ng-model="DepartureDate" is-open="departureDate" datepicker-options="departureDateOptions" close-text="Close" alt-input-formats="altInputFormats" readonly/>
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="departureDate = !departureDate"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label id="lbl"></label>
<p class="input-group" style="max-width:280px;">
<input type="text" class="form-control" uib-datepicker-popup="dd-MMMM-yyyy" ng-model="ArrivalDate" is-open="arrivalDate" datepicker-options="arrivalDateOptions" close-text="Close" alt-input-formats="altInputFormats" readonly/>
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="ArrivalDateClick()"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
</div>
Code:
$scope.departureDateOptions = {
minDate: new Date()
};
$scope.arrivalDateOptions = {
minDate: null
};
$scope.ArrivalDateClick = function () {
$scope.ArrivalDate = $scope.DepartureDate;
$scope.arrivalDateOptions.minDate = new Date($scope.DepartureDate);
$scope.arrivalDate = !$scope.arrivalDate;
};
$scope.ArrivalDateClick();
How can I prevent the datepicker popup from opening at the same time when I click on only 1 input?
Plunkr
<form>
<div class="form-group">
<label for="fromDate">From:</label>
<input type="text" class="form-control" datepicker-popup="{{format}}" ng-model="dt" is-open="opened" datepicker-options="dateOptions" ng-required="true" close-text="Close" show-weeks="false" ng-click="open($event)" name="fromDate" id="fromDate" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event)">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</div>
<div class="form-group">
<label for="toDate">To:</label>
<input type="text" class="form-control" datepicker-popup="{{format}}" ng-model="toDate" is-open="opened2" datepicker-options="dateOptions" ng-required="true" close-text="Close" show-weeks="false" ng-click="open($event)" name="toDate" id="toDate" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event)">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</div>
</form>
I looked at your plunkr. In your script.js file you have the following
$scope.open = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened = true;
$scope.opened2 = true;
};
$scope.opened = true; and $scope.opened2=true; are both being set. This is forcing both of them to open. You are calling this function when either of the calendar buttons is clicked
ng-click="open($event)"
is-open will force the calendar to show when the variable is set somewhere else in code as well. Remember it is 2-way binding
As for your solution. A simple way I can think to fix it is to pass another variable into your open method telling it which button was clicked so
$scope.open = function($event, calId) {
$event.preventDefault();
$event.stopPropagation();
if(calId===1) $scope.opened = true;
if(calId===2) $scope.opened2 = true;
};
Then in your html for the buttons change to the following passing in a 1,2,3 etc.. for whichever datepicker on the page you want to display.
ng-click="open($event,1)"
With uibootstrap's datepicker,I have a single page with two controls, one is starttime and one is endtime.
I want the following; when I set starttime ,the endtime's min-date is start time. But when I click the endtime I would like the fielded set to "" the.first time.
<p class="input-group">
<input class="form-control" datepicker-popup ng-model="view.starttime" is-open="dateSet.opened.startTime" min-date="'2015-05-02'" max-date="'2015-06-22'" datepicker-options="dateSet.dateOptions" date-disabled="dateSet.disabled(date, mode)" ng-required="true" show-weeks="flase" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="dateSet.openFn($event,'startTime')"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
<p class="input-group">
<input class="form-control" datepicker-popup ng-model="view.endtime" is-open="dateSet.opened.endTime" min-date="view.starttime" max-date="'2015-06-22'" datepicker-options="dateSet.dateOptions" date-disabled="dateSet.dateSet.disabled(date, mode)" ng-required="true" show-weeks="flase"/>
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="dateSet.openFn($event,'endTime')"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
This works for me (forked from the bootstrap demo)
$scope.updateEndDate = true;
$scope.$watch('startDate', function(val) {
if($scope.updateEndDate) $scope.endDate = val;
});
$scope.click = function() {
if ($scope.updateEndDate)
{
$scope.updateEndDate = false;
$scope.endDate = "";
}
};
HTML
{{updateEndDate}}
<div class="col-md-6">
<p class="input-group">
<input name="startDate" type="text" class="form-control"
ng-model="startDate"
is-open="opened"
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 class="col-md-6">
<p class="input-group">
<input
ng-focus="click()"
name="endDate" type="text" class="form-control"
ng-model="endDate"
is-open="opened"
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>
Plunk http://plnkr.co/edit/HfihvKanQsERr4wFq9VE?p=preview
If I understood correctly, you want to set the min-date on the 'end date' picker to be the value of the 'start date' picker, BUT you want to initialize the end date picker to be null.
To do this, you need to initialize the end date to a null value. In your case, that would be $scope.view = {endtime: ''};. Since you didn't provide your controller code or a demo, I just created a simple demo below that matches what I think you want to accomplish.
var app = angular.module('daterange.demo', ['ui.bootstrap'])
.config(function(datepickerConfig, datepickerPopupConfig) {
datepickerConfig.formatYear = 'yy';
datepickerConfig.startingDay = 1;
datepickerConfig.showWeeks = false;
datepickerPopupConfig.datepickerPopup = "shortDate";
datepickerPopupConfig.closeText = "Close";
});
app.controller('DatepickerPopupDemoCtrl', function($scope) {
$scope.startdt = new Date();
$scope.enddt = '';
$scope.opened = {
startdt: false,
enddt: false
};
$scope.open = function($event, picker) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened[picker] = true;
};
$scope.$watch('startdt', function(newval) {
if ($scope.enddt !== '' && newval > $scope.enddt) {
$scope.enddt = newval;
}
});
$scope.setRangeClass = function(date, mode) {
if (mode === 'day') {
var dayToCheck = new Date(date).setHours(12, 0, 0, 0);
var startDay = new Date($scope.startdt).setHours(12, 0, 0, 0);
var endDay = new Date($scope.enddt).setHours(12, 0, 0, 0);
if (dayToCheck >= startDay && dayToCheck < endDay) {
return 'range';
}
}
return '';
};
});
#import "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css";
.btn-default[disabled], .btn-default.disabled {
background-color: #999;
}
.range>.btn-default {
background-color: #5bb75b;
}
.range button span {
color: #fff;
font-weight: bold;
}
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.13.0.js"></script>
<div ng-app="daterange.demo">
<div class="container" ng-controller="DatepickerPopupDemoCtrl">
<div class="row">
<div class="col-xs-12">
<h2>Popup Date Range Picker Demo</h2>
<pre>Date Range: {{startdt | date:'fullDate' }} - {{enddt | date:'fullDate' }}</pre>
</div>
<div class="col-xs-6">
<label for="startdate">Start Date</label>
<p class="input-group">
<input type="text" class="form-control" id="startdate" datepicker-popup ng-model="startdt" is-open="opened.startdt" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event, 'startdt')"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
<div class="col-xs-6">
<label for="enddate">End Date</label>
<p class="input-group">
<input type="text" class="form-control" id="enddate" datepicker-popup ng-model="enddt" is-open="opened.enddt" min-date="startdt" custom-class="setRangeClass(date, mode)" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event, 'enddt')"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
</div>
</div>
In my demo above, I also added a $watch function that updates the end date picker when the start date picker changes. If the start date is greater than the end date, the end date is reset. Since you don't want the end date to change when the initial digest cycles are run on the page, you have to check for an empty value for the end date.
Additionally, I'm using the new custom-class attribute to show the date range on the end calendar. If you'd like to use this feature, make sure that you're using UI Bootstrap 0.13.0+.
I am Useing Bootstrap angular datepicker in a form to update my model 'User'.
I set this datepicker 'require' property is true.
UpdateUser.html:
<form name="userForm" novalidate>
<div class="form-group">
<label>Birthday</label>
<p class="input-group">
<input type="text" name="birthday" class="form-control" datepicker-popup="yyyy-MM-dd" ng-model="user.birthday" is-open="opened" datepicker-options="dateOptions" ng-required="true" />
<span class="input-group-btn">
<button type="button" class="btn btn-default"
ng-click="openDate($event)">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</p>
<span>{{userForm.birthday.$invalid}}</span>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary" ng-disabled="userForm.$invalid">Update</button>
</div>
</form>
UserCtrl.js:
mainApp.controller("detailCtrl", function($scope, $http, $routeParams, DemoService) {
$scope.user = DemoService.get({userId : $routeParams.userId});
$scope.openDate = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened = true;
};
$scope.dateOptions = {
formatYear: 'yy',
startingDay: 1
};
});
So my question is:
Why {{userForm.birthday.$invalid}} is true when I first set the 'user.birthday' to the datepicker?
Plunker:
http://plnkr.co/edit/DkGEVJ?p=preview
This is weird, but changing the initial birthday from '1403575208000' to new Date(1403575208000) fixes this problem.
http://plnkr.co/edit/Wut4sJT5hFcG6EfSYe8t?p=preview
There are a lot of different problems that look the same at angular-bootstrap Github forums.
I am using angular-bootstrap version 0.13.0 and I found that the datepicker has the value:
userForm.$invalid = true
when the date field is empty and other situations, and does not work well.
When you want to validate it, problems arise. In such cases, to avoid datepicker validation I used the following code:
<div class="form-group">
<button type="submit" class="btn btn-primary" ng-disabled="userForm.$error['required'] !== undefined">Update</button>
</div>
Here is my plunkr
http://plnkr.co/edit/Sqog7OqudQkww9WsCUT2?p=preview
There you can see the value of userForm.$error and decide to use ng-required=true or false at 'birthday'.
Hope it helps!