JSViews 和 Materialize 下拉按钮的问题

Issue with JSViews and Materialize Dropdown Button

我在使用带有 JSViews 和 Materialize 下拉按钮的链接模板时遇到问题。

第一次呈现视图时,它工作正常,但是一旦我观察到更新按钮的状态,链接到按钮的 ul 标签就会从 DOM 中删除。

我在 JSFiddle 上创建了一个测试用例:here

<script id="test_template" type="text/x-jsrender">
{^{for tasks}}
<div class="dropdown change-state" style="display: block">
    {^{if Status == 0}}
        <a href="#" class="completed-state-box dropdown-button btn btn-flat red" data-constrainwidth="false" data-activates='review_status_dropdown-{{:Id}}'>NOT COMPLETE</a>
    {{/if}}

    {^{if Status == 1}}
        <a href="#" class="completed-state-box dropdown-button btn btn-flat green" data-constrainwidth="false" data-activates='review_status_dropdown-{{:Id}}'>COMPLETE</a>
    {{/if}}

    <ul id="review_status_dropdown-{{:Id}}" class="dropdown-content">
        <li><a class="state-change-button" href="#" data-value="0">NOT COMPLETE</a></li>
        <li><a class="state-change-button" href="#" data-value="1">COMPLETE</a></li>
    </ul>

</div>

{{/for}}

如果您单击 运行 之后的按钮,它会很好地打开下拉菜单。如果您 select 一个未设置的选项(即将完成按钮设置为未完成),它会更新 UI,但是当 ul 从 DOM 中删除时,单击它再次不显示下拉。只有更新的按钮会受到影响。

谁能看出我错在哪里?

看起来 Materialise 克隆了 ul 并在每个激活器之后插入了一个副本。最初只有一个激活器(因为另一个 {^{if}} 表达式是假的,所以它的内容是空的)——并且克隆的 ul 被放置在它旁边的 {^{if}} 块中。

当您单击切换状态时,{^{if}} 的内容将被删除,而其他 {^{if}} 的内容将被呈现。但是第二个激活器(<a> 标签)还没有 'activated',因此没有关联的 <ul>

如果您打算将 Materialize 与 JsViews 一起使用,那么您必须处理 Materialize 可能进行的 DOM 操作,这可能会破坏 JsViews 数据 linking。拥有两个操作相同 DOM 的框架可能会导致冲突或冲突。

在这种情况下,您可以使用 visible 绑定解决问题,而不是 {^{if}}:

<div class="dropdown change-state" style="display: block">
  <a href="#" data-link="visible{:Status==0}" class="completed-state-box dropdown-button btn btn-flat red" data-constrainwidth="false" data-activates='review_status_dropdown-{{:Id}}'>NOT COMPLETE</a>
  <a href="#" data-link="visible{:Status==1}" class="completed-state-box dropdown-button btn btn-flat green" data-constrainwidth="false" data-activates='review_status_dropdown-{{:Id}}'>COMPLETE</a>
  <ul id="review_status_dropdown-{{:Id}}" class="dropdown-content">
    <li><a class="state-change-button" href="#" data-value="0">NOT COMPLETE</a></li>
    <li><a class="state-change-button" href="#" data-value="1">COMPLETE</a></li>
  </ul>
</div>

更新:

响应 'inline-block' 与 'block' 的 grayson 的 Materialize 相关问题, 这里有几个选择:

你可以data-link直接到CSS显示属性,指定你要切换的值:

<a data-link="css-display{:Status==1?'inline-block':'none'}" ...>

或者您可以创建一个自定义标签来执行您想要的操作:

$.views.tags("show", {
  render: function(val) {
    return val ? "inline-block" : "none"
  },
  attr: "css-display"
});

然后写:

<a data-link="{show Status==0}" ...>

你甚至可以这样做:

$.views.tags("show", {
  render: function(val, type) {
    return val ? type||"inline-block" : "none"
  },
  attr: "css-display"
});

并写

<a data-link="{show Status==0}" ...>

<foo data-link="{show Status==0 'block'}" ...>

Boris 的回答是这个问题的正确答案,正如您显然期望的那样,但是,我想补充一点可能对处于这种情况的任何人有所帮助的内容。

JSViews 非常聪明并且使用可见绑定,它似乎尝试识别元素的类型,因此在锚标记的情况下它使用 display:inline,而对于 div它使用 display:block

在实现(和 bootstrap)的情况下,btn class 将显示设置为内联块,因此使用可见绑定并非在所有情况下都按预期工作。

在我的例子中,因为这确实是一个按钮而不是 link,我将锚标记更改为按钮标记,因为这是一个块元素,所以它工作得很好。

这不是一个理想的解决方案,就我而言,我可能有 30 个按钮,有 5 个选项,这意味着 DOM 充满了很多额外的隐藏标签,但直到我想出一个更好的解决方案,使用 {^{if...,它有效。