🏝️ Koh.js - Fetch Island!

This example demonstrates the use of:


import { island } from './static/koh-js/core/index.js'
import { fromValue, fromFetch } from './static/koh-js/stream/index.js'
import {
    map,
    debounce,
    startWith,
    tap,
    filter,
} from './static/koh-js/operators/index.js'

island('fetch-island', k => {
    const loading$ = fromValue(false)

    const users$ = fromFetch(
        `https://dummyjson.com/users`,
        {},
        { limit: 10, skip: 0 }
    )

    const userData$ = users$.pipe(
        filter(data => data?.users?.length > 0),
        map(val => val?.users)
    )

    const pagination$ = users$.pipe(
        map(data => {
            const { total, skip, limit } = data
            const totalPages = Math.round(total / limit)
            if (limit + skip === total) {
                return { lastPage: true, ...data }
            } // last page

            return { lastPage: false, ...data }
        }),
        map(data => {
            const { lastPage, total, skip, limit } = data
            const totalPages = Math.round(total / limit)
            const currentPage = skip < limit ? 1 : (skip + limit) / limit

            return { lastPage, currentPage, totalPages, pageSize: limit }
        })
    )

    k.foreach('#users', {
        stream: userData$,
        key: u => u.id,
        render: u => {
            const li = document.createElement('li')
            li.innerHTML = `
${u.id}. ${u.firstName} ${u.lastName}
` return li }, }) k.foreach('#buttons', { stream: pagination$.pipe( map(({ totalPages }) => { return Array.from({ length: totalPages }, (_, i) => ({ id: i, })) }) ), key: u => u.id, render: itm => { const btn = document.createElement('button') btn.innerHTML = `${itm.id}` k.on(btn, 'click', () => { users$.next(({ url, baseUrl, params }) => ({ params: { skip: itm.id * params.limit }, })) }) return btn }, }) k.sync( '#buttons', pagination$.pipe(filter(page => page.totalPages > 0)), (el, page) => { const buttons = k.qsa('button', el) const { currentPage, totalPages } = page const windowSize = 2 const realIdx = currentPage - 1 const windowStart = Math.max(realIdx - windowSize, 1) const windowEnd = Math.min(realIdx + windowSize, totalPages - 2) buttons.forEach((btn, idx) => { btn.classList.remove('active') btn.hidden = false // Active page if (idx === realIdx) btn.classList.add('active') // Always show first & last if (idx === 0 || idx === totalPages - 1) { btn.hidden = false btn.textContent = (idx + 1).toString() return } // Window pages if (idx >= windowStart && idx <= windowEnd) { btn.textContent = (idx + 1).toString() btn.hidden = false return } // Ellipsis if (idx === windowStart - 1 || idx === windowEnd + 1) { btn.textContent = '...' btn.hidden = false return } // Rest btn.hidden = true }) } ) })

<fetch-island />