Skip to content

Instantly share code, notes, and snippets.

@ayamomiji
Last active June 14, 2024 06:08
Show Gist options
  • Save ayamomiji/e755bb1b7f477840e4d66b8a2ba7acea to your computer and use it in GitHub Desktop.
Save ayamomiji/e755bb1b7f477840e4d66b8a2ba7acea to your computer and use it in GitHub Desktop.
Stimulus example: smart scroll
<div data-controller="smart-scroll"
data-action="smart-scroll:added->smart-scroll#handleAdded
resize->smart-scroll#handleAdded
scroll->smart-scroll#handleScroll">
<div data-controller="smart-scroll-item">
aya: an an
</div>
<div data-controller="smart-scroll-item">
hatate: ni hao
</div>
<!-- add more smart-scroll-item dynamically... -->
</div>
import { Controller } from 'stimulus'
import Rails from 'rails-ujs'
const observer = new ResizeObserver(entries => {
for (let entry of entries) {
Rails.fire(entry.target, 'resize')
}
})
export default class extends Controller {
connect() {
observer.observe(this.element)
this.shouldScroll = true
this.scrollToBottom()
}
disconnect() {
observer.unobserve(this.element)
}
scrollToBottom() {
const { scrollHeight, clientHeight, offsetHeight } = this.element
if (scrollHeight >= clientHeight) {
this.element.scrollTop = scrollHeight - clientHeight
}
}
handleAdded() {
const { scrollHeight, clientHeight } = this.element
if (clientHeight >= scrollHeight) {
this.shouldScroll = true
}
if (this.shouldScroll) {
this.scrollToBottom()
}
}
handleScroll() {
const { scrollTop, scrollHeight, clientHeight, offsetHeight } = this.element
if (clientHeight >= scrollHeight) {
this.shouldScroll = true
} else {
this.shouldScroll =
Math.abs((scrollTop + offsetHeight) - scrollHeight) < 1
}
}
}
import { Controller } from 'stimulus'
import { getParentController } from 'stimulus_utils'
import Rails from 'rails-ujs'
export default class extends Controller {
connect() {
const parent = getParentController(this, 'smart-scroll')
Rails.fire(parent.element, 'smart-scroll:added')
}
}
export function getParentController(controller, identifier) {
const application = controller.application
let element = controller.element
do {
let foundController =
application.getControllerForElementAndIdentifier(element, identifier)
if (foundController) {
return foundController
}
} while (element = element.parentElement)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment