jueves, 6 de febrero de 2020

28. Vaadin 14. How to display programmatically components to the OpenXava (C) way

1. Introduction

OpenXava is a wonderful framework based on the Model. I love it. I am a fan of its creator Mr. Javier Paniza. He has designed a nomenclature for defining the "view" part of an MVC pattern. As he states, programmers can devote to business logic instead of designing complicated HTML, CSS or javascript code on the client-side.
Now responsiveness is a must.

Vaadin has a Horizontal and a Vertical  Layout component, that seems responsive, but when you nest them it is very difficult for me to keep track of the CSS code added by Vaadin Themes.. so you cannot predict how the information is displayed

After struggling about for some days and googling some days too, I found the CSS flex property

Another problem is that you cannot know the real width and height of the components in run time, you should use some unpredictable javascript code that is not recommended.

2. Designing the layout


A simple definition of a view in OpenXava could be:
--------------------------------------------------------------------------------------------------------------------
student   [ firstName,    lastName;
            address       [streetName, number, city ],
            parents       [mother,     father]
          ];
Sports    [ firstSport;   secondSport]
--------------------------------------------------------------------------------------------------------------------

That should produce something like this:

+------------------------------------------------------------------------------+
| +--------------------------------------------------------------------------+ |
| |                                  Student                                 | |
| +--------------------------------------------------------------------------+ |
| |             +-------------+             +-------------+                  | |
| | First Name: |             Last Name: |             |                  | |
| |             +-------------+             +-------------+                  | | 
| | +---------------------------------------+ +----------------------------+ | | 
| | |            Address                    | |          Parents           | | |
| | +---------------------------------------+ +----------------------------+ | |
| | |        +------+    +---+       +----+ | |     +------+      +------+ | | |
| | | Street:|      | N. |   | City: |    | | | Mom:|      | Dad: |      | | | |
| | |        +------+    +---+       +----+ | |     +------+      +------+ | | |
| | +---------------------------------------+ +----------------------------+ | |
| |                                                                          | |
| +--------------------------------------------------------------------------+ |
| |                              Sports                                      | |
| +--------------------------------------------------------------------------+ |
| | |                +----------------------------------------+              | |
| | |  First Sport:  |                                        |              | |
| | |                +----------------------------------------+              | |
| | |                +----------------------------------------+              | |
| | |  Second Sport: |                                        |              | |
| | |                +----------------------------------------+              | |
| +--------------------------------------------------------------------------+ |
+------------------------------------------------------------------------------+



Now to simplify I will be using this pseudo Html structure:

Main form: (Horizontal Panel)
   |
   +--> Vertical Panel
        |
        +--> Horizontal Panel (Student)
        |    |
        |    +--> Vertical Panel
        |         |
        |         +--> Horizontal Panel (line of controls)
        |         |    |
        |         |    +--> Field (First Name)
        |         |    |
        |         |    +--> Field (Last Name)
        |         |     
        |         +--> Horizonal Panel  
        |              |
        |              +--> Vertical Panel
        |                   |
        |                   +--> Horizontal Panel (Address)
        |                   |    |
        |                   |    +--> Vertical Panel 
        |                   |        |   
        |                   |        +--> Horizontal Panel (line of controls)
        |                   |             |
        |                   |             +--> Field (Street)
        |                   |             |
        |                   |             +--> Field (Num)
        |                   |             | 
        |                   |             +--> Field (City)
        |                   |
        |                   +--> Horizontal Panel (Parents)
        |                        |
        |                        +--> Vertical Panel 
        |                             |   
        |                             +--> Horizontal Panel (line of controls)
        |                                  |
        |                                  +--> Field (Mom)
        |                                  |
        |                                  +--> Field (Dad)
        +--> Horizonal Panel (Sports) 
             |
             +--> Vertical Panel
                  |
                  +--> Horizontal Panel (line of controls)
                  |    |
                  |    +--> Field (First Sport)
                  |     
                  +--> Horizontal Panel (line of controls)

                       |                        


                       +--> Field (Second Sport)



