在foreach循环中将变量传递给函数

时间:2020-11-12 22:01:08

标签: java teavm teavm-flavour

我想问一下std:foreach中的变量是如何处理的? 我有这样一种情况,即同一个对象传递给一个函数,无论它不是应该传递的那个对象:

<std:foreach var="property" in="properties">
  <button onclick="unhide('collapse-primitive')"/>
  <span class="hidden" id="collapse-primitive">
    <ul class="">
      <li event:async-click="setItemPropertyType(property, 'String')">String</li>
      <li event:async-click="setItemPropertyType(property, 'Boolean')">Boolean</li>
      <li event:async-click="setItemPropertyType(property, 'Integer')">Integer</li>
      <li event:async-click="setItemPropertyType(property, 'Long')">Long</li>
      <li event:async-click="setItemPropertyType(property, 'Double')">Double</li>
      <li event:async-click="setItemPropertyType(property, 'Set')">Set</li>
      <li event:async-click="setItemPropertyType(property, 'List')">List</li>
      <li event:async-click="setItemPropertyType(property, 'Map')">Map</li>
    </ul>
  </span>
</std:foreach>

上面的代码为属性列表中的每个项目生成一个跨度,问题是函数setItemPropertyType总是获取第一个项目,而这是一个循环,因此意味着为每个setItemPropertyType传递的对象跨度中的方法应该不同。如果我的解释还不够,请原谅,但是代码本身是不言自明的。

现在的问题是,无论用户单击其他li中的span,为什么将同一个对象传递给方法?

我还怀疑是由于id="collapse-primitive"导致了这种奇怪的行为。但是,我不知道如何在没有和id的情况下进行测试,因为我不知道如何在Flavour中执行此操作,这意味着当单击按钮时,如何在代码中注入跨度,而id只是“隐藏”或使用CSS“显示”它。好的,这是另一个问题。

所以我的问题总结如下:

  1. 为什么std:foreach在每个函数中都传递相同的(第一个)变量 事件:异步点击
  2. 如何为此问题注入一个span或任何div元素 甚至单击按钮还是Flavour的操作方式是什么?

1 个答案:

答案 0 :(得分:-1)

解决方案是创建类似于Dropdown组件的组件,该组件可以通过HTML包装器将自身呈现为DOM。

在TeaVM中,可以通过以下方法解决:

public interface DropdownContent {
  void setDelegate(DropdownDelegate delegate);
}

此内容可以是任何HTML,并具体表示为:

@BindTemplate("templates/views/custom-dropdown-content.html")
public class CustomDropdownContent implements DropdownContent {
}

使用此HTML模板:

<span>
   <ul>
     <li>Item1</li>
     <li>Item2</li>
     <li>Item3</li>    
   </ul>
</span>

显然,其他任何具体的实现都可以使用任何HTML模板完成。

现在,这仍然只是必须通过某种静态方法显示给DOM的内容,该方法可以帮助快速构建组件UI

public void showDropdown(MouseEvent event) {
    HTMLElement element = (HTMLElement) event.getTarget();
    DropdownContent content = new CustomDropdownContent();
    Dropdown.show(content, element);
}

如果可以在DOM中的任何位置进行渲染,则HTML element是可选的,如果是这种情况,则可以在Dropdown.show()方法内实现典型的DOM注入:

document.getBody().appendChild(dropdownComponent.wrapper);
dropdownComponent.component = Templates.bind(dropdownComponent, dropdownComponent.wrapper);

如果您要包装用户单击过的东西等组件,则不需要上面的代码。

现在,对于Dropdown本身,可以这样实现:

@BindElement(name = "dropdown")
@BindTemplate("templates/components/dropdown.html")
public class Dropdown {

  private static HTMLDocument document = HTMLDocument.current();
  private Fragment content;
  private Component component;
  private HTMLElement wrapper;

  public Dropdown(Fragment content) {
    this.content = content;
  }

  public Fragment getContent() {
    return content;
  }

  public void setContent(Fragment content) {
    this.content = content;
  }

  public static void show(DropdownContent content, HTMLElement wrapper) {
    Dropdown dropdown = new Dropdown(Templates.create(content));
    dropdown.wrapper = wrapper;
    dropdown.component = Templates.bind(dropdown, dropdown.wrapper);
  }
}

使用非常简单的HTML模板:

<div>
  <std:insert fragment="content"/>
</div>

最后,可以在小部件中使用它,例如:

@BindElement(name = "simple-form")
@BindTemplate("templates/components/form.html")
public class FormComponent extends AbstractWidget {
    public void showDropdown(MouseEvent event) {
        HTMLElement element = (HTMLElement) event.getTarget();
        DropdownContent content = new CustomDropdownContent();
        Dropdown.show(content, element);
    }
}

form.html

<std:foreach var="property" in="properties">
  <button event:click="e -> showDropdown(e)"/>
</std:foreach>