可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a form where there is a need for me to have 2 or more date fields for different things. I tried the Angular UI Bootstrap which works fine when I have only 1 date field in the form. But it stops working if I have multiple date fields and I dont know the easier method to get this to work.
This is my HTML sample:
<label>First Date</label>
<div class="input-group">
<input type="text" class="form-control" datepicker-popup="{{format}}" name="dt" ng-model="formData.dt" is-open="opened" datepicker-options="dateOptions" ng-required="true" close-text="Close" />
<span class="input-group-btn">
<button class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</div>
<label>Second Date</label>
<div class="input-group">
<input type="text" class="form-control" datepicker-popup="{{format}}" name="dtSecond" ng-model="formData.dtSecond" is-open="opened" datepicker-options="dateOptions" ng-required="true" close-text="Close" />
<span class="input-group-btn">
<button class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</div>
My JS is:
myApp.controller('DatePickrCntrl', function ($scope) {
$scope.today = function() {
$scope.formData.dt = new Date();
};
$scope.today();
$scope.showWeeks = true;
$scope.toggleWeeks = function () {
$scope.showWeeks = ! $scope.showWeeks;
};
$scope.clear = function () {
$scope.dt = null;
};
// Disable weekend selection
$scope.disabled = function(date, mode) {
return ( mode === 'day' && ( date.getDay() === 0 || date.getDay() === 6 ) );
};
$scope.toggleMin = function() {
$scope.minDate = ( $scope.minDate ) ? null : new Date();
};
$scope.toggleMin();
$scope.open = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened = true;
};
$scope.dateOptions = {
'year-format': "'yy'",
'starting-day': 1
};
$scope.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'shortDate'];
$scope.format = $scope.formats[0];
});
I implemented based on the sample here. The problem I have here is:
1) When one of the date field is clicked, the pop-up datepicker is messed up and seems to show 2 datepicker in 1.
2) When I remove is-open="opened"
attribute, the pop-up window seems to work fine. But without is-open="opened"
, the ng-click="open($event)
for the button doesnt work.
3) Since each of the date fields have different ng-models, I am unable to set default dates for any date fields except for the first one with ng-model="formData.dt"
The only long way to resolve this that I can think of is to separate the controller for each date field.
I would like to know how others implement multiple date fields in 1 form itself when using Angular UI Bootstrap.
回答1:
I have 30 in one form one controller no problem. use the same concept if you need it on ng-repeat.
<label>First Date</label>
<div class="input-group">
<input type="text" class="form-control" datepicker-popup="{{format}}"
name="dt" ng-model="formData.dt" is-open="datepickers.dt"
datepicker-options="dateOptions" ng-required="true"
close-text="Close" />
<span class="input-group-btn">
<button class="btn btn-default" ng-click="open($event,'dt')">
<i class="glyphicon glyphicon-calendar"></i></button>
</span>
</div>
<label>Second Date</label>
<div class="input-group">
<input type="text" class="form-control" datepicker-popup="{{format}}"
name="dtSecond" ng-model="formData.dtSecond"
is-open="datepickers.dtSecond" datepicker-options="dateOptions"
ng-required="true" close-text="Close" />
<span class="input-group-btn">
<button class="btn btn-default" ng-click="open($event,'dtSecond')">
<i class="glyphicon glyphicon-calendar"></i></button>
</span>
</div>
myApp.controller('DatePickrCntrl', function ($scope) {
$scope.datepickers = {
dt: false,
dtSecond: false
}
$scope.today = function() {
$scope.formData.dt = new Date();
// ***** Q1 *****
$scope.formData.dtSecond = new Date();
};
$scope.today();
$scope.showWeeks = true;
$scope.toggleWeeks = function () {
$scope.showWeeks = ! $scope.showWeeks;
};
$scope.clear = function () {
$scope.dt = null;
};
// Disable weekend selection
$scope.disabled = function(date, mode) {
return ( mode === 'day' && ( date.getDay() === 0 || date.getDay() === 6 ) );
};
$scope.toggleMin = function() {
$scope.minDate = ( $scope.minDate ) ? null : new Date();
};
$scope.toggleMin();
$scope.open = function($event, which) {
$event.preventDefault();
$event.stopPropagation();
$scope.datepickers[which]= true;
};
$scope.dateOptions = {
'year-format': "'yy'",
'starting-day': 1
};
$scope.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'shortDate'];
$scope.format = $scope.formats[0];
});
// ***** Q2 ***** somemodel can be just an array [1,2,3,4,5]
<div ng-repeat="o in somemodel">
<label>Date Label</label>
<div class="input-group">
<input type="text" class="form-control" datepicker-popup="{{format}}"
name="dt{{o}}" ng-model="datepickers.data[o]"
is-open="datepickers.isopen[o]" datepicker-options="datepickers.option"
ng-required="true" close-text="Close" />
<span class="input-group-btn">
<button class="btn btn-default" ng-click="open($event,o)">
<i class="glyphicon glyphicon-calendar"></i></button>
</span>
</div>
</div>
myApp.controller('DatePickrCntrl', function ($scope) {
$scope.datepickers = {
data: {},
options: {
'year-format': "'yy'",
'starting-day': 1
},
isopen: {}
}
$http.get("get/data/for/some/model", function(result) {
$scope.somemodel = result;
for (var i = 0; i < result.length; i++) {
$scope.datepickers.isopen[result] = false;
$scope.datepickers.data[result] = new Date(); //set default date.
}
});
// fill in rest of the function
});
回答2:
Simpler Solution. Requires only modding the HTML and can be used in a ng-repeat if you like. Just be creative with what you name the opened
Stick this in your Controller:
$scope.calendar = {
opened: {},
dateFormat: 'MM/dd/yyyy',
dateOptions: {},
open: function($event, which) {
$event.preventDefault();
$event.stopPropagation();
$scope.calendar.opened[which] = true;
}
};
HTML:
<div class="form-group row">
<div class="col-lg-6">
<label for="formDOB">Date of Birth</label>
<p class="input-group">
<input type="text" class="form-control" datepicker-popup="{{calendar.dateFormat}}" ng-model="record.birthDate" is-open="calendar.opened.dob" datepicker-options="calendar.dateOptions" close-text="Close" placeholder="Date of Birth" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="calendar.open($event, 'dob')"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
<div class="col-lg-6">
<label for="formWinDate">Win Date</label>
<p class="input-group">
<input type="text" class="form-control" datepicker-popup="{{calendar.dateFormat}}" ng-model="record.winDate" is-open="calendar.opened.win" datepicker-options="calendar.dateOptions" close-text="Close" placeholder="Win DAte" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="calendar.open($event, 'win')"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
回答3:
wayne's answer is great. I would only add, that you can make the function 'open()' better:
$scope.open = function ($event, datePicker) {
$event.preventDefault();
$event.stopPropagation();
$scope.closeAll();
datePicker.opened = true;
};
And then you have to use it like that:
ng-click="open($event, dateFrom)"
Where dateFrom is your ng-model (i.e. you use $scope.dateFrom).
EDIT: $scope.closeAll();
is a function that closes all the datePickers. It can be written like that:
$scope.closeAll = function() {
$scope.dateFrom.opened = false;
$scope.dateTo.opened = false;
};
回答4:
I'd prefer not to mix ng-model with UI info.For this purpose, is necessary to define an array to store the opening flags, as well as checking if the datePicker is opened or not.
Moreover, I have changes the 'open' behavior to 'toggle' instead, in order to allow closinf the datePicker with the button.
Here is my controller:
$scope.toggleOpenDatePicker = function($event,datePicker) {
$event.preventDefault();
$event.stopPropagation();
$scope[datePicker] = !$scope[datePicker];
};
Then it can be used as:
<input type="text" class="form-control" ng-model="model.date1" is-open="date1" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="toggleOpenDatePicker($event,'date1')"><i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
The $scope idea was borrowed from here:
回答5:
I solved my problem by use this plunker with minor changes.
HTML
<div class="row">
<div class="col-md-6">
<p class="input-group">
<input type="text" class="form-control" datepicker-popup="{{format}}" ng-model="dt" is-open="openDatePickers[0]" min-date="minDate" max-date="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true" close-text="Close" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event, 0)"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
<h4>Popup</h4>
<div class="row">
<div class="col-md-6">
<p class="input-group">
<input type="text" class="form-control" datepicker-popup="{{format}}" ng-model="dt" is-open="openDatePickers[1]" min-date="minDate" max-date="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true" close-text="Close" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event, 1)"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
and in controller
$scope.openDatePickers = [];
$scope.open = function ($event, datePickerIndex) {
$event.preventDefault();
$event.stopPropagation();
if ($scope.openDatePickers[datePickerIndex] === true) {
$scope.openDatePickers.length = 0;
} else {
$scope.openDatePickers.length = 0;
$scope.openDatePickers[datePickerIndex] = true;
}
};
my changes
instead numbers (0 or 1) i use $index
in angular ng-repeat
.
like this:
is-open="openDatePickers[**$index**]"
ng-click="open($event, **$index**)"
<p class="input-group">
<input type="text" class="form-control" datepicker-popup="{{format}}" ng-model="dt" is-open="openDatePickers[$index]" min-date="minDate" max-date="'2015-06-22'" datepicker-options="dateOptions" date-disabled="disabled(date, mode)" ng-required="true" close-text="Close">
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event, $index)"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
回答6:
i used it in a different way and it looks a bit easier to me. I was using one of the mentioned approaches, but i was to lazy to create tons of calendars since i was running i a loop without having any static identifier.
So this solution is just valid for you, if you want to create lots of calendars inside of a ng-repeat. Hope it helps!
That is the controller
$scope.datepickers = {
data: {},
isopen: {}
}
// setting the defaults once
for (var i = 0; i < $scope.array.length; i++) {
$scope.datepickers.isopen[i] = false;
$scope.datepickers.data[i] = new Date();
}
// aso..
$scope.valuationDatePickerOpen = function($event, index) {
if ($event) {
$event.preventDefault();
$event.stopPropagation();
}
$scope.datepickers.isopen[index] = true;
};
And this is the HTML snipped inside my loop
<!-- ng-repeat="entry in array track by $index" -->
<input type="text" class="form-control"
datepicker-popup="dd-MMMM-yyyy"
is-open="datepickers.isopen[$index]"
ng-click="valuationDatePickerOpen($event, $index)"
ng-model="entry.date" />