1

我正在尝试使用 littemplate 从客户端调用服务器端函数。我有一个需要帮助的问题。我在服务器端添加了一个 HTML fromatted 文本,它有一个自定义组件“hello-world2”。

我在这个自定义组件中传递了一个属性(name="Vaadin")。我希望当用户单击“helloButton”时,应将值“Vaadin”发送到服务器并调用“acceptMessage”。但截至目前,我收到了附加屏幕截图中显示的错误。

我这样做是因为在我当前的应用程序中我已经生成了 HTML 表。对于几列我正在尝试合并和使用 <vaadin-button> HTML 标记。因此,当用户单击此按钮时,我希望服务器端出现消息/值以进行进一步处理。

请指导我如何做到这一点。

点亮模板

// hello-world2.ts
import { customElement, html, LitElement, property } from "lit-element";

import "@vaadin/vaadin-button/vaadin-button";
import "@vaadin/vaadin-text-field/vaadin-text-field";
import "@vaadin/vaadin-ordered-layout/vaadin-vertical-layout";
import { showNotification } from "@vaadin/flow-frontend/a-notification";


@customElement('hello-world2')
export class HelloWorld extends LitElement {

    public $server1?: HelloWorldServerInterface;

    @property({ type: String })
    name = '';

    render() {
        return html`<vaadin-vertical-layout theme="padding spacing">
        <vaadin-button id="helloButton" @click="${this.sendMessage}">Message Button</vaadin-button>
    </vaadin-vertical-layout>`;
    }

    sendMessage() {
        showNotification("Hello : " + this.name); //Works well, displays the notification
        this.$server1!.acceptMessage(this.name); // Issue here.

    }


}
interface HelloWorldServerInterface {
    greet(): void;
    acceptMessage(arg0: String): void;
}

爪哇

package com.example.application.views.helloworld;

import com.example.application.views.main.MainView;
import com.vaadin.flow.component.ClientCallable;
import com.vaadin.flow.component.Html;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.littemplate.LitTemplate;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.template.Id;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;

@CssImport("./views/helloworld/hello-world-view.css")
@Route(value = "hello", layout = MainView.class)

@PageTitle("Hello World")
//@Tag("hello-world2") -- Commented, if I uncomment this then I can see two buttons on browser.
@JsModule("./views/littemplate/hello-world2.ts")
public class HelloWorldView extends HorizontalLayout {

     public HelloWorldView() {   
        
         Html html = new Html("<hello-world2 name=\"Vaadin\"></hello-world2>");
         add(html);
        
     }
     
          @ClientCallable 
          public void acceptMessage(String message) {
          System.out.println("Message from client : " + message); 
          }
          
} 

在此处输入图像描述

在此处输入图像描述

4

3 回答 3

2

如果您想HelloWorldView在 Java 中代表<hello-world2>客户端自定义元素的 Java API,它应该扩展Component(或者LitTemplate如果您想使用@Id注释)而不是,HorizontalLayout您应该取消@Tag注释并删除new Htmladd(html)部分。

当您拥有@Tag("hello-world2")它时,意味着通过添加HelloWorldView到页面,它实际上添加了<hello-world2></hello-world2>,因为它被视为此 Java 组件的客户端表示。因此,当您还在构造函数中手动为其添加 HTML 时,您最终会得到<hello-world2><hello-world2></hello-world2></hello-world2>(这就是为什么您会看到两倍内容的原因)。

现在,当您在@Tag这里注释掉并扩展HorizontalLayout它时,它意味着HelloWorldView=<vaadin-horizontal-layout>组件,因为它继承了客户端的@Tag("vaadin-horizontal-layout")from HorizontalLayout(而不是您的自定义元素的直接 Java API <hello-world2>)。然后<vaadin-horizontal-layout>实例将获取该$server.acceptMessage()方法,因此您不能从thisin调用它,<hello-world2>因为它只会在其父级上声明。

这是我认为您正在尝试做的事情(或类似的事情)的工作示例(我对其进行了测试):

hello-world2.ts

import { customElement, html, LitElement, property } from 'lit-element';

import '@vaadin/vaadin-button/vaadin-button';
import '@vaadin/vaadin-ordered-layout/vaadin-vertical-layout';
import { showNotification } from '@vaadin/flow-frontend/a-notification';

@customElement('hello-world2')
export class HelloWorld2View extends LitElement {
  $server?: HelloWorldServerInterface;

  @property({ type: String })
  name = '';

  render() {
    return html`
      <vaadin-vertical-layout theme="padding spacing">
        <vaadin-button id="helloButton" @click="${this.sendMessage}">Message Button</vaadin-button>
      </vaadin-vertical-layout>
    `;
  }

  sendMessage() {
    showNotification("Hello : " + this.name);
    this.$server!.acceptMessage(this.name);
  }
}

interface HelloWorldServerInterface {
  greet(): void;
  acceptMessage(arg0: String): void;
}

HelloWorld2View.java

package com.example.application.views.helloworld;

import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.PageTitle;
import com.example.application.views.MainLayout;
import com.vaadin.flow.component.ClientCallable;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.dependency.JsModule;

@Route(value = "hello", layout = MainLayout.class)
@PageTitle("Hello World")
@Tag("hello-world2")
@JsModule("./views/littemplate/hello-world2.ts")
public class HelloWorld2View extends Component {
    public HelloWorld2View() {
        setName("Vaadin");
    }

    public void setName(String name) {
        getElement().setProperty("name", name);
    }

    @ClientCallable
    public void acceptMessage(String message) {
        System.out.println("Message from client : " + message);
    }
}

我不确定name这里属性的确切用例是什么,或者为什么要在组件的构造函数中设置它,但这里我还在 Java API 中为它添加了一个设置器。或者,您也可以在 TS 文件中设置默认值,name而不是在 Java 构造函数中设置它。

看起来您可能希望这<hello-world2>是一个旨在添加到视图中的组件(而不是单独表示整个视图)。在这种情况下,您应该有一个专门用于该组件的 TS 和 Java 文件(如上),然后在某个视图中使用它,并且HelloWorld2View上面的名称可能应该只是HelloWorld2或类似的名称,因此不会混淆为视图。

public class SomeOtherView extends Div {
    public SomeOtherView() {
        HorizontalLayout hl = new HorizontalLayout();
        HelloWorld2 helloComponent = new HelloWorld2();
        helloComponent.setName("Vaadin");
        hl.add(helloComponent);
        add(hl);
    }
}

或者

public class SomeOtherView extends HorizontalLayout {
    public SomeOtherView() {
        HelloWorld2 helloComponent = new HelloWorld2();
        helloComponent.setName("Vaadin");
        add(helloComponent);
    }
}
于 2021-06-22T10:13:53.610 回答
2

这是另一个可能更接近您想要的工作示例。

hello-world2.ts

import { customElement, html, LitElement, property } from 'lit-element';

import '@vaadin/vaadin-button/vaadin-button';
import '@vaadin/vaadin-ordered-layout/vaadin-vertical-layout';
import { showNotification } from '@vaadin/flow-frontend/a-notification';

@customElement('hello-world2')
export class HelloWorld2 extends LitElement {
  @property({ type: String })
  name = '';

  render() {
    return html`
      <vaadin-vertical-layout theme="padding spacing">
        <vaadin-button id="helloButton" @click="${this.sendMessage}">Message Button</vaadin-button>
      </vaadin-vertical-layout>
    `;
  }

  sendMessage() {
    const $server = (this.parentElement as HtmlElementWithMyViewServerInterface).$server;
    showNotification("Hello : " + this.name);
    $server!.acceptMessage(this.name);
  }
}

interface MyViewServerInterface {
  acceptMessage(message: String): void;
}

interface HtmlElementWithMyViewServerInterface extends HTMLElement {
  $server?: MyViewServerInterface;
}

MyView.java

@Route(value = "myview", layout = MainLayout.class)
@PageTitle("My View")
@JsModule("./views/littemplate/hello-world2.ts")
public class MyView extends HorizontalLayout {
  public MyView() {
    Html html = new Html("<hello-world2 name='Vaadin'></hello-world2>");
    add(html);
  }

  @ClientCallable
  public void acceptMessage(String message) {
    System.out.println("Message from client : " + message);
  }
}

虽然理想情况下,您还应该有一个 Java 组件类,<hello-world2>并在视图中使用它而不是Html组件。这可能看起来像这样:

HelloWorld2.java

@Tag("hello-world2")
@JsModule("./views/littemplate/hello-world2.ts")
public class HelloWorld2 extends Component {
    public HelloWorld2() {
        setName("");
    }

    public HelloWorld2(String name) {
        setName(name);
    }

    public void setName(String name) {
        getElement().setProperty("name", name);
    }
}

MyView.java

@Route(value = "myview", layout = MainLayout.class)
@PageTitle("My View")
public class MyView extends HorizontalLayout {
  public MyView() {
    add(new HelloWorld2("Vaadin"));
  }

  @ClientCallable
  public void acceptMessage(String message) {
    System.out.println("Message from client : " + message);
  }
}
于 2021-06-22T13:06:54.483 回答
1

Vaadin 设置了一个名为 $server 的变量,您无法更改此名称。这就是您出现错误的原因,因为 $server1 不存在。

您应该将 $server1 重命名为 $server 并且它应该可以工作。

于 2021-06-21T19:45:12.353 回答