为NPS反馈创建自定义组件
#java #vaadin #component #nps

我们有一个项目需要实施著名的Net Promoter Score或NPS反馈。很无聊,tbh。您需要拥有的那些相对微不足道的UI之一。 ("Does this spark joy?"绝对是一个清晰的“否。” )。

Image description

但是,有一个充分的理由收集这样的用户反馈,我们想拥有它。我立即认为这样的事情是单独的组成部分(主要是avoid doing it again)是有意义的,所以我决定这样做。

这是我构建可重复使用版本的过程。该博客再次适用于Vaadin,但是原理和“构建可重复使用的组件” - 在任何网络或IU框架上都有意义。

创建一个新的附加项目

可重用性的第一步:我们想创建一个单独的附加项目。我从GitHub使用了Vaadin默认addon-template,并在我的帐户下创建了一个新的存储库。该项目是一个很好的起点,因为它为包装和分发提供了样板。

克隆本地项目

接下来,在Visual Studio Code中本地克隆存储库项目。我正在使用Dev Containers与其他项目分开运行该项目。有一个现成的Java容器,我将Maven添加到该容器中。

vaadin提示:升级到v24
在撰写本文时,模板项目仍在较旧的vaadin 23上。因此,pom.xml需要进行较小的更新以使其与最新的vaadin版本兼容。

  • vaadin版本为24.0.5
  • Java版本为17
  • 码头版本为11.0.15

UI代码

就像我一开始说的那样,UI非常简单,并且代码创建的代码不是太多:

public NPS() {
    Span title = new Span("On a scale of 1 to 10, how likely would you recommend this to your friend or colleague?");
    HorizontalLayout buttons = new HorizontalLayout();
    buttons.add(new Text("Not likely"));
    for (int i = 1; i <= 10; i++) {
        Button button = new Button(String.valueOf(i), e -> {
            int score = Integer.parseInt(e.getSource().getText());
            Notification.show("Changed to "+score);
        });  
        buttons.add(button);
    }
    buttons.add(new Text("Very likely"));
    this.add(title, buttons);    
}

因此,水平布局中的标题和按钮列表。如果您想尝试并使用"copy-paste reusability",这已经是可用的。

考虑组件可重复使用性

制作可重复使用的组件时,您想考虑一些事情。记录组件的最简单方法是创建一个自称的API。

  • 组件UX。您需要键盘导航吗?鼠标悬停?捷径?我建议保持安全,将existing components结合在一起,并谨慎地使您的自定义解决方案。
  • 组件配置或DX。您希望能够以各种方式改变文本和行为。 combinations can get tricky,所以您想经过各种测试。
  • ui集成。您的组件是否仅使用(即单组分应用程序)?它会在弹出窗口中,还是它是其他UI的一部分? 数据集成。您的组件发射事件吗?它支持数据绑定吗?在服务器上缓存多少数据,浏览器可以处理多少?
  • 兼容性。您正在使用什么框架版本?您希望用户使用哪个版本? Java版本怎么样?请记住,依赖项与Venn diagrams一样工作,因此请保持清单。
  • 测试。如何自动化测试。如前所述,状态的配置可能会很棘手,因此您想在这里保持良好状态,以确保找到边缘案例。
  • 文档。如果您在API方面做得好,则该部分应该很简单。专注于描述开发人员用例,然后跳过“此方法x”样式文档。

可能需要一两个回合才能使一切正确,但最好从您使用它的“真实应用程序”开始,并编写使用组件的代码。不是为了满足成熟的TDD,这是我为测试所做的:

final NPS nps = new NPS();
nps.setId("nps");  // This is for automated tests

// Button to start the feed process
add(new Button("Ask NPS", e -> {
    add(nps);
}));

// Get the score and remove component
nps.addValueChangeListener(e-> {
    Notification.show("Value changed from "+e.getOldValue()+" to "+e.getValue());
    add(new Paragraph("NPS: " +e.getOldValue()+" -> "+e.getValue()));
    remove(nps);
});

// Edit the the score
add(new Button("Edit score", e -> {
    nps.setValue((int)Math.ceil(Math.random()*10));
    add(nps);
}));

这是在AddonView.java中实现的,也用于自动测试。这不是真实的事情,而是模拟我们在实际应用中的方案。

基本业务逻辑

由于NPS组件显然是具有单个可编辑值的“字段组件”,因此我们可以在此处重复使用框架功能。扩展CustomField为我们提供了价值输入和事件所需的大多数功能。我们只需要实施以下内容:

protected Integer generateModelValue() {
    return this.score;
}

protected void setPresentationValue(Integer score) {
    this.score = score;        
}

我们的测试案例已经显示出仅阅读支持的问题。我们希望值可见,但输入已禁用。这些需要另外两种方法要实现。

首先,突出显示选择。我们使用“成功颜色”来做到这一点。

private void updateButtonSate() {
    this.buttons
        .getChildren()
        .filter(c -> c instanceof Button)
        .forEach(c -> {
            Button b = (Button)c;
            if (score != null && score.equals(Integer.parseInt(b.getText()))) {
                b.addClassName(LumoUtility.Background.SUCCESS_50);
                b.addClassName(LumoUtility.TextColor.SUCCESS_CONTRAST);
            } else {
                b.removeClassName(LumoUtility.Background.SUCCESS_50);
                b.removeClassName(LumoUtility.TextColor.SUCCESS_CONTRAST);
            };
        });
}

然后,当我们处于仅阅读状态时,另一个可以禁用按钮。

public void setReadOnly(boolean readOnly) {
    super.setReadOnly(readOnly);
    this.buttons
        .getChildren()
        .filter(c -> c instanceof Button)
        .forEach(c -> ((Button)c).setEnabled(!readOnly));
}

现在我们有事件,我们得到了组件价值簿记。

发布,发布

Release early, release often”,对吗?这就是创建一个简单的应用程序,该应用程序从用户那里收集NPS反馈。如您所见,它只是Web UI部分,您仍然需要存储数据并计算最终分数。

您可能拥有您的自定义数据库,我们仍然需要打包组件以进行分发,但是我将在下一篇博客文章中显示一些简单的选项。同时:在github.com/samie/nps上查看组件。

这种可重复使用实际上会引起欢乐,但是现在轮到您:以1到10的比例,您有可能向您的朋友或同事推荐此NPS调查?在下面发表评论。