this.setup_observer(), 500); } }, apply_column_breakpoints(row_element) { if (this.responsive_mode !== 'collapse') return; let cells = Array.from(row_element.children); cells.forEach((cell, index) => { let breakpoint = this.column_breakpoints[index]; if (breakpoint && cell.tagName === 'TD') { cell.classList.add('d-none', `d-${breakpoint}-table-cell`); } }); }, build_request_params(next_page) { let params = new URLSearchParams({ page: next_page, batch_size: this.batch_size }); if (this.sort_column) { params.set('sort', this.sort_column); params.set('direction', this.sort_direction); } return params; }, async check_container_height() { let table_container = this.$refs.table_container; let trigger = this.$refs.infinite_scroll_trigger; if (!table_container || !trigger || !this.has_next || this.is_refreshing || this.prevent_auto_load || this.is_loading) { return; } await new Promise(resolve => setTimeout(resolve, 50)); let container_rect = table_container.getBoundingClientRect(); let trigger_rect = trigger.getBoundingClientRect(); if (trigger_rect.top <= container_rect.bottom) { await this.load_more(); } }, cleanup_loading_state() { this.is_loading = false; this.skeleton_count = 0; }, disconnect_observer() { if (this.observer) { this.observer.disconnect(); } }, async fetch_rows(next_page) { if (!this.endpoint) { return { success: false, error: 'No endpoint provided' }; } let params = this.build_request_params(next_page); let url = `${this.endpoint}?${params}`; let view = new ViewGlue(url, this.$refs.shared_payload ? JSON.parse(this.$refs.shared_payload.textContent) : {}); if (next_page === 1) { this.$dispatch('clear-rows', { table_id: this.table_id }); this.$refs.table_body.innerHTML = ''; } let previous_count = this.loaded_count; await view.render_insert_adjacent(this.$refs.table_body, {}, 'beforeend'); let added = this.loaded_count - previous_count; return { success: true, added: added }; }, get_sort_icon(column) { if (this.sort_column !== column) { return 'bi-chevron-expand'; } return this.sort_direction === 'asc' ? 'bi-chevron-up' : 'bi-chevron-down'; }, handle_header_mounted(event) { this.column_count = event.detail.count; }, handle_header_registered(event) { this.column_breakpoints[event.detail.index] = event.detail.breakpoint; }, handle_row_deselected(event) { this.selected_rows.delete(event.detail.row_id); }, handle_row_mounted(event) { this.loaded_count++; if (event.detail.row_element) { this.apply_column_breakpoints(event.detail.row_element); if (this.average_row_height === 0) { this.average_row_height = event.detail.row_element.offsetHeight; } } }, handle_row_selected(event) { this.selected_rows.add(event.detail.row_id); }, handle_rows_cleared() { this.loaded_count = 0; this.selected_rows.clear(); this.select_all = false; }, handle_toggle_all() { this.select_all = !this.select_all; if (this.select_all) { this.$dispatch('select-all-rows', { table_id: this.table_id }); } else { this.selected_rows.clear(); this.$dispatch('deselect-all-rows', { table_id: this.table_id }); } }, handle_toggle_row(event) { let row_id = event.detail.row_id; this.is_row_open[row_id] = !this.is_row_open[row_id]; this.$dispatch('toggle-row-state', { row_id: row_id, is_open: this.is_row_open[row_id], table_id: this.table_id }); }, handle_total_count_updated(event) { this.total_count = event.detail.total_count; if (event.detail.batch_size) { this.batch_size = event.detail.batch_size; } }, async load_more() { if (!this.endpoint) { return; } this.is_loading = true; this.skeleton_count = this.batch_size; if (!this.$refs.table_body) { this.cleanup_loading_state(); return; } let result = await this.fetch_rows(this.current_page + 1); if (!result.success) { this.cleanup_loading_state(); return; } if (result.added > 0) { this.current_page++; } if (result.added < this.batch_size) { this.has_next = false; this.disconnect_observer(); } this.cleanup_loading_state(); await this.$nextTick(); await this.check_container_height(); }, async refresh_table() { if (this.is_refreshing || this.is_loading) { return; } this.disconnect_observer(); this.prevent_auto_load = true; this.skeleton_count = this.batch_size; this.is_refreshing = true; this.select_all = false; await this.$nextTick(); this.reset_table_state(); let result = await this.fetch_rows(1); this.update_counts_after_refresh(result); await this.$nextTick(); await new Promise(resolve => setTimeout(resolve, 150)); this.is_refreshing = false; this.skeleton_count = 0; if (this.has_next) { setTimeout(() => { this.setup_observer(); setTimeout(() => { this.prevent_auto_load = false; }, 100); }, 500); } }, reset_scroll_position() { requestAnimationFrame(() => { if (this.$refs.table_container) { this.$refs.table_container.scrollTop = 0; } }); }, reset_table_state() { this.current_page = 1; this.has_next = true; this.is_row_open = {}; }, async setup_observer() { let trigger = this.$refs.infinite_scroll_trigger; if (!trigger) { return; } let options = { root: null, rootMargin: '200px', threshold: 0.01 }; this.observer = new IntersectionObserver( (entries) => { entries.forEach(async entry => { if (entry.isIntersecting && this.has_next && !this.is_loading && !this.prevent_auto_load) { await this.load_more(); } }); }, options ); this.observer.observe(trigger); }, should_load_initial_data() { return this.loaded_count === 0 && this.current_page === 0; }, async sort_by(column) { if (this.is_refreshing || this.is_loading) { return; } if (this.sort_column === column) { this.sort_direction = this.sort_direction === 'asc' ? 'desc' : 'asc'; } else { this.sort_column = column; this.sort_direction = 'asc'; } await this.refresh_table(); }, update_counts_after_refresh(result) { if (result && result.added < this.batch_size) { this.has_next = false; } }, }" @clear-rows.window="if (!$event.detail || $event.detail.table_id === table_id) handle_rows_cleared()" @filter-applied.window="if (!$event.detail || $event.detail.table_id === table_id) refresh_table()" @header-mounted="handle_header_mounted($event)" @header-registered="handle_header_registered($event)" @row-deselected.window="if (!$event.detail || $event.detail.table_id === table_id) handle_row_deselected($event)" @row-mounted.window="if (!$event.detail || $event.detail.table_id === table_id) handle_row_mounted($event)" @row-selected.window="if (!$event.detail || $event.detail.table_id === table_id) handle_row_selected($event)" @toggle-row.window="if (!$event.detail || $event.detail.table_id === table_id) handle_toggle_row($event)" @total-count-updated.window="if (!$event.detail || $event.detail.table_id === table_id) handle_total_count_updated($event)" > {% block table_toolbar %}{% endblock %} {% block table_container %}
{% block table_header_container %} {% block table_header_start %} {% endblock %} {% block table_header %}{% endblock %} {% block table_header_end %} {% endblock %} {% endblock %} {% block refreshing_skeleton %} {% include 'django_spire/table/element/refreshing_skeleton.html' %} {% endblock %} {% block table_body %} {% endblock %} {% block loading_skeleton %} {% include 'django_spire/table/element/loading_skeleton.html' %} {% endblock %}
Actions
{% block trigger %} {% include 'django_spire/table/element/trigger.html' %} {% endblock %}
{% endblock %} {% block table_footer %} {% include 'django_spire/table/element/footer.html' %} {% endblock %}