OWL
data_display
Pager
Odoo 19 OWL component — Pager (core)
Live preview
Interactive
Source excerpt
web/static/src/core/pager/pager.js
import { useAutofocus } from "../utils/hooks";
import { clamp } from "../utils/numbers";
import { Component, EventBus, useEffect, useExternalListener, useState } from "@odoo/owl";
export const PAGER_UPDATED_EVENT = "PAGER:UPDATED";
export const pagerBus = new EventBus();
/**
* Pager
*
* The pager goes from 1 to total (included).
* The current value is minimum if limit === 1 or the interval:
* [minimum, minimum + limit[ if limit > 1].
* The value can be manually changed by clicking on the pager value and giving
* an input matching the pattern: min[,max] (in which the comma can be a dash
* or a semicolon).
* The pager also provides two buttons to quickly change the current page (next
* or previous).
* @extends Component
*/
export class Pager extends Component {
static template = "web.Pager";
static defaultProps = {
isEditable: true,
withAccessKey: true,
};
static props = {
offset: Number,
limit: Number,
total: Number,
onUpdate: Function,
isEditable: { type: Boolean, optional: true },
withAccessKey: { type: Boolean, optional: true },
updateTotal: { type: Function, optional: true },
};
setup() {
this.state = useState({
isEditing: false,
isDisabled: false,
});
this.inputRef = useAutofocus();
useExternalListener(document, "mousedown", this.onClickAway, { capture: true });
let firstMount = true;
useEffect(
() => {
if (!firstMount && this.env.isSmall) {
pagerBus.trigger(PAGER_UPDATED_EVENT, {
value: this.value,
total: this.props.total,
});
}
firstMount = false;
},
() => [this.props.offset, this.props.limit, this.props.total]
);
}
/**
* @returns {number}
*/
get minimum() {
return this.props.offset + 1;
}
/**
* @returns {number}
*/
get maximum() {
return Math.min(this.props.offset + this.props.limit, this.props.total);
}
/**
* @returns {string}
*/
get value() {
const parts = [this.minimum];
if (this.props.limit > 1) {
parts.push(this.maximum);
}
return parts.join("-");
}
/**
* Note: returns false if we received the props "updateTotal", as in this case we don't know
* the real total so we can't assert that there's a single page.
* @returns {boolean} true if there is only one page
*/
get isSinglePage() {
return !this.props.updateTotal && this.minimum === 1 && this.maximum === this.props.total;
}
/**
* @param {-1 | 1} direction
*/
async navigate(direction) {
let minimum = this.props.offset + this.props.limit * direction;
let total = this.props.total;
if (this.props.updateTotal && minimum < 0) {
// we must know the real total to be able to loop by doing "previous"
total = await this.props.updateTotal();
}
if (minimum >= total) {
if (!this.props.updateTotal) {
// only loop forward if we know the real total, otherwise let the minimum
// go out of range
minimum = 0;
}
} else if (minimum < 0 && this.props.limit === 1) {
minimum = total - 1;
} else if (minimum < 0 && this.props.limit > 1) {
minimum = total - (total % this.props.limit || this.props.limit);
}
this.update(minimum, this.props.limit, true);
}
/**
* @param {string} value
* @returns {{ minimum: number, maximum: number }}
*/
async parse(value) {
let [minimum, maximum] = value.trim().split(/\s*[-\s,;]\s*/);
minimum = parseInt(minimum, 10);
maximum = maximum ? parseInt(maximum, 10) : minimum;
Registry / API
- Registry name
Pager- Category
—- Module
web- Slug
pager- Nav group
data_display