Vaadin: Collapse all Tabs in an Accordion - vaadin

I'm wondering if there's a way to collapse all tabs on an accordion. Found no such method in TabSheets either. I would like to basically display the tab names and show the content when I select the tab. By default the first tab is always opened.
Thanks in advance!

Last time I checked, I found no way either. You can workaround this by adding an "empty" Tab. Combined with some styling, that worked quite well. E.g.:
#Grapes([
#Grab('org.vaadin.spring:spring-boot-vaadin:0.0.3'),
#Grab('com.vaadin:vaadin-server:7.4.0.beta1'),
#Grab('com.vaadin:vaadin-client-compiled:7.4.0.beta1'),
#Grab('com.vaadin:vaadin-themes:7.4.0.beta1'),
])
import org.vaadin.spring.VaadinUI
import com.vaadin.server.VaadinRequest
import com.vaadin.ui.*
#com.vaadin.annotations.Theme('valo')
#VaadinUI
class MyUI extends UI {
protected void init(VaadinRequest request) {
setContent(new Accordion().with{ c->
['A','B','C'].each{ c.addTab(new Label("Some $it"), it) }
c.addTab(new CssLayout(), "[x] close all") // XXX
return c
})
}
}

Related

Vaadin Designer Tabs not correctly adding children "tab" to tabs object

I'm using Vaadin Deisgner 14.6.1 to create some super simple tabs. However, when I try to do some simple operations in the java class (eg selecting a tab), it throws an error which indicates that the "Tabs" object does not have the proper children "tab" components. Here's a simple test case below. (I discovered the issue when I was trying to add a addSelectedChangeListener() to the tabs class and discovered that it would never fire, presumably since the "tabs" class never properly had any children.) I tried a bunch of hacks, but nothing worked. (I have in the past gotten tabs to work if I stuck purely to a programmatic approach, but I really really really like using Designer, since it saves me tonnes of times and keeps the code quite modular and clean....when it works....)
import {html, PolymerElement} from '#polymer/polymer/polymer-element.js';
import '#vaadin/vaadin-ordered-layout/src/vaadin-vertical-layout.js';
import '#vaadin/vaadin-tabs/src/vaadin-tabs.js';
import '#vaadin/vaadin-tabs/src/vaadin-tab.js';
class MyTabtest extends PolymerElement {
static get template() {
return html`
<style include="shared-styles">
:host {
display: block;
height: 100%;
}
</style>
<vaadin-vertical-layout theme="spacing" style="width: 100%; height: 100%;">
<vaadin-tabs theme="equal-width-tabs" id="tabs" orientation="horizontal" selected="0">
<vaadin-tab id="tab1" selected>
Tab one
</vaadin-tab>
<vaadin-tab id="tab2">
Tab two with a longer title
</vaadin-tab>
<vaadin-tab id="tab3">
Tab three
</vaadin-tab>
</vaadin-tabs>
<label id="lbl1">page1</label>
<label id="lbl2">page2</label>
<label id="lbl3">page3</label>
</vaadin-vertical-layout>
`;
}
static get is() {
return 'my-tabtest';
}
static get properties() {
return {
// Declare your properties here.
};
}
}
customElements.define(MyTabtest.is, MyTabtest);
and
package com.deepsearch.fe.tab2vizdb.fpsgraphicaldetails.spectratab.hslspectrachartandalts;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.polymertemplate.Id;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.templatemodel.TemplateModel;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.polymertemplate.PolymerTemplate;
/**
* A Designer generated component for the my-tabtest template.
*
* Designer will add and remove fields with #Id mappings but
* does not overwrite or otherwise change this file.
*/
#Route("tabtest")
#Tag("my-tabtest")
#JsModule("./src/my-tabtest.js")
public class MyTabtest extends PolymerTemplate<MyTabtest.MyTabtestModel> {
#Id("tabs")
private Tabs tabs;
#Id("tab1")
private Tab tab1;
#Id("tab2")
private Tab tab2;
#Id("tab3")
private Tab tab3;
#Id("lbl1")
private Label lbl1;
#Id("lbl2")
private Label lbl2;
#Id("lbl3")
private Label lbl3;
/**
* Creates a new MyTabtest.
*/
public MyTabtest() {
// tabs.setSelectedTab(tab2); //throws error!
tabs.addSelectedChangeListener(e -> {
System.out.println("A tab got selected!"); //this never fires!!!!
});
}
/**
* This model binds properties between MyTabtest and my-tabtest
*/
public interface MyTabtestModel extends TemplateModel {
// Add setters and getters for template properties here.
}
}
Ultimately, I'm trying to capture a tab select event -- but it doens't seem to work when the tabs are created in Designer....is this true on Vaadin's side too? (ie is this reproducible?)
This is an unfortunate limitation of the component mapping to elements defined in a template. When mapping to Java, the parent-child relationships are not preserved and thus the tabs component does not realize that the tab is one of its child components.
See https://github.com/vaadin/flow/issues/7622
The way to make it work would be to create the Tabs and Tab instances in Java and the rest in Designer.

Vaadin Tabs based component created using Designer doesn't show data when bound using its Java companion file

Below is the Vaadin Designer code for simple tab functionality
import {html, PolymerElement} from '#polymer/polymer/polymer-element.js';
import '#vaadin/vaadin-tabs/src/vaadin-tabs.js';
import '#vaadin/vaadin-tabs/src/vaadin-tab.js';
class TestUi extends PolymerElement {
static get template() {
return html`
<style include="shared-styles">
:host {
display: block;
height: 100%;
}
</style>
<vaadin-tabs theme="equal-width-tabs" id="vaadinTabs">
<vaadin-tab id="vaadinTab">
Product Overview
</vaadin-tab>
<vaadin-tab id="vaadinTab1">
Product DetailView
</vaadin-tab>
<vaadin-tab id="vaadinTab2">
Reports
</vaadin-tab>
</vaadin-tabs>
`;
}
static get is() {
return 'test-ui';
}
static get properties() {
return {
// Declare your properties here.
};
}
}
customElements.define(TestUi.is, TestUi);
It's corresponding Java companion file looks as below
import com.vaadin.flow.component.polymertemplate.Id;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.templatemodel.TemplateModel;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.polymertemplate.PolymerTemplate;
/**
* A Designer generated component for the test-ui template.
*
* Designer will add and remove fields with #Id mappings but
* does not overwrite or otherwise change this file.
*/
#Tag("test-ui")
#JsModule("./src/productdetailview/test-ui.js")
public class TestUi extends PolymerTemplate<TestUi.TestUiModel> {
#Id("vaadinTabs")
private Tabs vaadinTabs;
#Id("vaadinTab")
private Tab vaadinTab;
#Id("vaadinTab1")
private Tab vaadinTab1;
#Id("vaadinTab2")
private Tab vaadinTab2;
/**
* Creates a new TestUi.
*/
public TestUi() {
// You can initialise any data required for the connected UI components here.
vaadinTabs.addSelectedChangeListener(selectedChangeEvent -> {
selectedChangeEvent.getSelectedTab().getElement().getStyle().set("background-color":"blue");
});
}
/**
* This model binds properties between TestUi and test-ui
*/
public interface TestUiModel extends TemplateModel {
// Add setters and getters for template properties here.
}
}
In the above code, My thinking was to start writing the selectedChangeListener Handler directly without doing much but instead this doesn't work and below initialization code needs to be added.
//I have added for one tab but it requires all the tabs to be added
vaadinTabs = new Tabs();
vaadinTab = new Tab();
vaadinTabs.add(vaadinTab);
My question here is why would I need to initialize when the Polymer js code generated using Vaadin Designer clearly defines the tab and it's group?
This is the same issue with Vaadin Grid. Even after defining the columns in the Polymer js, I have to redefine it from the Java component end instead of directly start providing the data via data provider
TLDR; Unfortunately, you have encountered this issue IllegalArgumentException when switching tabs
which is closed as won't fix.
My question here is why would I need to initialize when the Polymer js code generated using Vaadin Designer clearly defines the tab and it's group?
Generally, you don't need to. But Tabs doesn't work as intended in this case. Thus, for this particular component, it's suggested to not mix template/Java logic.
For example, you can verify it with a <vaadin-text-field>, where event is fired correctly.
Java counterpart
#Id("vaadinTextField")
private TextField vaadinTextField;
/**
* Creates a new TestUi.
*/
public TestUi() {
// You can initialise any data required for the connected UI components here.
vaadinTextField.addValueChangeListener(event->{
System.out.println("Event has happened");
});
vaadinTextField.setValueChangeMode(ValueChangeMode.EAGER);
and snippet for the template right after the tabs:
<vaadin-vertical-layout id="vaadinVerticalLayout" style="width: 100%; height: 100%;">
<vaadin-text-field id="vaadinTextField"></vaadin-text-field>
</vaadin-vertical-layout>
Taken from the issue:
So all Tab related API methods in Tabs are completely broken in regard to injected Tabs.
and
Unfortunately we've concluded that there is no sensible way we can support this for now, thus this issue will be a known limitation with Tabs. It will not work as #Id mapped component when the child vaadin-tabs are created in the template file, so you should not try to mix client & server logic and content for the Tabs component.
As a workaround, you could try to use your own component for #Id mapping tabs like:
#Tag("vaadin-tabs")
public IdMappedTabs extends Component {
public IdMappedTabs() {
}
public Registration addSelectionListener(PropertyChangeListener listener) {
return getElement().addPropertyChangeListener("selected", listener);
}
public void setSelectedTabIndex(int index) {
getElement().setProperty("selected", index);
}
}
Edit:
What is the issue with Grid you are having? (There is a good tutorial about Designer, where Grid is used. It might be useful : Vaadin Designer tutorial)

MatFormField outline issue

When I change the font type in my form, label overlays the outline.
How can i fix this?
in the following image it is shown how it should be:
Seems like after 3 years there's still no fix to this issue in Angular Material.
However, there are two workarounds:
First workaround:
create a directive that links to all mat-form-field components (directives) with appearance attribute set to outline
listen to document.fonts.ready event and run updateOutlineGap on the MatFormField
export the directive in AppModule or SharedModule to make it accessible everywhere
this way Angular will update the outline size as soon as the custom font is loaded
import { AfterViewInit, Directive } from '#angular/core';
import { MatFormField } from '#angular/material/form-field';
#Directive({
selector: 'mat-form-field[appearance=outline]',
})
export class UpdateOutlineGapDirective implements AfterViewInit {
constructor(private formField: MatFormField) {
}
ngAfterViewInit() {
document.fonts.ready.then(() => {
this.formField.updateOutlineGap();
});
}
}
Second workaround:
add #userNameField to your mat-form-field element
add (focus)="userNameField.updateOutlineGap()" to the input element
this way every time the input is focused, Angular will update the outline size

