Как использовать несколько Angular UT Bootstrap Datepicker в одной форме?
У меня есть форма, где есть необходимость, чтобы у меня было 2 или более полей даты для разных вещей. Я попробовал Angular UI Bootstrap, который отлично работает, когда у меня есть только 1 поле даты в форме. Но он перестает работать, если у меня есть несколько полей даты, и я не знаю более простой способ заставить это работать.
Это мой образец HTML:
<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:
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];
});
Я реализовал на основе примера здесь. Проблема у меня здесь:
1) Когда одно из полей даты нажата, всплывающая датапикер перепуталась и, кажется, показывает 2 datepicker в 1.
2) Когда я удаляю атрибут is-open="opened"
, всплывающее окно работает нормально. Но без is-open="opened"
кнопка ng-click="open($event)
для кнопки не работает.
3) Поскольку каждое из полей даты имеет разные ng-модели, я не могу установить даты по умолчанию для любых полей даты, кроме первого с ng-model="formData.dt"
Единственный длинный способ разрешить это, о котором я могу думать, - отделить контроллер от каждого поля даты.
Я хотел бы знать, как другие реализуют несколько полей даты в самой 1 форме при использовании Angular UI Bootstrap.
Ответы
Ответ 1
У меня 30 в одной форме, у одного контроллера нет проблем. используйте ту же концепцию, если вам это нужно на 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
Упрощенное решение. Требуется только modding HTML и может использоваться в ng-repeat, если хотите. Просто проявляйте творческий подход к тому, что вы называете открытым
Вставьте это в свой контроллер:
$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 ответ велик. Я бы добавил, что вы можете сделать функцию "open()" лучше:
$scope.open = function ($event, datePicker) {
$event.preventDefault();
$event.stopPropagation();
$scope.closeAll();
datePicker.opened = true;
};
И тогда вы должны использовать его так:
ng-click="open($event, dateFrom)"
Где dateFrom - ваша ng-модель (т.е. вы используете $scope.dateFrom).
EDIT: $scope.closeAll();
- это функция, которая закрывает все datePickers. Это можно сделать так:
$scope.closeAll = function() {
$scope.dateFrom.opened = false;
$scope.dateTo.opened = false;
};
Ответ 4
Я бы предпочел не смешивать ng-model с информацией UI. Для этой цели необходимо определить массив для хранения открывающих флагов, а также проверить, открыт ли datePicker или нет.
Кроме того, у меня есть изменения "открытого" поведения для "переключения" вместо этого, чтобы разрешить закрытие кнопки datePicker с помощью кнопки.
Вот мой контроллер:
$scope.toggleOpenDatePicker = function($event,datePicker) {
$event.preventDefault();
$event.stopPropagation();
$scope[datePicker] = !$scope[datePicker];
};
Затем его можно использовать как:
<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>
Идея $scope была взята из здесь:
Ответ 5
Я решил свою проблему, используя этот плункер с незначительными изменениями.
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>
и в контроллере
$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;
}
};
мои изменения
вместо чисел (0 или 1) я использую $index
в angular ng-repeat
.
вот так:
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
Я использовал его по-другому, и мне это немного легче. Я использовал один из упомянутых подходов, но я был ленив, чтобы создавать тонны календарей, так как я запускал цикл без какого-либо статического идентификатора.
Поэтому это решение справедливо для вас, если вы хотите создать много календарей внутри ng-repeat. Надеюсь, это поможет!
Это контроллер
$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;
};
И это HTML, отрезанный внутри моего цикла
<!-- 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" />