Показаны сообщения с ярлыком vaadin. Показать все сообщения
Показаны сообщения с ярлыком vaadin. Показать все сообщения

Редактируем колонку таблицы

Ни для кого не секрет, что vaadin таблицу можно сделать редактируемой, если вызвать метод table.setEditable(true) и наоборот. В этом случае редактировать можно все ячейки.

Но что, если необходимо редактировать ячейки только одной колонки? Например так:

Форумы и «Book of Vaadin» подсказывают, что надо использовать TableFieldFactory. Например: https://vaadin.com/book/-/page/components.table.html, параграф «Navigation in Editable Mode».

Собственно, примерно так должен выглядеть код:

// создаем таблицу и определяем ее колонки
Table table = new Table();
table.addContainerProperty("num", Integer.class, null);
table.addContainerProperty("name", String.class, null);
table.addContainerProperty("age", String.class, null);

// переопределяя метод создания редактируемых полей, мы просто 
// указываем конкретную колонку или колонки, для которых надо 
// создавать эти самые поля
table.setTableFieldFactory(new TableFieldFactory() {
   @Override
   public Field createField(Container c, Object itemId, 
         Object propertyId, Component uiContext) {
      TextField field = null;

      if ("age".equals(propertyId)) {
         field = new TextField((String) propertyId);
         field.setWidth("100%");
      }

      return field;
   }
});

// а это позволит проверить работоспособность примера по 
// двойному нажатию мышки на табличке
table.addListener(new ItemClickEvent.ItemClickListener() {
   @Override
   public void itemClick(ItemClickEvent event) {
      if (event.isDoubleClick()) {
         table.setEditable(!table.isEditable());
      }
   }
});

// осталось заполнить таблицу данными и запустить приложение
int index = 1;
table.addItem(new Object[]{index, "Nathan Fielding", 41}, index++);
table.addItem(new Object[]{index, "John Smith", 26}, index++);
table.addItem(new Object[]{index, "Jane Hill", 88}, index++);
table.addItem(new Object[]{index, "John Sheridan", 32}, index++);
table.addItem(new Object[]{index, "Marc Torvalds", 40}, index++);
table.addItem(new Object[]{index, "Sarah Richards", 34}, index++);
table.addItem(new Object[]{index, "Peter Fielding", 85}, index++);
table.addItem(new Object[]{index, "Lenny Sheridan", 32}, index++);
table.addItem(new Object[]{index, "Lenny McGoff", 70}, index++);
table.addItem(new Object[]{index, "John Halas", 72}, index++);

Selenium проблема с Vaadin ComboBox

При написании selenium теста я столкнулся с ситуацией, когда стандартный метод type(locator, text) никак не взаемодействовал с vaadin элементом ComboBox. Ну и не только с ним.

Для решения проблемы, selenium позволяет генерировать HTML DOM Events при помощи метода fireEvent(locator, eventName), например:

public void typeInVaadinComboBox(String locator, String text) {
    fireEvent(locator, "keydown");
    type(locator, text);
    fireEvent(locator, "keypress");
    fireEvent(locator, "keyup");
}

Это решает данную проблему, а также позволяет взаимодействовать с другими недружелюбными элементами, например строками таблиц.

Доп. материалы:
http://www.w3schools.com/jsref/dom_obj_event.asp
http://www.quirksmode.org/dom/events/index.html
http://java.dzone.com/articles/testing-gwt-apps-selenium-or
http://blog.softwaretestingclub.com/2011/04/selenium-commands-locators-explained

Vaadin сервлет приложение внутри портлета

Это всего-лишь небольшой трюк, который кому-то пригодится, а кому-то нет. Речь пойдет о Liferay портале, портлетах и Vaadin приложении.

Как известно, Vaadin позволяет создать как сервлетное так и портлетное приложение. Портлеты же позволяют создавать внутри себя сервлеты. Предлагаемый трюк можно представить себе как Vaadin сервлет приложение врнутри портлета. То есть именно сервлетное приложение.

