Как добавить к существующему элементу в нокауте foreach, а не создавать новый элемент

Это немного нишевый случай, но у меня есть простой сценарий в стиле чата.

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

Итак, текущий foreach выглядит так:

<!-- ko foreach: ChatEntries -->
<div class="chat-entry">
    <img class="entry-sender"></span>
    <span class="entry-content" data-bind="html: Content"></span>
</div>
<!-- /ko -->

И в настоящее время для каждой записи будет добавлена ​​новая запись в чате, что нормально и выглядит так:

Существующая система чата

Однако теперь существует требование просто добавить к существующей записи в чате, если следующее сообщение принадлежит тому же человеку, например, так (простите за ужасную работу по рисованию).

Требуемая система чата

И я не уверен, как это сделать в нокауте... Я думал, что мог бы сделать afterRender и проверить, совпадает ли он с предыдущим постером записи, затем удалить все созданные dom и найти предыдущую запись, используя jquery. или что-то просто добавляющее элементы, но это выглядит как хакерство, так как я манипулирую домом вручную.

Так есть ли хороший способ решить эту проблему?

== РЕДАКТИРОВАТЬ ==

Просто чтобы прояснить некоторые вещи, в настоящее время я всегда добавляю к наблюдаемому массиву всякий раз, когда появляется новая запись, однако есть аргумент для повторного создания массива каждый раз, когда появляется что-то новое, поскольку это упростит вещи немного, но не уверен насчет видимого эффекта от этого, просто добавляя отдельные записи.

В настоящее время существует буфер 50 после точки отсечения, поэтому в основном массиве хранится около 100, а затем разрешается еще 50% (до 150 записей), затем, как только он преодолеет это, он отключит последние 50 записей и заново создаст массив, так что снова 100 записей, затем пользователь может вернуться назад, чтобы увидеть предыдущие записи. так что это уменьшает отдых, но звучит так, как будто это может стать немного сложнее. Весь входящий чат хранится локально в локальном хранилище, поэтому его можно быстро перемещать по страницам без необходимости в сервере, поэтому не стоит беспокоиться о потере данных чата.

2 ответа

Разве изменение массива в соответствии с вашим взглядом не будет более хакерским? Для манипулирования DOM-нокаутом есть bindingHandlers. Так что, возможно, именно то, что вы ищете, будет привязано к заказу. Просто сравните currentUser с previousUser и решите добавить span к предыдущей записи или создать новую. Нет jQuery, чистый JavaScript. Или jQuery, если вы хотите сделать это с эффектами для прихода нового сообщения. Вы даже можете предоставить шаблон в качестве параметра, чтобы в вашем чате могли быть темы для выбора.

У Bindings также есть много уже предоставленной информации: http://www.knockmeout.net/2011/07/another-look-at-custom-bindings-for.html

ИМО это может быть самое чистое решение, данные в модели, вид в поле зрения. Ваш основной HTML чистый как:

<!-- ko foreach: ChatEntries as chatEntry -->
    <div class="chat-entry" data-bind="yourCustomChatBinding: chatEntry"></div>
<!-- /ko -->

Только одна мысль: приведенный выше код создаст пустой div, если данные будут добавлены. КО виртуальные элементы:

<!-- ko foreach: ChatEntries as chatEntry -->
    <!-- ko yourCustomChatBinding: chatEntry -->
<!-- /ko -->

И у виртуальных элементов есть хороший API, который может быть полезен: http://knockoutjs.com/documentation/custom-bindings-for-virtual-elements.html

Вы можете использовать несколько нокаутом if вместе с $index() функция.

Это не самое элегантное решение, но оно простое и делает свою работу.

<!-- ko foreach: ChatEntries -->
<div class="chat-entry">
    <!-- ko if: $index() === 0 -->  //first item does not have a previous
        <span class="entry-sender">img</span>
        <span class="entry-content" data-bind="html: Content"></span>
    <!-- /ko -->
    <!-- ko if: $parent.ChatEntries()[$index()-1]-->    //check if previous is same user
        <!-- ko if: user !== ($parent.ChatEntries()[$index()-1].user)-->    
        <span class="entry-sender">img</span>
        <span class="entry-content" data-bind="html: Content"></span>
        <!-- /ko -->
        <!-- ko if: user === ($parent.ChatEntries()[$index()-1].user)-->    
        <span class="entry-content" data-bind="html: Content"></span>
        <!-- /ko -->
    <!-- /ko -->
</div>
<!-- /ko -->

Посмотрите на скрипку здесь

Это можно сделать и с вычисляемым полем, но для этого потребуется некоторый код JavaScript, и вы сможете изменить свою модель. Это решение требует только изменения в HTML

Другие вопросы по тегам