I am happily using the standard Vaadin AppLayout Component as the layout starting point for my application. Now I received the requirement to add a statusbar. The statusbar must span the same width as the NavBar, so it cannot be part of the "content".
Is this at all possible with the default AppLayout?
Originally AppLayout has been purposed to take over the whole space, so it is not really meant for this use case. However I was able to tweak it to behave fit footer bar with these settings.
public class MainLayout extends VerticalLayout implements RouterLayout {
private AppLayout appLayout = new AppLayout();
private FlexLayout childWrapper = new FlexLayout();
public MainLayout() {
... setup appLayout ...
childWrapper.setSizeFull();
appLayout.setContent(childWrapper);
HorizontalLayout statusBar = new HorizontalLayout();
statusBar.setHeight("50px");
statusBar.setWidth("100%");
statusBar.add(new Span("Status Bar"));
statusBar.getElement().getStyle().set("background",
"var(--lumo-tint-30pct)");
appLayout.getElement().getStyle().set("width", "100%");
appLayout.getElement().getStyle().set("height", "500px");
add(appLayout, statusBar);
this.expand(appLayout);
}
#Override
public void showRouterLayoutContent(HasElement content) {
childWrapper.getElement().appendChild(content.getElement());
}
}
If you are interested in the status bar to be on top instead, just switch add(appLayout, statusBar); to add(statusBar, appLayout);
Related
I'm using the class AppLayout in Vaadin. I wonder how I can change the background color in the navigation bar.
I know how to add CSS style in Vaadin, but I have trouble to access the navigation class.
Here is my code. As you see, I'm always using the method setClassName. But where can I find that method for the navigation bar?
#Viewport("width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes, viewport-fit=cover")
#PWA(name = "Hemsida", shortName = "Hem")
#Route("")
#CssImport("./CSS/MainView.css")
public class MainView extends AppLayout {
/**
*
*/
private static final long serialVersionUID = 1L;
public MainView() {
// Image bar
Image barImage = new Image("img/cropped-logo_liggande_rod.png", "Spektrakon Logo");
barImage.setClassName("barImage");
// Drawer
DrawerToggle drawerToggle = new DrawerToggle();
drawerToggle.setClassName("drawerToggle");
addToNavbar(barImage, drawerToggle);
Tabs tabs = new Tabs(new Tab("Hem"), new Tab("Produktutveckling"), new Tab("Industriell Design"), new Tab("System"), new Tab("Kvalitet"), new Tab("Om oss"), new Tab("Intrenet"));
tabs.setOrientation(Tabs.Orientation.VERTICAL);
addToDrawer(tabs);
}
}
From the Styling part you can see there is a navbar part. You can use it to style the navbar of a AppLayout
if navbarStyles.css has:
[part~="navbar"]{
background-color: red;
}
And imported to the view with :
#CssImport(value= "./styles/navbarStyles.css", themeFor = "vaadin-app-layout"), background color is changed
A complete example with using theme to distinguish from other AppLayout's
#Route("")
#CssImport(value= "./styles/navbarStyles.css", themeFor = "vaadin-app-layout")
public class AppLayoutPictures extends AppLayout {
public AppLayoutPictures(){
setPrimarySection(AppLayout.Section.DRAWER);
Image img = new Image("https://i.imgur.com/GPpnszs.png", "Vaadin Logo");
img.setHeight("44px");
addToNavbar(new DrawerToggle(), img);
Tabs tabs = new Tabs(new Tab("Home"), new Tab("About"));
tabs.setOrientation(Tabs.Orientation.VERTICAL);
addToDrawer(tabs);
//Set to AppLayout, propageted to `parts`
getElement().setAttribute("theme","appLayout");
}
navbarStyles.css
:host([theme~="appLayout"]) [part~="navbar"]{
background-color: orange;
}
Result:
I have the following code in Wicket 7.3 with JQuery 2.1.4:
public class MyTabbedPanel extends JQueryGenericPanel<List<ITab>>
implements ITabsListener {
...
#Override
protected void onInitialize() {
super.onInitialize();
this.add( new ListView<ITab>( "tabs", this.getModel() ) {
#Override
protected ListItem<ITab> newItem( int index, IModel<ITab> model ) {
ListItem<ITab> item = super.newItem( index, model );
item.setVisible( model.getObject().isVisible() );
item.setOutputMarkupId( true );
return item;
}
#Override
protected void populateItem( ListItem<ITab> item ) {
How can I access this item from the Java code in the panel? I have added icons to each item and want to enable/ disable them when the panel changes.
I have tried in the panels code:
ListItem item = this.findParent( ListItem.class );
but this only gives item = null. There is a "LoadingPanel.class" as a parent. But this does not have a ListItem or any of the other components I have added to the tab.
A better approach would be to make the icons "reactive". I.e. instead of trying to find the ListItem to modify its icon better put the logic for this to the icon itself, so every time Wicket renders an icon the icon itself calculates whether to be shown or not and what to graphics show.
I assume the ListView you're showing here is just rendering the "tabs", not the panels itself.
The currently visible ITab's panel is added somewhere else in MyTabbedPanel.
You could extend ITab:
public interface ILoadingTab extends ITab {
boolean isLoaded();
}
In #populateItem() add an icon to the ListItem depending on #isLoaded().
You tab implementation's #isLoaded() then asks LoadingPanel whether it has finished loading.
I am new to Vaadin and trying to know if it can suit my needs for a webapp project migration.
Actually I'm already loosing my time on a simple goal: to have a layout with fixed headers and footers, and a scrollable content in the middle.
I made a very basic fiddle with what I want:
jsfiddle
Here is the main Vaadin class I came up with:
public class MyVaadinUI extends UI {
// attributes
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = MyVaadinUI.class, widgetset = "testvaadin.aep.com.AppWidgetSet")
public static class Servlet extends VaadinServlet {
}
#Override
protected void init(VaadinRequest request) {
buildMainLayout();
}
private void buildMainLayout() {
final VerticalLayout mainLayout = new VerticalLayout();
mainLayout.setSizeFull();
//HEADER
final VerticalLayout headerLayout = new VerticalLayout();
final Resource res = new ThemeResource("img/logo.png");
final Image image = new Image(null, res);
headerLayout.addComponent(image);
//CONTENT
final VerticalLayout contentLayout = new VerticalLayout();
for(int i=0; i<80; i++){
contentLayout.addComponent(new Button("TEST " + i));
}
//FOOTER
final VerticalLayout footerLayout = new VerticalLayout();
footerLayout.addComponent(new Label("--------------------------- footer --------------------------"));
mainLayout.addComponent(headerLayout);
mainLayout.addComponent(contentLayout);
mainLayout.addComponent(footerLayout);
mainLayout.setExpandRatio(contentLayout, 1);
setContent(mainLayout);
}
}
The displayed page is OK on startup, but when I scroll down, the footer also scrolls (it is not fixed).
On startup:
When scrolled:
I browsed a lot of pages on this topic, but I did never see any correct answer. This seems to be rather complicated in Vaadin, although it is very simple in HTML; Vaadin may not suit my needs.
Anyway, do you know how can I achieve this behaviour?
Thanks!
You can use a Panel to create a scrollable center content area. See the example below.
For the panel to work, everything in the component hierarchy must be setSizeFull (or equivalent) and the content of the panel must not (in the example mainLayout and contentPanel are 100%, but contentLayout is not (implicit))
#Grapes([
#Grab('org.vaadin.spring:spring-boot-vaadin:0.0.3'),
#Grab('com.vaadin:vaadin-client-compiled:7.4.0.beta1'),
#Grab('com.vaadin:vaadin-themes:7.4.0.beta1'),
])
import com.vaadin.ui.*
#org.vaadin.spring.VaadinUI
class MyUI extends UI {
protected void init(com.vaadin.server.VaadinRequest request) {
final headerLayout = new VerticalLayout(new Label('HEADER'))
final footerLayout = new VerticalLayout(new Label('FOOTER'))
final contentLayout = new VerticalLayout()
80.times{ contentLayout.addComponent(new Button("TEST $it")) }
// XXX: place the center layout into a panel, which allows scrollbars
final contentPanel = new Panel(contentLayout)
contentPanel.setSizeFull()
// XXX: add the panel instead of the layout
final mainLayout = new VerticalLayout(headerLayout, contentPanel, footerLayout)
mainLayout.setSizeFull()
mainLayout.setExpandRatio(contentPanel, 1)
setContent(mainLayout)
}
}
(runs standalone with spring run vaadin.groovy)
Hi everyone I have this layout:
Here is the class MainLayout:
public class MainLayout extends VerticalLayout {
/**
*
*/
private static final long serialVersionUID = 1L;
private VerticalLayout upperSection = new VerticalLayout();
private HorizontalSplitPanel lowerSection = new HorizontalSplitPanel();
private VerticalLayout menuLayout = new VerticalLayout();
private VerticalLayout contentLayout = new VerticalLayout();
public MainLayout() {
upperSection.addComponent(new Label("Header"));
menuLayout.addComponent(new Label("Menu"));
contentLayout.addComponent(new Label("Content"));
lowerSection.addComponent(menuLayout);
lowerSection.addComponent(contentLayout);
addComponent(upperSection);
addComponent(lowerSection);
showBorders();
setSizeFull();
lowerSection.setSizeFull();
// menuLayout.setSizeFull();
contentLayout.setSizeFull();
setExpandRatio(lowerSection, 1);
//lowerSection.setSplitPosition(30);
}
private void showBorders() {
String style = "v-ddwrapper-over";
setStyleName(style);
upperSection.setStyleName(style);
lowerSection.setStyleName(style);
menuLayout.setStyleName(style + "-menu");
contentLayout.setStyleName(style + "-content");
}
#SuppressWarnings("serial")
public void addMenuOption(String caption, final Component component) {
Button button = new Button(caption);
menuLayout.addComponent(button);
button.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
contentLayout.removeAllComponents();
contentLayout.addComponent(component);
}
});
}
}
This layout class extends VerticalLayout and constructs the basic structure of the layout, the addMenuOption method adds a button to the left menu column and a click listener to it so that when the user clicks on the button the content layout on the right should switch its content from the current to the one bound with the button, now inside the init method of the UI:
protected void init(VaadinRequest request) {
MainLayout layout = new MainLayout();
layout.addMenuOption("Option 1", new Label("Component 1"));
layout.addMenuOption("Option 2", new Label("Component 2"));
setContent(layout);
}
Actually the result I obtain is this:
But my problem is that neither of the two buttons (Option 1, Option 2) are clickable.
Where is the problem?
Thanks for the attention!
You are right. Adding style "v-ddwrapper-over" to one of the components makes the buttons non-clickable. Lets take a look at definition of this style in style.css file.
.appName .v-ddwrapper-over:before, .so5 .v-ddwrapper-over:after {
content: "";
position: absolute;
z-index: 10;
top: -1px;
right: -1px;
bottom: -1px;
left: -1px;
border: 0 solid #197de1;
}
What's important is the fourth line with z-index. This brings a component (more specifficaly div in DOM) to the front covering all others components with less z-index value (usually they have 0).
If you really need this style to be applied to all your components (seems weird to me) consider adding additional style to the buttons with higher z-index value.
Learn more about z-index property here.
I have the following parent container:
public class ParentContainer extends Composite {
// Contains a bunch of TextButtons (RedButton, GreenButton, etc.).
private LayoutPanel buttonPanel;
// When user clicks a TextButton inside the buttonPanel,
// it changes the content of this contentPanel.
private LayoutPanel contentPanel;
}
So when the user clicks one of the TextButtons inside the buttonPanel, the contentPanel's contents change. I am trying to get each TextButton click to be remembered in history, using the Activities/Places framework. So, if the user clicks the "Red", "Green" and "Blue" buttons respectively, the contentPanel will change three times, and then they can click the Back/Forward browser history buttons and keep moving back and forth in history (and "replaying" the button clicks over and over again, etc.).
I also have the following classes:
com.mywebapp
MainModule.gwt.xml
com.mywebapp.client
MainModule
com.mywebapp.client.places
RedButtonPlace
GreenButtonPlace
BlueButtonPlace
... 1 place for all buttons
com.mywebapp.client.activities
RedButtonActivity
GreenButtonActivity
BlueButtonActivity
... 1 activity for all buttons
com.mywebapp.client.ui
ParentContainer
RedButton
GreenButton
BlueButton
BlackButton
PurpleButton
OrangeButton
I am planning on wiring things up such that:
PlaceController.goTo(new RedButtonPlace()) eventually routes to the RedButtonActivity
PlaceController.goTo(new GreenButtonPlace()) eventually routes to the GreenButtonActivity
etc. (every button has a place and activity per its color)
What I'm stuck on is: if I call PlaceController.goTo(new RedButtonPlace()) from inside a RedButton click handler, how and where do I instruct RedButtonActivity to update contentPanel? For instance:
public class RedButton extends TextButton {
// ... bunch of stuff, nevermind why I am extending TextButton
// this is just to help me connect all the major dots of GWT!
public RedButton() {
this.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
// If the RedButton is clicked, we want all the content in RedButtonActivity#RedButtonView
// to go inside ParentContainer#contentPanel.
PlaceController.goto(new RedButtonPlace());
}
});
}
}
public class RedButtonActivity extends AbstractActivity {
public interface RedButtonView extends IsWidget {
// Whatever the RedButton expects to be able to display.
}
private RedButtonView view;
#Override
public void start(AcceptsOneWidget panel, EventBus eventBus) {
// Probably injected via GIN.
view = somehowInjectTheView();
panel.setWidget(view);
}
}
That last line is the key here: panel.setWidget(view). How do we make sure that panel is the ParentContainer#contentPanel? Thanks in advance!
Edit: Per one answer suggests, here is a code update:
public class ParentContainer extends Composite {
// All the stuff that's up above in the first parent container.
public ParentContainer() {
super();
// Again, via GIN.
ActivityManager redButtonActivityManager = getSomehow();
redButtonActivityManager.setDisplay(contentPanel);
}
}
If this is the correct way, then I assume when the start(AcceptsOneWidget panel, EventBus eventBus) method is called, the redButtonActivityManager knows to inject the correct display for the panel argument?
You would pass the ParentContainer#contentPanel to the setDisplay() method of your ActivityManager as part of the manager's initialization.