Что для этого надо:

  1. Создать портлет используя liferay-sdk;
  2. В файле liferay-plugin-package.properties указать зависимость для библиотеки vaadin.jar:
    portal-dependency-jars=vaadin.jar
    
  3. Описать приложения в web.xml:
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://java.sun.com/xml/ns/javaee"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
       id="WebApp_ID" version="2.5">
    
       <display-name>dashboard</display-name>
    
       <context-param>
          <description>Vaadin production mode</description>
          <param-name>productionMode</param-name>
          <param-value>false</param-value>
       </context-param>
    
       <servlet>
          <display-name>Dashboard</display-name>
          <servlet-name>dashboardServlet</servlet-name>
          <servlet-class>
             com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
    
          <init-param>
             <param-name>application</param-name>
             <param-value>org.demo.dashboard.DashboardApplication</param-value>
          </init-param>
       </servlet>
    
       <servlet-mapping>
          <servlet-name>dashboardServlet</servlet-name>
          <url-pattern>/*</url-pattern>
       </servlet-mapping>
    </web-app>
    
  4. Написать само приложение:
    package org.demo.dashboard;
    
    import com.vaadin.Application;
    import com.vaadin.ui.Label;
    import com.vaadin.ui.Window;
    
    public class DashboardApplication extends Application {
       @Override
       public void init() {
          Window mainWindow = new Window("Dashboard Application");
          setMainWindow(mainWindow);
    
          String AE = "Make everything as simple as possible, but not simpler.";
          mainWindow.addComponent(new Label(AE));
        }
    }
    
  5. Ну и собственно url — {host}/dashboard-portlet, например:
    http://localhost:7080/dashboard-portlet
    

К такому приложению можно обращаться по фиксированной линке, вход на сайт не нужен, это не часть страницы портала, не надо ломать голову со стилями портала и размерами занимаемого пространства, это просто vaadin приложение. Плюс еще в том, что приложение разворачивается внутри портлета, а это дает возможность использовать весь функционал портала, который доступен в портлете.

Как использовать пусть каждый придумает сам, в моем случае это некий dashboard-portlet, который позволяет быстро выполнять рутинные задачи. Как я уже говорил — это всего-лишь небольшой трюк, который кому-то пригодится, а кому-то нет.

Валидация непустых полей

Оказывается, в Vaadin 6.7.8 невозможно валидировать текстовое поле на непустое значение. Можно пометить его как обязательное и тогда, вызывая метод commit этого поля, возникает исключение — com.vaadin.data.Validator.EmptyValueException. При этом, если поле размещается вручную, то визуально ошибку не будет видно. Имеется ввиду, что поле не является частью какой-нибудь стандартной формы фреймворка, типа com.vaadin.ui.Form.

Может это дефект, а может задумка, но как выход можно показать сообщение об ошибке в заранее определенном месте, например так: http://demo.vaadin.com/sampler#FormBasic. Для вывода сообщения можно использовать компонент com.vaadin.ui.Label. Вызов метода commit нашего поля надо поместить в блок try-catch. При возникновении исключения EmptyValueException вручную задать сообщение об ошибке используя метод setComponentError компонента label. Можно также добавить логику, которая покажет label с сообщением, когда произойдет ошибка, а в любом другом случае — скроет его.

Небольшой пример:
public class UserForm extends VerticalLayout {
    private TextField name;
    private Button apply;
    private Label error;

    public UserForm() {
        setSizeFull();
        setSpacing(true);

        name = new TextField("Name");
        name.setRequired(true);
        name.setRequiredError("Please enter a valid name");
        addComponent(name);

        error = new Label();
        error.setVisible(false);
        addComponent(error);

        apply = new Button("Apply");
        addComponent(apply);

        apply.addListener(new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                try {
                    name.commit();
                } catch (Validator.InvalidValueException e) {
                    error.setCaption(e.getMessage());
                    error.setComponentError(e);
                    error.setVisible(true);
                }
                error.setVisible(false);
            }
        });
    }
}
Henri Sara объясняет причину: https://vaadin.com/forum/-/message_boards/view_message/365283