Data binding Vaadin 8活页夹中相关计算特性的自动更新显示

Data binding Vaadin 8活页夹中相关计算特性的自动更新显示,data-binding,vaadin,vaadin8,Data Binding,Vaadin,Vaadin8,在Vaadin 8中使用活页夹时,如果bean具有只读计算属性(其值源自另一个属性),如何获取文本字段,以便在驱动属性的值发生更改时自动更新导出计算结果的显示 在下面的示例中,当用户更改“出生年份”字段时,如何让“年龄”字段更新其计算 Vaadin 8的完整工作示例 package com.example.val; import com.vaadin.annotations.Theme; import com.vaadin.annotations.VaadinServletConfigura

在Vaadin 8中使用
活页夹
时,如果bean具有只读计算属性(其值源自另一个属性),如何获取
文本字段
,以便在驱动属性的值发生更改时自动更新导出计算结果的显示

在下面的示例中,当用户更改“出生年份”字段时,如何让“年龄”字段更新其计算

Vaadin 8的完整工作示例

package com.example.val;

import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.data.Binder;
import com.vaadin.data.converter.StringToIntegerConverter;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.*;

import javax.servlet.annotation.WebServlet;
import java.time.LocalDate;
import java.time.ZoneId;

/**
 * This UI is the application entry point. A UI may either represent a browser window
 * (or tab) or some part of a html page where a Vaadin application is embedded.
 * <p>
 * The UI is initialized using {@link #init(VaadinRequest)}. This method is intended to be
 * overridden to add component to the user interface and initialize non-component functionality.
 */
@Theme ( "mytheme" )
public class MyUI extends UI {

    Person person;
    Binder < Person > binder;

    @Override
    protected void init ( VaadinRequest vaadinRequest ) {
        // Data model
        this.person = new Person ( "Jean-Luc", 1955 );

        // Widgets
        final TextField nameField = new TextField ( "Type the person’s name here:" );
        final TextField yearOfBirthField = new TextField ( "Type the year of birth here:" );
        final TextField ageField = new TextField ( "Approximate age:" );
        ageField.setReadOnly ( true );
        final Label beanToString = new Label ( );

        // Binder
        this.binder = new Binder <> ( );
        binder.forField ( nameField )
                .bind ( Person:: getName, Person:: setName );
        binder.forField ( yearOfBirthField )
                .withConverter ( new StringToIntegerConverter ( "Input must be Integer" ) )
                .bind ( Person:: getYearOfBirth, Person:: setYearOfBirth );
        binder.forField ( ageField )
                .withConverter ( new StringToIntegerConverter ( "" ) )
                .bind ( Person:: getAge, null );
        binder.setBean ( this.person );

        final Button button = new Button ( "Save" );
        button.addClickListener ( event -> {
            if ( binder.validate ( ).isOk ( ) ) {
                // With `setBear`, the Person object is always up-to-date as long as there are no validation errors.
                // MyBackend.updatePersonInDatabase(person);
                beanToString.setValue ( this.person.toString ( ) );
            } else {  // Else bean flunks validation.
                beanToString.setValue ( "The Person bean has invalid state." );
            }
        } );


        this.setContent ( new VerticalLayout ( nameField, yearOfBirthField, ageField, button, beanToString ) );
    }

    @WebServlet ( urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true )
    @VaadinServletConfiguration ( ui = MyUI.class, productionMode = false )
    public static class MyUIServlet extends VaadinServlet {
    }
}

class Person {
    private Integer yearOfBirth;
    private String name;


    public Person ( String name_, Integer yearOfBirth_ ) {
        this.name = name_;
        this.yearOfBirth = yearOfBirth_;
    }

    public String getName ( ) {
        return name;
    }

    public void setName ( String name ) {
        this.name = name;
    }

    public Integer getYearOfBirth ( ) {
        return yearOfBirth;
    }

    public void setYearOfBirth ( Integer yearOfBirth ) {
        this.yearOfBirth = yearOfBirth;
    }

    // Read-only property 'age', calculated rather than stored.
    public Integer getAge ( ) {
        LocalDate today = LocalDate.now ( ZoneId.systemDefault ( ) );
        Integer years = ( today.getYear ( ) - this.yearOfBirth );
        return years;
    }

