Виджеты Vaadin просты и классны! Но они также плохо настраиваются. Мне нужен виджет DateField, чтобы открывать календарь на событии фокуса. Я не нашел этой функции в официальной документации Vaadin. Я нашел здесь сторонний виджет, но он скомпилирован для Vaadin 7.7, и я использую последнюю версию Ваадин (8.0.6). Также у него есть зависимость от Joda-time 2.1, что крайне нежелательно в моем проекте. Итак, есть ли простой способ настроить стандартный виджет vaadin DateField, чтобы открыть его календарь в фокусе поля, или мне нужно написать свой собственный компонент для этого? Любая помощь приветствуется.
Ваадин: открытый календарь в фокусе поля для поля даты
Ответы (1)
Как я уже говорил в своем комментарии, насколько мне известно, в настоящее время фреймворк не предлагает неявного способа программного открытия всплывающего окна календаря. То же самое и с некоторыми другими компонентами, такими как редактор сетки или список комбинированных элементов.
Я могу придумать одно быстрое решение - добавить расширение javascript., который регистрирует слушателей фокуса для всех полей даты и нажимает кнопку, когда поле даты сфокусировано. Пожалуйста, найдите ниже образец.
P.S. Если вам нужно применить это только к некоторым полям даты, вы можете добавить идентификаторы и передать их в JS, где вы сделаете что-то вроде document.getElementById('myDateFieldId')
вместо document.getElementsByClassName("v-datefield")
.
1) Макет с компонентами
public class MyDateFieldComponent extends HorizontalLayout {
public MyDateFieldComponent() {
// basic setup
DateField fromDateField = new DateField("From", LocalDate.of(2011, Month.FEBRUARY, 6));
DateField toDateField = new DateField("To", LocalDate.of(2018, Month.FEBRUARY, 6));
setSpacing(true);
addComponents(fromDateField, toDateField);
// add the extension
addExtension(new CalendarFocusPopupOpenerExtension());
}
}
2) Расширение - Java / серверная сторона
import com.vaadin.annotations.JavaScript;
import com.vaadin.server.AbstractJavaScriptExtension;
@JavaScript("calendar-focus-popup-opener-extension.js")
public class CalendarFocusPopupOpenerExtension extends AbstractJavaScriptExtension {
public CalendarFocusPopupOpenerExtension() {
// call the bind function defined in the associated JS
callFunction("bind");
}
}
3) Расширение - js / на стороне клиента
window.com_example_calendar_CalendarFocusPopupOpenerExtension = function () {
this.bind = function () {
if (document.readyState === "complete") {
// if executed when document already loaded, just bind
console.log("Doc already loaded, binding");
bindToAllDateFields();
} else {
// otherwise, bind when finished loading
console.log("Doc nod loaded, binding later");
window.onload = function () {
console.log("Doc finally loaded, binding");
bindToAllDateFields();
}
}
};
function bindToAllDateFields() {
// get all the date fields to assign focus handlers to
var dateFields = document.getElementsByClassName("v-datefield");
for (var i = 0; i < dateFields.length; i++) {
addFocusListeners(dateFields[i]);
}
}
function addFocusListeners(dateField) {
// when focusing the date field, click the button
dateField.onfocus = function () {
dateField.getElementsByTagName("button")[0].click();
};
// or when focusing the date field input, click the button
dateField.getElementsByTagName("input")[0].onfocus = function () {
dateField.getElementsByTagName("button")[0].click();
};
}
};
ПОЗДНЕЕ ОБНОВЛЕНИЕ
Второй подход может заключаться в назначении некоторых идентификаторов вашим полям, а затем периодической проверки, чтобы видеть, когда все они видны, и, как только они становятся, привязать слушателей фокуса.
1) Макет с компонентами
public class MyDateFieldComponent extends HorizontalLayout {
public MyDateFieldComponent() {
// basic setup
DateField fromDateField = new DateField("From", LocalDate.of(2011, Month.FEBRUARY, 6));
fromDateField.setId("fromDateField"); // use id to bind
fromDateField.setVisible(false); // initially hide it
DateField toDateField = new DateField("To", LocalDate.of(2018, Month.FEBRUARY, 6));
toDateField.setId("toDateField"); // use id to bind
toDateField.setVisible(false); // initially hide it
// simulate a delay until the fields are available
Button showFieldsButton = new Button("Show fields", e -> {
fromDateField.setVisible(true);
toDateField.setVisible(true);
});
setSpacing(true);
addComponents(showFieldsButton, fromDateField, toDateField);
// add the extension
addExtension(new CalendarFocusPopupOpenerExtension(fromDateField.getId(), toDateField.getId()));
}
}
2) Расширение - Java / серверная сторона
@JavaScript("calendar-focus-popup-opener-extension.js")
public class CalendarFocusPopupOpenerExtension extends AbstractJavaScriptExtension {
public CalendarFocusPopupOpenerExtension(String... idsToBindTo) {
// send the arguments as an array of strings
JsonArray arguments = Json.createArray();
for (int i = 0; i < idsToBindTo.length; i++) {
arguments.set(i, idsToBindTo[i]);
}
// call the bind defined in the associated JS
callFunction("bind", arguments);
}
}
3) Расширение - js / на стороне клиента
window.com_example_calendar_CalendarFocusPopupOpenerExtension = function () {
var timer;
this.bind = function (idsToBindTo) {
// check every second to see if the fields are available. interval can be tweaked as required
timer = setInterval(function () {
bindWhenFieldsAreAvailable(idsToBindTo);
}, 1000);
};
function bindWhenFieldsAreAvailable(idsToBindTo) {
console.log("Looking for the following date field ids: [" + idsToBindTo + "]");
var dateFields = [];
for (var i = 0; i < idsToBindTo.length; i++) {
var dateFieldId = idsToBindTo[i];
var dateField = document.getElementById(dateFieldId);
if (!dateField) {
// field not present, wait
console.log("Date field with id [" + dateFieldId + "] not found, sleeping");
return;
} else {
// field present, add it to the list
console.log("Date field with id [" + dateFieldId + "] found, adding to binding list");
dateFields.push(dateField);
}
}
// all fields present and accounted for, bind the listeners!
clearInterval(timer);
console.log("All fields available, binding focus listeners");
bindTo(dateFields);
}
function bindTo(dateFields) {
// assign focus handlers to all date fields
for (var i = 0; i < dateFields.length; i++) {
addFocusListeners(dateFields[i]);
}
}
function addFocusListeners(dateField) {
// when focusing the date field, click the button
dateField.onfocus = function () {
dateField.getElementsByTagName("button")[0].click();
};
// or when focusing the date field input, click the button
dateField.getElementsByTagName("input")[0].onfocus = function () {
dateField.getElementsByTagName("button")[0].click();
};
}
};
bindToAllDateFields
вызывается до отображения поля даты. Как я могу вызвать эту функцию после загрузки страницы?
- person Everv0id; 12.06.2017
bind
и добавил проверку, чтобы увидеть, загружен ли уже документ при его вызове. Если это так, то он будет привязан немедленно, в противном случае он будет использовать onload
функцию для привязки. Ваш пользовательский интерфейс, вероятно, более сложен, поэтому он будет завершен позже, но в моем случае, когда он был выполнен, документ был загружен. Вы можете проверить консоль разработчика (chrome, firefox и т. Д.), Поэтому просмотрите добавленные мной строки журнала (очевидно, вы также можете удалить их перед фиксацией кода, они предназначены только для целей отладки).
- person Morfic; 12.06.2017
document.readyState === "complete"
истинно, когда вызывается функция bind
, но в данный момент на странице нет .v-datefield
элементов. На своей странице я использую сетку с некоторыми временными фильтрами, и когда вызывается bind
, ни один из фильтров и строк не отображается.
- person Everv0id; 13.06.2017
if
и просто использовать window.onload
, например window.onload = function() {bindToAllDateFields();}
- person Morfic; 13.06.2017
bind
, документ уже имеет состояние complete
, и назначение window.onload
не дает никакого эффекта. Грустный :(
- person Everv0id; 13.06.2017
bind
в конструкторе CalendarFocusPopupOpenerExtension
вы можете переместить его в метод и вызвать его, когда загрузка будет завершена. Учитывая вашу ситуацию, возможно, вы также можете поделиться sscce, чтобы легко отладить свой сценарий.
- person Morfic; 13.06.2017
Grid
странице в документации Vaadin.
- person Everv0id; 13.06.2017
myService.loadData(myFilter)
или чего-то еще, что загружает ваши данные. Тем не менее, одностраничные приложения затрудняют работу с windows.onload
(или аналогичными проверками), и пока я не знаю ни одного события, инициированного Vaadin (есть issue, открытый для этого), поэтому мы пытаемся решить эту проблему. Вот почему я просил sscce, чтобы легко воспроизвести его и выяснить, есть ли какие-либо решения, такие как тайм-аут или проверка наличия final element в dom
- person Morfic; 20.06.2017
DateField
с датой где-то в прошлом (например,addComponent(new DateField("Event date", LocalDate.of(2011, Month.FEBRUARY, 6)))
) и щелкаю его значок календаря, он всплывает с этой конкретной страницей и датой ... - person Morfic   schedule 12.06.2017