Проблема с JSViews и кнопкой раскрывающегося списка Materialise

У меня проблема с использованием связанного шаблона с JSViews и кнопкой раскрывающегося списка Materialize.

В первый раз представление отображается, оно работает нормально, однако, как только я заметно обновляю статус кнопки, тег ul, связанный с кнопкой, удаляется из DOM.

Я создал тестовый пример на JSFiddle: здесь

<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}}

If you click on a button after running, it opens the drop down just fine. If you select an option that is not set (ie set the COMPLETED button to NOT COMPLETE), it updates the UI, but as the ul is removed from the DOM, clicking on it again does not reveal the drop down. Only the button that is updated is affected.

Может ли кто-нибудь увидеть, где я ошибаюсь?


person grayson    schedule 12.08.2017    source источник


Ответы (2)


Похоже, что Materialise клонирует ul и вставляет копию после каждого активатора. Изначально есть только один активатор (поскольку другое выражение {^{if}} ложно, поэтому его содержимое пусто) — и клонированный ul помещается рядом с ним внутри блока {^{if}}.

Когда вы нажимаете, чтобы переключить статус, содержимое этого {^{if}} удаляется, а другое содержимое {^{if}} визуализируется. Но второй активатор (тег <a>) не был «активирован» и поэтому не имеет связанного с ним <ul>.

Если вы собираетесь использовать Materialize вместе с JsViews, вам придется иметь дело с Materialize, который потенциально может выполнять манипуляции с DOM, что может нарушить связывание данных JsViews. Наличие двух фреймворков, которые управляют одним и тем же 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>

Обновление:

В ответ на вопросы Грейсона, связанные с Materialise, о «встроенном блоке» и «блоке», вот несколько альтернатив:

Вы можете связать данные непосредственно с атрибутом отображения 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}" ...>

or

<foo data-link="{show Status==0 'block'}" ...>
person BorisMoore    schedule 12.08.2017
comment
Это не совсем работает с использованием Visibilty, поскольку он устанавливает отображение на встроенный, а не на встроенный блок или блок, который нужен элементу в моем фактическом коде. Как обычно, это фантастический ответ, и, надеюсь, он направит меня в правильном направлении. - person grayson; 13.08.2017
comment
Это действительно странно, потому что в скрипке он переключает встроенное отображение. Были ли обновления кода? - person grayson; 13.08.2017
comment
Вроде бы когда вариантов больше 2-х. Я добавил третью скрипку: jsfiddle.net/x8Lwmk7n/7, чтобы увидеть эффект - person grayson; 13.08.2017
comment
Борис, ты невероятен. Я надеюсь, что однажды у меня будет половина твоих навыков. - person grayson; 13.08.2017

Ответ Бориса - правильный ответ на этот вопрос, как и следовало ожидать, однако я хотел добавить кое-что, что может помочь любому в ситуации.

JSViews очень умен и, используя видимую привязку, пытается определить тип элемента, поэтому в случае тега привязки он использует display:inline, тогда как для div он использует display:block

В случае материализации (и начальной загрузки) класс btn устанавливает отображение в встроенный блок, поэтому использование видимой привязки не работает должным образом во всех случаях.

В моем случае, поскольку это действительно была кнопка, а не ссылка, я изменил тег привязки на тег кнопки, и, поскольку это блочный элемент, все работало нормально.

Это не идеальное решение, так как в моем случае у меня может быть 30 кнопок с 5 параметрами, что означает заполнение DOM множеством дополнительных скрытых тегов, но пока я не смогу придумать лучшее решение, используя {^{if ..., оно работает.

person grayson    schedule 13.08.2017