DatePicker behavior in view: In a Vaadin 23 application there is a view with two DatePickers and a button:
When a user steps between the fields with TAB, then the DatePicker marks the whole content as selected (which is fine and the intended behavior):
DatePicker behavior in Dialog is different: When I put two DatePicker instances into a Dialog then the TAB behavior is different: it does not mark the whole content, but sets the focus after the content:
Code:
#Route("sandbox")
public class SandboxView extends VerticalLayout {
public SandboxView() {
this.add(createDatePicker(), createDatePicker());
this.add(new Button("Open dialog", event -> {
openDialog();
}));
}
private void openDialog() {
VerticalLayout layout = new VerticalLayout(createDatePicker(), createDatePicker());
Dialog dialog = new Dialog(layout);
dialog.open();
}
private DatePicker createDatePicker() {
DatePicker datePicker = new DatePicker();
datePicker.setValue(LocalDate.now());
datePicker.setAutoOpen(false);
return datePicker;
}
}
Intended behavior: I'd like the DatePicker to show the same behavior in a Dialog as it is in a view.
Question: How can I do this?
What I tried: When a focus listener calls select() at the INPUT child node in JavaScript (see code below), the whole content is marked/selected (which is as intended). But this also marks/selects the whole content when the user clicks with the mouse into the field (which is not intended).
field.getElement().addEventListener("focus", new DomEventListener() {
#Override
public void handleEvent(DomEvent event) {
event.getSource().executeJs("for (var i=0;i<$0.childNodes.length;i++){if($0.childNodes[i].nodeName=='INPUT'){$0.childNodes[i].select();}}");
}
});
Update for TextField: When using TextFields instead of DatePickers, it's the same behavior: in a view a TAB marks/selects the whole content. In a Dialog a TAB sets the focus before the content, but does not mark/select it:
This behavior is fixed in Vaadin 23.1.6.
Related
I use the menuBar component in my application and I would like to add a "mini" form in the menu.
In the "contact" menu, the user can fill a TextField with a phone number and click on a submit button to be called.
My issue is when I select the TextField, the menu closes automatically.
Do you know if it's possible to do that and how I can do ?
Thank you.
This an example of my menu
public class HeaderView extends MenuBar implements RouterLayout {
private final MenuItem tools;
private final MenuItem contacts;
public HeaderView() {
// logo
final Image img = new Image("img/logo.png", "image");
img.setHeight("44px");
this.addItem(img);
// TOOLS
tools = this.addItem("Tools");
tools.addComponentAsFirst(new Icon(VaadinIcon.TOOLS));
// CONTACTS
contacts = this.addItem("Contacts");
contacts.addComponentAsFirst(new Icon(VaadinIcon.PHONE));
// layout for the form contact
final FormLayout nameLayout = new FormLayout();
final TextField phoneField = new TextField();
phoneField.setLabel("Phone");
phoneField.setPlaceholder("Phone");
final Button sendButton = new Button("send");
// add textfield and button to the layout
nameLayout.add(phoneField, sendButton);
// add the form to the menubar
contacts.getSubMenu().addItem(nameLayout);
}
You can try changing contacts.getSubMenu().addItem(nameLayout) to contacts.getSubMenu().add(nameLayout) I'm not sure if you can self trigger closure of the submenu after submission. If that is required.
I have an issue with showing a Modal on Ionic 5 Angular 8 on iOS.
So I have a page with two buttons, one is declared in the same page component, the other one is from a child component.
When the button in the same page is clicked, the modal opens fine.
When the button from the child component is clicked, the event is emitted to the parent Page, which then creates the modal, but the modal slides up, outside the view port.
I have tried all possible trouble shooting I can think of:
Removing all custom CSS, removing all html, changing the route of the event, adding a timeout etc..
I don't have any autofocus or bootstrap: [] in my entire app.
Here is what the page looks like
export class MyPage implements OnInit, OnDestroy {
//...
private openModal (params) {
const obj = {
component: ModalComponent,
componentProps: params
};
this.modalProvider.create (obj).then (
modal => {
modal.onDidDismiss().then(
() => {}
);
modal.presente ();
}
)
}
public onOpenModal () {
const params = {
//custom properties
}
this.openModal(params);
}
public localAction () {
const params = {
// custom params
}
this.openModal (params)
}
}
Now on the template side :
<ion-content force-overscroll="false" [scrollY]="false">
<!-- Some html --->
<ion-grid (click)="localAction()">
<!-- Some html --->
</ion-grid>
<!-- Some html --->
<child-component (modalOpenEmitter)="onOpenModal($event)">
</ion-content>
Ok I have found the problem after several hours digging.
It turns out it was because of the child component which host a list of button scrolling horizontally.
When a button from the the child component was clicked, an event was emitted as per normal, but I was using a DOM function called scrollintoview like so:
Child component.ts :
public btnClicked (value) {
//...
this.clickEmitter.emit(value); // Normal stuff
const element = document.getElementById(value.id);
if (element) {
element.scrollIntoView(); // This caused the the modal to disappear
}
}
This scrollIntoView was there to make the clicked button slide further in the view port.
Unfortunately, this beaks the modal on iOS, but it works fine on android by the way.
I am using Vaadin 8.5.1 with the Vaading Desiin combination with Spring Boot 2.0.4.
Currently I am trying to add a PopupView at the bottom of the page which opens on button click. In the Popup there is a vertical layout including two components: a HorizontalSplitPanel and a Button. The PopupView should have the width of the current BrowserWindow and one third of the height.
The HorizontalSplitPanel should use all the space in the popup, which is not needed for the button.
What I did:
#SpringComponent
#UIScope
public class View extends VerticalLayout implements Observer {
private final PopupContentView popupContentView;
private PopupView popup;
#Autowired
public View(PopupContentView popupContentView) {
this.popupContentView = popupContentView;
}
#PostConstruct
void init() {
button.addClickListener(clickEvent -> openPopup());
}
private void openPopup() {
if (popup == null) {
setSizeOfPopUp();
// popup will adjust automatically to size of content
popup = new PopupView(null, popupContentView);
popup.addPopupVisibilityListener(event -> {
if (event.isPopupVisible()) {
popupContentView.build(this::submitted);
}
});
popup.setHideOnMouseOut(false);
this.addComponent(popup);
}
popup.setPopupVisible(true);
}
private void setSizeOfPopUp() {
if (popupContentView != null) {
popupContentView.setWidth(Page.getCurrent().getBrowserWindowWidth(), Unit.PIXELS);
popupContentView.setHeight(((float) Page.getCurrent().getBrowserWindowHeight()) / 3, Unit.PIXELS);
}
}
private void submitted() {
// do some stuff
}
#Override
public void update(Observable observable, Object o) {
if (observable instanceof BrowserWindowResizeListenerObservable) {
setSizeOfPopUp();
}
}
}
#Service
public class BrowserWindowResizeListenerObservable extends Observable implements Page.BrowserWindowResizeListener {
#Override
public void browserWindowResized(Page.BrowserWindowResizeEvent browserWindowResizeEvent) {
this.setChanged();
this.notifyObservers();
}
}
#SpringComponent
#UIScope
public class PopupContentView extends VerticalLayout {
private SubmitCallback submitCallback;
private Button submitBtn;
#PostConstruct
void init() {
super.init();
}
void build(#NotNull SubmitCallback) {
removeAllComponents();
this.addComponent(horizontalSplitPanel);
this.addComponent(submitBtn);
this.setExpandRatio(horizontalSplitPanel, 1.0f);
this.submitCallback = callback;
}
private void submit() {
submitCallback.submit(someContent);
}
#FunctionalInterface
public interface SubmitCallback {
void submit(SomeContent someContent);
}
}
As you can see, I have a main view, a view for the content and a listener class.
What I want to happen is that the popup is visible on button click and contains the content view with the panel and the submit button. The panel takes the rest of the space, which is not needed for the button. and the popup is fully filled with content.
What actually happens is that the panel takes the full space of the popup and the button will be shown below the popup.
However, when I resize the window and the resizing event gets fired, everything is fine and the button is no longer below the popup.
It seems to be that the padding and the margin (which are the HTML implementation of the expand ratio in Vaadin) are calculated at an earlier stage and get triggered again when resizing the window. However, I have no clue when and what I need to do, to trigger it.
Does anyone have an idea, how can fix this?
EDIT:
When I have a Tree component or a DateField component in the PopupView and then expand a tree element or change the value of the DateField by selecting a value from the Date popup, the resizing is done correctly and everything is fine.
I think in your case the method of checking Browser window size and calculating target pixel size is too complex for your case. I would recommend just to set the width of the popup to be 100% and height to be 33%, like component.setHeight("33%"), yes you can use percentages for width and height instead of pixels. Then sizing is done by CSS, and it will react faster to browser window sizing without server round trip.
I know that drillup button works on the client side, but is there any way to know when that button is clicked?
In the ColumnWithLazyMultiLevelDrilldown class you can see example of using ChartDrillupListener.
Chart chart = new Chart(ChartType.COLUMN);
chart.addChartDrillupListener(new ChartDrillupListener() {
#Override
public void onDrillup(ChartDrillupEvent event) {
log("ChartDrillupEvent");
}
});
I created a TextField with TextChangeListener. When user types in certain values (in this case 'admin') then addStyleName is invoked on that field and font color becomes red. But afterwards, the value is blank and each entered character is being cleared.
Here is the code of the application. Why after adding new style to TextField its value changes?
public class VaadintestApplication extends Application {
#Override
public void init() {
Window mainWindow = new Window("Vaadintest Application");
setTheme("test");
TextField textField = new TextField("username");
textField.setEnabled(true);
textField.setTextChangeEventMode(TextChangeEventMode.EAGER);
textField.addListener(new TextChangeListener() {
public void textChange(TextChangeEvent event) {
if ("admin".equals(event.getText())) {
((TextField) event.getComponent()).addStyleName("text-error");
} else {
((TextField) event.getComponent()).removeStyleName("text-error");
}
}
});
mainWindow.addComponent(textField);
setMainWindow(mainWindow);
}
}
I would guess that the following happens:
The style name change triggers a repaint on the server, causing the TextField component to be serialized again to the client
The client receives the serialization (the whole bloody thing, not just the changed parts, because that's how things work with Vaadin), and hence it changes the contents of the textfield, while ignoring any changes that are pending from the text change listener
Solutions:
Update the value of the TextField at the same time you add/remove the style name: ((TextField) event.getComponent()).setValue(event.getText())
Create a custom client side widget which extends VTextField and add the functionality there