Note that every group of fields (marked in OpenXava between brackets [..]) is formed by Horizontal Panel + Vertical panel 

Note that each line of controls is formed by a Horizontal Panel 

So the algorithm should identify the elements:

  • group of controls (between brackets [])
  • lines of controls (identified by comma and semicolons (,;)
  • controls 

2. Implementing Horizontal and Vertical Panels for containers and lines of controls in Vaadin

The simple Vaadin Div component and the CSS flex and @media  elements can perform the magic.

The @media is used for determining the form the components are arranged depending on the size of the screen (so we can predict if the user is managing a big screen, tablet or phone)

The flex element is used to wrap controls in a line (line of controls), so we do not need to worry about the length of the controls when they are contained in a line.

Here is  CSS code

/* For using with OX components.*/ 

/*----------------------------------------------------------*/
/* VERTICAL PANEL */
/*----------------------------------------------------------*/ 

/* For vetical layout */
 .flex-column {
    display: flex;
    flex-direction: column;
    flex: 1;
 }


/*----------------------------------------------------------*/
/* HORIZONTAL PANEL: BIG SCREENS */
/*----------------------------------------------------------*/ 
    /* For horizontal layout (line of controls) */
 .flex-row {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    width: 100%;
 }
 
 
 
 /*When sharing a horizontal with a number of group of controls*/
 .share-with-1 {
  width: 100%;
 }
 .share-with-2 {
  width: 50%;
 }
 .share-with-3 {
  width: 33%;
 }
 .share-with-4 {
  width: 25%;
 }
 .share-with-5 {
  width: 20%;
 }
 .share-with-6 {
  width: 16%;
 }
 .share-with-7 {
  width: 14%;
 }
 .share-with-8 {
  width: 12%;
 }
 .share-with-9 {
  width: 11%;
 }
 .share-with-10 {
  width: 10%;
 }
 
 
/*----------------------------------------------------------*/
/* HORIZONTAL PANEL: MEDIUM SCREENS */
/*----------------------------------------------------------*/ 
 @media all and (max-width: 1000px) {
    .flex-row  {
       /* When on medium sized screens, we center it by evenly distributing empty space around items */
       justify-content: space-around;
    }
    .share-with-1 {
       width: 100%;
    }
    .share-with-2 , .share-with-3 , .share-with-4 , .share-with-5 ,
    .share-with-6 , .share-with-7 , .share-with-8 , .share-with-8 ,
    .share-with-10 {
       width: 50%;
    }
 }

/*----------------------------------------------------------*/
/* HORIZONTAL PANEL: SMALL SCREENS */
/*----------------------------------------------------------*/ 
 @media all and (max-width: 600px) {
    .flex-row  {
     /* On small screens, we are no longer using row direction but column */
     flex-direction: column;
    }
   .share-with-1 , .share-with-2 , .share-with-3 , .share-with-4 ,
  .share-with-5 , .share-with-6 , .share-with-7 , .share-with-8 ,
  .share-with-9 , .share-with-10 {
   width: 100%;
  }
 }
 
 

The vertical panel properties are not affected by the screen size.

. However, horizontal panels must adapt to the width of the screen. (class flex-column)

For groups of controls in one line, in big displays, it is accepted up to 10 columns, in medium ones, 2 columns are accepted and in small devices only one column (class share-with-number_of_groups)

The lines of controls are managed with the flex component (class flex-row).  The behavior (number of columns) can vary depending on both the width of the controls (wrapping) and the width of the screen.



2 comentarios:

  1. Hi, can you post an example on the usage of this CSS file?

    ResponderEliminar
    Respuestas
    1. Hi IIB User, thanks for your question. You are right, I've missed the code to show the components. I am planning a new post for this.

      Eliminar