Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dealing with sorted data in a stream #109

Closed
miczed opened this issue Jan 15, 2021 · 1 comment
Closed

Dealing with sorted data in a stream #109

miczed opened this issue Jan 15, 2021 · 1 comment

Comments

@miczed
Copy link

miczed commented Jan 15, 2021

I've been playing around with hotwire for the last couple of days and so far I really like it, great work! 馃憤 However, I couldn't yet figure out how to deal with data that is sorted (e.g. has an order field with a numeric value). So when an element is created instead of just adding / prepending it to the turbo frame, it should be added as the nth element in the list.

I was thinking of something that could work similar to this:

<turbo-stream action="append" target="messages" index="5">
  <template>
    <div id="message_1">
      This div will be appended to the element with the DOM ID "messages" as the 5th element.
    </div>
  </template>
</turbo-stream>
<turbo-stream action="update" target="message_2" index="3">
  <template>
    <!-- The contents of this template will replace the
    contents of the element with ID "message_2" and change its position to the third place. -->
    1
  </template>
</turbo-stream>

Another approach could consist of leveraging Node.insertBefore() in combination with a new StreamAction called insertBefore:

<turbo-stream action="insertBefore" target="messages" reference="message_2">
  <template>
    <div id="message_1">
      This div will be appended to the element with the DOM ID "messages" before the element with the DOM ID "message_2".
    </div>
  </template>
</turbo-stream>

Do you plan to support more advanced use cases like this? Is there a simple way to change the behavior of the StreamActions (i.e. to switch out this.targetElement?.append(this.templateContent) with something more sophisticated)?

@dhh
Copy link
Member

dhh commented Jan 16, 2021

The way we solve this problem in HEY, which also requires sorting, is with a Stimulus controller:

export default class extends ApplicationController {
  initialize() {
    this.observeMutations(this.sortChildren)
  }

  // Private

  sortChildren() {
    const { children } = this
    if (elementsAreSorted(children)) return
    children.sort(compareElements).forEach(this.append)
  }

  get children() {
    return Array.from(this.element.children)
  }

  append = child => this.element.append(child)
}

function elementsAreSorted([ left, ...rights ]) {
  for (const right of rights) {
    if (compareElements(left, right) > 0) return false
    left = right
  }
  return true
}

function compareElements(left, right) {
  return getSortCode(right) - getSortCode(left)
}

function getSortCode(element) {
  return element.getAttribute("data-sort-code") || 0
}

Don't see adding this directly to Turbo, but do see this being part of a Stimulus stdlib.

@dhh dhh closed this as completed Jan 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants