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

Passing a variable to a function in a foreach loop

请问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 跨度中的方法应该不同。请原谅我的解释不够充分,但代码本身是不言自明的。

现在的问题是,为什么无论用户在不同的 span 中单击 li,都会将相同的对象传递给该方法?

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

所以我的问题总结如下:

  1. 为什么 std:foreach 在每个函数中传递相同的(第一个)变量 event:async-点击
  2. 你如何为这件事注入跨度或任何 div 元素 甚至单击按钮或者 Flavour 的做法是什么?

对此的解决方案是创建类似 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);
}

这里的HTMLelement是可选的,如果渲染可以在DOM的任何地方完成,如果是这样的话,DOM里面的典型注入Dropdown.show()方法可以实现:

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>