    @Override
    public String toString ( ) {
        return "Person{ " +
                "yearOfBirth=" + yearOfBirth +
                ", age='" + this.getAge ( ) + "'" +
                ", name='" + name + "'" +
                " }";
    }
}
package com.example.val;
导入com.vaadin.annotations.Theme;
导入com.vaadin.annotations.VaadinServletConfiguration;
导入com.vaadin.data.Binder;
导入com.vaadin.data.converter.StringToIntegerConverter;
导入com.vaadin.server.vaadin请求;
导入com.vaadin.server.VaadinServlet;
导入com.vaadin.ui.*;
导入javax.servlet.annotation.WebServlet;
导入java.time.LocalDate;
导入java.time.ZoneId;
/**
*此UI是应用程序入口点。UI可以表示浏览器窗口
*(或选项卡)或嵌入Vaadin应用程序的html页面的某些部分。
*
*UI是使用{@link#init(VaadinRequest)}初始化的。该方法旨在:
*重写以将组件添加到用户界面并初始化非组件功能。
*/
@主题(“神话主题”)
公共类MyUI扩展了MyUI{
个人;
活页夹<人>活页夹;
@凌驾
受保护的void init(VaadinRequest VaadinRequest){
//数据模型
此人=新人(“Jean-Luc”,1955年);
//小部件
final TextField nameField=new TextField(“在此处键入此人姓名:”);
final TextField yearOfBirthField=新TextField(“在此处键入出生年份:”);
最终文本字段年龄字段=新文本字段(“近似年龄:”);
ageField.setReadOnly(true);
最终标签beanToString=新标签();
//活页夹
this.binder=新的binder();
binder.forField(名称字段)
.bind(Person::getName,Person::setName);
binder.forField(出生年份)
.withConverter(新的StringToIntegerConverter(“输入必须是整数”))
.bind(Person::getYearOfBirth,Person::setYearOfBirth);
binder.forField(ageField)
.带转换器(新StringToIntegerConverter(“”)
.bind(Person::getAge,null);
binder.setBean(此人);
最终按钮=新按钮(“保存”);
button.addClickListener(事件->{
if(binder.validate().isOk()){
//使用“setBear”,只要没有验证错误,Person对象总是最新的。
//MyBackend.updatepersoninandabase(个人);
beanToString.setValue(this.person.toString());
}else{//else bean未通过验证。
setValue(“Person bean的状态无效。”);
}
} );
this.setContent(新的垂直布局(名称字段、出生年份字段、年龄字段、按钮、BeantString));
}
@WebServlet(urlPatterns=“/*”,name=“MyUIServlet”,asyncSupported=true)
@VaadinServletConfiguration(ui=MyUI.class,productionMode=false)
公共静态类MyUIServlet扩展了VaadinServlet{
}
}
班主任{
私人整数出生年份;
私有字符串名称;
公众人物(字符串名称,整数出生年份){
this.name=name_u2;;
this.yearOfBirth=出生年份;
}
公共字符串getName(){
返回名称;
}
公共void集合名(字符串名){
this.name=名称;
}
公共整数getYearOfBirth(){
返回出生年份;
}
公共无效设置出生年份(整数出生年份){
this.yearOfBirth=出生年份;
}
//只读属性“年龄”,计算而不是存储。
公共整数getAge(){
localdatetoday=LocalDate.now(ZoneId.systemDefault());
整数年=(today.getYear()-this.yearOfBirth);
回归年;
}
@凌驾
公共字符串toString(){
返回“Person{”+
“出生年份=”+出生年份+
,age='+this.getAge()+''+
“,name=”“+name+””+
" }";
}
}

我发现的最简单的方法是用以下方式修改
出生年份字段的绑定代码:

binder.forField(yearOfBirthField)
    .withConverter(new StringToIntegerConverter("Input must be Integer"))
    .bind(Person::getYearOfBirth, (Setter<Person, Integer>) (person1, integer) -> {
                person1.setYearOfBirth(integer);
                ageField.setValue(person1.getAge().toString());
            });
binder.forField(出生年份)
.withConverter(新的StringToIntegerConverter(“输入必须是整数”))
.bind(Person::getYearOfBirth,(Setter)(person1,integer)->{
person1.设置出生年份(整数);
ageField.setValue(person1.getAge().toString());
});
这将有效地将
yearOfBirthField
绑定到
yearOfBirth
属性,并更新person bean的
age
属性。 以任何方式更改person bean的成员,例如通过调用
person.setYearOfBirth(1977)
对字段没有直接影响。Vaadin的更新机制只在一个方向起作用。字段修改被传输到bean,但反之亦然

编辑

在vaadin8中,没有内置的方法在bean属性发生更改时自动更新字段。当
yearOfBirthField
的值更改时,新值将传播到person bean,person的
yearOfBirth
成员将通过绑定自动更改。但是之后,Vaadin不会获取bean的所有绑定字段的当前值。因此,
ageField
不会更新,也不会反映当前值

因此,要使
ageField
显示更新的值,您必须更新
ageField
程序
if (binder.validate().isOk()) {

  // Force update of the Fields...
  binder.readBean(binder.getBean());

  beanToString.setValue(person.toString());
} else {
  beanToString.setValue("The Person bean has invalid state.");
}