angular ag-grid auto bind false

We are using an ag-grid.
We would like to have the same functionality as the kendo-grid autoBind: false.
So the grid doesn't do anything till a button is clicked and the grid is triggered with server-side infinite-scroll paging.
How can we do this with ag-grid in Angular?
We did it like this:
First we assign an EmptyDataSource
import { IDatasource, IGetRowsParams } from "ag-grid-community";
/** Empty datasource used to assign to grid to have no results at first */
export class EmptyDatasource implements IDatasource {
getRows(params: IGetRowsParams): void {
params.successCallback([], 0);
}
}
When the search button is clicked we assign the real datasouce like so (which in this case is the component itself):
this.gridApi.setServerSideDatasource(this);

Use DartAngular with dart:html

Is it possible to use default dart library html with angular dart?
ie:
class Test1Component implements OnInit{
#override
void ngOnInit() {
ButtonElement button = querySelector('button');
//Broken code, avoid button to be null.
button.onClick.listen(onClick);
}
void onClick(Event e){
print('Button clicked');
}
}
How can I avoid to get a 'null' button without the using any timers?
Basically I'm using only angular just for the Routes and but I'd like to stick with dart:html to control the DOM and events.
Yes, you can do that, but it's usually not a good idea.
Use instead #ViewChild(...) or similar Angular methods to get references to elements in a components view.
<button #myButton>click me</button>
#ViewChildren('myButton')
set myButton(List<Element> value) {
if(value.isNotEmpty) {
print(value.first);
}
}
If you want to just add a click handler using
<button (click)="onClick">click me</button>
would be the better way but it sounds you are somehow adding the button dynamically and adding a click handler declaratively might not work in this case (would need more info)
EDIT:
If someone like me want to use dart:html instead angular ng code, it's possible to use it
import 'package:angular/angular.dart';
import 'dart:html';
// AngularDart info: https://webdev.dartlang.org/angular
// Components info: https://webdev.dartlang.org/components
#Component(
selector: 'container',
template: '<h1>Test 1</h1><button #test1>Bottone test 1</button>',
)
class Test1Component implements OnInit{
#ViewChild('test1')
ButtonElement button;
#override
void ngOnInit() {
//Verified that button is initialized
print(button);
//Initialize click
button.onClick.listen((e) => print("Clicked"));
}
}

Resources