@progress/kendo-angular-pager
Version:
Kendo UI Angular Pager
1,270 lines (1,255 loc) • 114 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import * as i0 from '@angular/core';
import { Directive, Input, forwardRef, Component, ChangeDetectionStrategy, ViewChild, HostBinding, Optional, ElementRef, EventEmitter, inject, SkipSelf, ContentChildren, Output, HostListener, NgModule } from '@angular/core';
import * as i1 from '@progress/kendo-angular-l10n';
import { ComponentMessages, LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n';
import { Subject, Subscription } from 'rxjs';
import { caretAltLeftIcon, caretAltToLeftIcon, caretAltRightIcon, caretAltToRightIcon } from '@progress/kendo-svg-icons';
import { isVisible, isDocumentAvailable, isFocusable, Keys, EventsOutsideAngularDirective, anyChanged, isChanged, replaceMessagePlaceholder, normalizeKeys, ResizeSensorComponent, isPresent, ResizeBatchService } from '@progress/kendo-angular-common';
import { ButtonComponent } from '@progress/kendo-angular-buttons';
import { DropDownListComponent } from '@progress/kendo-angular-dropdowns';
import { NumericTextBoxComponent } from '@progress/kendo-angular-inputs';
import { validatePackage } from '@progress/kendo-licensing';
import { NgTemplateOutlet, NgStyle } from '@angular/common';
import { take } from 'rxjs/operators';
import { IconsService } from '@progress/kendo-angular-icons';
import { PopupService } from '@progress/kendo-angular-popup';
/**
* @hidden
*/
class PreventableEvent {
prevented = false;
/**
* Prevents the default action for a specified event.
* In this way, the source component suppresses the built-in behavior that follows the event.
*/
preventDefault() {
this.prevented = true;
}
/**
* If the event is prevented by any of its subscribers, returns `true`.
*
* @returns `true` if the default action was prevented. Otherwise, returns `false`.
*/
isDefaultPrevented() {
return this.prevented;
}
}
/**
* Represents the arguments for the `pageSizeChange` event. The `pageSizeChange` event fires when you change the page size
* from the UI. If you cancel the event, the change does not occur.
*/
class PageSizeChangeEvent extends PreventableEvent {
/**
* Gets the newly selected page size.
*/
newPageSize;
/**
* Constructs the event arguments for the `pageSizeChange` event.
* @param newPageSize - The newly selected page size.
* @hidden
*/
constructor(newPageSize) {
super();
this.newPageSize = newPageSize;
}
}
/**
* @hidden
*/
class Messages extends ComponentMessages {
/**
* The label of the pager. Follows the pattern **Page navigation, page {currentPage} of {totalPages}** by default.
* Тhe default label text when the current page is 1, and the total number of pages is 10 will be
* **Page navigation, page 1 of 10**.
*
* The message consists of several parts - the current page number, the total number of pages, and a localizable string.
* To allow for reordering its parts, the `ariaLabel` input accepts a string with placeholders for the current page
* and total number of pages. The `{currentPage}` and `{totalPages}` placeholders will be replaced
* internally with the respective actual values.
*/
ariaLabel;
/**
* The label for the **First page** button.
*/
firstPage;
/**
* The label for the **Last page** button.
*/
lastPage;
/**
* The label for the **Previous page** button.
*/
previousPage;
/**
* The label for the **Next page** button.
*/
nextPage;
/**
* The label displayed before the pager input.
*/
page;
/**
* The title attribute of the page number input element.
*/
pageNumberInputTitle;
/**
* The label displayed after the page-size selector.
*/
itemsPerPage;
/**
* The label before the total-page number.
*/
of;
/**
* The label after the total-page number.
*/
items;
/**
* The text of the title and aria-label attributes applied to the page chooser.
*/
selectPage;
/**
* The text of the aria-label attribute applied to the input element for entering the page number."
*/
inputLabel;
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: Messages, deps: null, target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: Messages, selector: "kendoPagerMessages", inputs: { ariaLabel: "ariaLabel", firstPage: "firstPage", lastPage: "lastPage", previousPage: "previousPage", nextPage: "nextPage", page: "page", pageNumberInputTitle: "pageNumberInputTitle", itemsPerPage: "itemsPerPage", of: "of", items: "items", selectPage: "selectPage", inputLabel: "inputLabel" }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: Messages, decorators: [{
type: Directive,
args: [{
// eslint-disable-next-line @angular-eslint/directive-selector
selector: 'kendoPagerMessages'
}]
}], propDecorators: { ariaLabel: [{
type: Input
}], firstPage: [{
type: Input
}], lastPage: [{
type: Input
}], previousPage: [{
type: Input
}], nextPage: [{
type: Input
}], page: [{
type: Input
}], pageNumberInputTitle: [{
type: Input
}], itemsPerPage: [{
type: Input
}], of: [{
type: Input
}], items: [{
type: Input
}], selectPage: [{
type: Input
}], inputLabel: [{
type: Input
}] } });
/**
* Represents the Kendo UI Pager custom messages component for Angular. Use this component to override default component messages
* ([see example]({% slug pager_globalization %}#toc-messages)).
*
* @example
* ```html
* <kendo-pager [skip]="skip" [pageSize]="pageSize" [total]="total">
* <kendo-pager-messages
* previousNext="Previous/Next"
* page="Page"
* of="of">
* </kendo-pager-messages>
* </kendo-pager>
* ```
*/
class CustomMessagesComponent extends Messages {
service;
constructor(service) {
super();
this.service = service;
}
get override() {
return true;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CustomMessagesComponent, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: CustomMessagesComponent, isStandalone: true, selector: "kendo-datapager-messages, kendo-pager-messages", providers: [
{
provide: Messages,
useExisting: forwardRef(() => CustomMessagesComponent)
}
], usesInheritance: true, ngImport: i0, template: ``, isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CustomMessagesComponent, decorators: [{
type: Component,
args: [{
providers: [
{
provide: Messages,
useExisting: forwardRef(() => CustomMessagesComponent)
}
],
selector: 'kendo-datapager-messages, kendo-pager-messages',
template: ``,
standalone: true
}]
}], ctorParameters: () => [{ type: i1.LocalizationService }] });
/**
* @hidden
*/
class LocalizedMessagesDirective extends Messages {
service;
constructor(service) {
super();
this.service = service;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LocalizedMessagesDirective, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: LocalizedMessagesDirective, isStandalone: true, selector: "[kendoPagerLocalizedMessages]", providers: [
{
provide: Messages,
useExisting: forwardRef(() => LocalizedMessagesDirective)
}
], usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LocalizedMessagesDirective, decorators: [{
type: Directive,
args: [{
providers: [
{
provide: Messages,
useExisting: forwardRef(() => LocalizedMessagesDirective)
}
],
selector: '[kendoPagerLocalizedMessages]',
standalone: true
}]
}], ctorParameters: () => [{ type: i1.LocalizationService }] });
/**
* @hidden
*/
class PagerContextService {
total;
skip;
pageSize;
isAllSelected = false;
localization;
changes = new Subject();
pageChange = new Subject();
pageSizeChange = new Subject();
get currentPage() {
return this.skip / this.pageSize;
}
notifyChanges(changes) {
this.total = changes.total;
this.skip = changes.skip;
this.pageSize = changes.pageSize;
this.isAllSelected = changes.isAllSelected || false;
this.changes.next(changes);
}
changePage(page) {
this.pageChange.next({ skip: page * this.pageSize, take: this.pageSize });
}
changePageSize(event) {
this.pageSizeChange.next(event);
}
nextPage() {
const nextPage = this.currentPage + 1;
if (nextPage * this.pageSize < this.total) {
this.changePage(nextPage);
}
}
prevPage() {
const prevPage = this.currentPage - 1;
if (prevPage * this.pageSize >= 0) {
this.changePage(prevPage);
}
}
}
/**
* @hidden
*/
class PagerElementComponent {
localization;
pagerContext;
cd;
total;
skip;
pageSize;
caretAltLeftIcon = caretAltLeftIcon;
caretAltToLeftIcon = caretAltToLeftIcon;
caretAltRightIcon = caretAltRightIcon;
caretAltToRightIcon = caretAltToRightIcon;
/**
* @hidden
*
* @readonly
* @type {number}
* @memberOf PagerElementComponent
*/
get currentPage() {
return Math.floor((this.skip || 0) / this.pageSize) + 1;
}
/**
* @hidden
*
* @readonly
* @type {number}
* @memberOf PagerElementComponent
*/
get totalPages() {
return Math.ceil((this.total || 0) / this.pageSize);
}
subscriptions;
constructor(localization, pagerContext, cd) {
this.localization = localization;
this.pagerContext = pagerContext;
this.cd = cd;
this.total = pagerContext.total;
this.skip = pagerContext.skip;
this.pageSize = pagerContext.pageSize;
}
/**
* @hidden
*
* @param {string} key
* @returns {string}
*
* @memberOf PagerElementComponent
*/
textFor(key) {
const isPagerLocalization = this.localization.prefix === 'kendo.pager';
return this.localization.get(isPagerLocalization ? key : `pager${key[0].toLocaleUpperCase()}${key.slice(1)}`);
}
/**
* @hidden
*
* @param {number} page
*
* @memberOf PagerElementComponent
*/
changePage(page) {
this.pagerContext.changePage(page);
return false;
}
/**
* @hidden
*
* @memberOf PagerElementComponent
*/
ngOnInit() {
this.subscriptions = this.pagerContext.changes.subscribe(this.onChanges.bind(this));
this.subscriptions.add(this.localization.changes.subscribe(() => this.cd.markForCheck()));
}
ngOnDestroy() {
if (this.subscriptions) {
this.subscriptions.unsubscribe();
}
}
get prevArrowIcons() {
return !this.localization.rtl ? ['caret-alt-to-left', 'caret-alt-left'] : ['caret-alt-to-right', 'caret-alt-right'];
}
get prevArrowSVGIcons() {
return !this.localization.rtl ? [this.caretAltToLeftIcon, this.caretAltLeftIcon] : [this.caretAltToRightIcon, this.caretAltRightIcon];
}
get nextArrowIcons() {
return !this.localization.rtl ? ['caret-alt-right', 'caret-alt-to-right'] : ['caret-alt-left', 'caret-alt-to-left'];
}
get nextArrowSVGIcons() {
return !this.localization.rtl ? [this.caretAltRightIcon, this.caretAltToRightIcon] : [this.caretAltLeftIcon, this.caretAltToLeftIcon];
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerElementComponent, deps: [{ token: i1.LocalizationService }, { token: PagerContextService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: PagerElementComponent, selector: "kendo-pager-element", ngImport: i0, template: ``, isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerElementComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-pager-element',
template: ``
}]
}], ctorParameters: () => [{ type: i1.LocalizationService }, { type: PagerContextService }, { type: i0.ChangeDetectorRef }] });
/**
* @hidden
*/
const DEFAULT_PAGE_SIZE_VALUES = [5, 10, 20].map(n => ({
text: String(n),
value: n
}));
/**
* @hidden
*/
const focusableDirectiveSelector = '[kendoPagerFocusable]';
/**
* @hidden
*/
const getAllFocusableChildren = (parent) => {
return Array.from(parent.querySelectorAll(focusableDirectiveSelector))?.filter(isVisible);
};
/**
* @hidden
*/
const focusableSelector = [
'a[href]:not([disabled]):not([aria-hidden="true"])',
'area[href]:not([disabled]):not([aria-hidden="true"])',
'input:not([disabled]):not([aria-hidden="true"])',
'select:not([disabled]):not([aria-hidden="true"])',
'textarea:not([disabled]):not([aria-hidden="true"])',
'button:not([aria-hidden="true"])',
'iframe:not([disabled])',
'object:not([disabled])',
'embed:not([disabled])',
'*[tabindex]:not([disabled]):not([aria-hidden="true"])',
'*[contenteditable]:not([disabled]):not([contenteditable="false"])'
].join(',');
/**
* @hidden
*/
const DEFAULT_SIZE = 'medium';
const SIZES = {
small: 'sm',
medium: 'md',
large: 'lg'
};
/**
* @hidden
*
* Returns the styling classes to be added and removed
*/
const getStylingClasses = (componentType, stylingOption, previousValue, newValue) => {
switch (stylingOption) {
case 'size':
return {
toRemove: `k-${componentType}-${SIZES[previousValue]}`,
toAdd: newValue !== 'none' ? `k-${componentType}-${SIZES[newValue]}` : ''
};
default:
break;
}
};
/**
* @hidden
*/
const calculatePadding = (element) => {
if (!element || !isDocumentAvailable()) {
return { padding: 0, gapNumbersSizes: 0, gapSizesInfo: 0 };
}
const computedStyle = window.getComputedStyle(element);
const paddingLeft = parseInt(computedStyle.paddingLeft, 10) || 0;
const paddingRight = parseInt(computedStyle.paddingRight, 10) || 0;
const padding = (paddingLeft + paddingRight) * 1.2; // account for rounding errors
const style = getComputedStyle(document.documentElement);
const gapNumbersSizes = 2 * (parseFloat(style.getPropertyValue('--kendo-spacing-3\\.5') || '0.875rem') * (parseFloat(getComputedStyle(document.documentElement).fontSize) || 16)); // convert rem to px
const gapSizesInfo = gapNumbersSizes;
return { padding, gapNumbersSizes, gapSizesInfo };
};
/**
* @hidden
*/
const calculateGap = (element) => {
if (!element || !isDocumentAvailable()) {
return 0;
}
const computedStyle = window.getComputedStyle(element);
return parseFloat(computedStyle.gap) || 0;
};
/**
* @hidden
*/
const createMeasurementSpan = (renderer, container, className) => {
const span = renderer.createElement('span');
renderer.appendChild(container, span);
renderer.addClass(span, className);
return span;
};
/**
* @hidden
*/
const copyComputedStyles = (renderer, source, destination) => {
const computedStyle = getComputedStyle(source);
const importantStyles = [
'font-family', 'font-size', 'font-weight', 'font-style',
'letter-spacing', 'text-transform', 'white-space', 'word-spacing',
'padding-left', 'padding-right', 'margin-left', 'margin-right',
'border-left-width', 'border-right-width', 'box-sizing'
];
importantStyles.forEach(style => {
renderer.setStyle(destination, style, computedStyle.getPropertyValue(style));
});
};
/**
*
* @hidden
*/
const positionOffScreen = (renderer, element) => {
renderer.setStyle(element, 'position', 'absolute');
renderer.setStyle(element, 'visibility', 'hidden');
renderer.setStyle(element, 'left', '-9999px');
renderer.setStyle(element, 'top', '-9999px');
renderer.setStyle(element, 'display', 'flex');
};
/**
* @hidden
*/
class PagerNavigationService {
isNavigable = true;
innerNavigationChange = new Subject();
toggleInnerNavigation(value) {
this.innerNavigationChange.next(value);
}
keepFocusWithinComponent(wrapper, target, event) {
const [firstFocusable, lastFocusable] = this.getFirstAndLastFocusable(wrapper);
const tabAfterLastFocusable = !event.shiftKey && target === lastFocusable;
const shiftTabAfterFirstFocusable = event.shiftKey && target === firstFocusable;
if (tabAfterLastFocusable) {
event.preventDefault();
firstFocusable.focus();
}
if (shiftTabAfterFirstFocusable) {
event.preventDefault();
lastFocusable.focus();
}
}
getFirstAndLastFocusable(wrapper) {
const all = getAllFocusableChildren(wrapper);
const firstFocusable = all.length > 0 ? all[0] : wrapper;
const lastFocusable = all.length > 0 ? all[all.length - 1] : wrapper;
return [
isFocusable(firstFocusable) ? firstFocusable : firstFocusable.querySelector(focusableSelector),
isFocusable(lastFocusable) ? lastFocusable : lastFocusable.querySelector(focusableSelector)
];
}
}
/**
* Represents the Kendo UI Pager focusable directive for Angular. Apply this directive to custom focusable elements in the [`kendoPagerTemplate`]({% slug api_pager_pagertemplatedirective %}) to include them in the built-in Pager keyboard navigation.
*
* @example
* ```html
* <kendo-pager [skip]="skip" [pageSize]="pageSize" [total]="total">
* <ng-template kendoPagerTemplate>
* <button kendoPagerFocusable type="button">Custom Button</button>
* </ng-template>
* </kendo-pager>
* ```
*/
class PagerFocusableDirective {
navigationService;
element;
renderer;
subscriptions = new Subscription();
constructor(navigationService, element, renderer) {
this.navigationService = navigationService;
this.element = element;
this.renderer = renderer;
}
ngOnInit() {
if (!(this.nativeElement instanceof HTMLElement)) {
return;
}
this.subscriptions.add(this.navigationService.innerNavigationChange.subscribe(this.innerNavigationChange.bind(this)));
}
ngOnDestroy() {
this.subscriptions.unsubscribe();
}
get nativeElement() {
return this.element.nativeElement;
}
innerNavigationChange(value) {
if (!this.navigationService.isNavigable) {
return;
}
const index = value ? '0' : '-1';
if (this.nativeElement.matches(focusableSelector)) {
this.renderer.setAttribute(this.nativeElement, 'tabindex', index);
}
const focusableElements = this.nativeElement.querySelectorAll(focusableSelector);
focusableElements.forEach(el => {
this.renderer.setAttribute(el, 'tabindex', index);
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerFocusableDirective, deps: [{ token: PagerNavigationService }, { token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: PagerFocusableDirective, isStandalone: true, selector: "[kendoPagerFocusable]", exportAs: ["kendoPagerFocusable"], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerFocusableDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoPagerFocusable]',
exportAs: 'kendoPagerFocusable',
standalone: true
}]
}], ctorParameters: () => [{ type: PagerNavigationService }, { type: i0.ElementRef }, { type: i0.Renderer2 }] });
// eslint-disable no-access-missing-member
/**
* Represents the Kendo UI Pager Previous Buttons component for Angular. Displays buttons for navigating to the first and to the previous page ([see example]({% slug pager_settings %})).
*
* @example
* ```html
* <kendo-pager [skip]="skip" [pageSize]="pageSize" [total]="total">
* <ng-template kendoPagerTemplate>
* <kendo-pager-prev-buttons></kendo-pager-prev-buttons>
* </ng-template>
* </kendo-pager>
* ```
*/
class PagerPrevButtonsComponent extends PagerElementComponent {
constructor(localization, pagerContext, cd) {
super(localization, pagerContext, cd);
}
/**
* Specifies the padding of the navigation buttons.
*
* @default 'medium'
*/
size = DEFAULT_SIZE;
/**
* @hidden
*
* @readonly
* @type {boolean}
* @memberOf PagerPrevButtonsComponent
*/
get disabled() {
return this.currentPage === 1 || !this.total;
}
/**
* @hidden
*/
onClick(isFirst = false) {
if (this.disabled) {
return false;
}
const targetPage = isFirst ? 0 : this.currentPage - 2;
return this.currentPage !== 1 ? this.changePage(targetPage) : false;
}
onChanges({ total, skip, pageSize }) {
this.total = total;
this.skip = skip;
this.pageSize = pageSize;
this.cd.markForCheck();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerPrevButtonsComponent, deps: [{ token: i1.LocalizationService }, { token: PagerContextService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: PagerPrevButtonsComponent, isStandalone: true, selector: "kendo-datapager-prev-buttons, kendo-pager-prev-buttons", inputs: { size: "size" }, usesInheritance: true, ngImport: i0, template: `
<button
type="button" kendoButton
kendoPagerFocusable
class="k-pager-nav k-pager-first"
[attr.aria-disabled]="disabled"
[class.k-disabled]="disabled"
[icon]="prevArrowIcons[0]"
[svgIcon]="prevArrowSVGIcons[0]"
fillMode="flat"
rounded="none"
[size]="size"
[title]="textFor('firstPage')"
[attr.aria-label]="textFor('firstPage')"
(click)="onClick(true)">
</button>
<button
type="button" kendoButton
kendoPagerFocusable
class="k-pager-nav"
[attr.aria-disabled]="disabled"
[class.k-disabled]="disabled"
[icon]="prevArrowIcons[1]"
[svgIcon]="prevArrowSVGIcons[1]"
fillMode="flat"
rounded="none"
[size]="size"
[title]="textFor('previousPage')"
[attr.aria-label]="textFor('previousPage')"
(click)="onClick()">
</button>
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: PagerFocusableDirective, selector: "[kendoPagerFocusable]", exportAs: ["kendoPagerFocusable"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerPrevButtonsComponent, decorators: [{
type: Component,
args: [{
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'kendo-datapager-prev-buttons, kendo-pager-prev-buttons',
template: `
<button
type="button" kendoButton
kendoPagerFocusable
class="k-pager-nav k-pager-first"
[attr.aria-disabled]="disabled"
[class.k-disabled]="disabled"
[icon]="prevArrowIcons[0]"
[svgIcon]="prevArrowSVGIcons[0]"
fillMode="flat"
rounded="none"
[size]="size"
[title]="textFor('firstPage')"
[attr.aria-label]="textFor('firstPage')"
(click)="onClick(true)">
</button>
<button
type="button" kendoButton
kendoPagerFocusable
class="k-pager-nav"
[attr.aria-disabled]="disabled"
[class.k-disabled]="disabled"
[icon]="prevArrowIcons[1]"
[svgIcon]="prevArrowSVGIcons[1]"
fillMode="flat"
rounded="none"
[size]="size"
[title]="textFor('previousPage')"
[attr.aria-label]="textFor('previousPage')"
(click)="onClick()">
</button>
`,
standalone: true,
imports: [ButtonComponent, PagerFocusableDirective]
}]
}], ctorParameters: () => [{ type: i1.LocalizationService }, { type: PagerContextService }, { type: i0.ChangeDetectorRef }], propDecorators: { size: [{
type: Input
}] } });
/**
* Represents the Kendo UI Pager Page Sizes component for Angular. Displays a drop-down list for the page size selection ([see example]({% slug pager_settings %})).
*
* @example
* ```html
* <kendo-pager [skip]="skip" [pageSize]="pageSize" [total]="total">
* <ng-template kendoPagerTemplate>
* <kendo-pager-page-sizes [pageSizes]="[10, 20, 50]"></kendo-pager-page-sizes>
* </ng-template>
* </kendo-pager>
* ```
*/
class PagerPageSizesComponent extends PagerElementComponent {
pagerContext;
element;
ngZone;
dropDownList;
_showItemsText = true;
/**
* Controls the visibility of the page text label.
* @hidden
*/
get showItemsText() {
return this._showItemsText;
}
set showItemsText(value) {
this._showItemsText = value;
this.cd.markForCheck();
}
/**
* Specifies the page sizes collection. You can include numbers and [`PageSizeItem`]({% slug api_pager_pagesizeitem %}) objects.
*
* @example
* ```html
* <kendo-pager [skip]="0" [pageSize]="10" [total]="100">
* <ng-template kendoPagerTemplate>
* <kendo-pager-page-sizes [pageSizes]="[5, 10, 20, { text: 'All', value: 'all' }]"></kendo-pager-page-sizes>
* </ng-template>
* </kendo-pager>
* ```
*/
set pageSizes(pageSizes) {
let normalizedItems = [];
if (Array.isArray(pageSizes)) {
pageSizes.forEach(item => {
if (typeof item === 'number') {
normalizedItems.push({
text: item.toString(),
value: item
});
}
else {
normalizedItems.push(item);
}
});
}
else {
normalizedItems = DEFAULT_PAGE_SIZE_VALUES;
}
if (this.pageSize && !normalizedItems.some(item => item.value === this.pageSize)) {
normalizedItems = [{ text: this.pageSize.toString(), value: this.pageSize }, ...normalizedItems];
}
this._pageSizes = normalizedItems;
}
/**
* Specifies the padding of the DropDownList component.
*
* @default 'medium'
*/
size = DEFAULT_SIZE;
/**
* Specifies the adaptive mode of the internal `DropDownList` component.
*
* @default 'auto'
*/
adaptiveMode = 'auto';
/**
* @hidden
*
* @readonly
*/
get classes() {
return true;
}
_pageSizes = [];
constructor(localization, cd, pagerContext, element, ngZone) {
super(localization, pagerContext, cd);
this.pagerContext = pagerContext;
this.element = element;
this.ngZone = ngZone;
}
ngAfterViewInit() {
this.ngZone.runOutsideAngular(() => {
this.element.nativeElement.addEventListener('keydown', this.keyDownHandler.bind(this), true);
});
}
ngOnDestroy() {
this.element.nativeElement.removeEventListener('keydown', this.keyDownHandler);
}
/**
* @hidden
*/
pageSizeChange(value, dropdownlist) {
const event = new PageSizeChangeEvent(value);
this.pagerContext.changePageSize(event);
if (event.isDefaultPrevented()) {
dropdownlist.writeValue(this.pageSize);
}
}
onChanges({ total, skip, pageSize, isAllSelected }) {
this.total = total;
this.skip = skip;
const normalizedPageSize = typeof pageSize === 'number' ? pageSize : this.total;
this.pageSize = isAllSelected ? 'all' : normalizedPageSize;
this.cd.markForCheck();
}
keyDownHandler(ev) {
if (ev.code === Keys.Escape && this.dropDownList.isOpen) {
ev.stopPropagation();
this.dropDownList.toggle(false);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerPageSizesComponent, deps: [{ token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }, { token: PagerContextService }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: PagerPageSizesComponent, isStandalone: true, selector: "kendo-datapager-page-sizes, kendo-pager-page-sizes", inputs: { showItemsText: "showItemsText", pageSizes: "pageSizes", size: "size", adaptiveMode: "adaptiveMode" }, host: { properties: { "class.k-pager-sizes": "this.classes" } }, viewQueries: [{ propertyName: "dropDownList", first: true, predicate: ["dropdownlist"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
<kendo-dropdownlist kendoPagerFocusable
#dropdownlist
[size]="size"
[data]="_pageSizes"
textField="text"
valueField="value"
[valuePrimitive]="true"
[value]="pageSize"
(valueChange)="pageSizeChange($event, dropdownlist)"
[adaptiveMode]="adaptiveMode"
[attr.aria-label]="textFor('itemsPerPage')">
</kendo-dropdownlist>
@if (showItemsText) {
{{ textFor('itemsPerPage') }}
}
`, isInline: true, dependencies: [{ kind: "component", type: DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "directive", type: PagerFocusableDirective, selector: "[kendoPagerFocusable]", exportAs: ["kendoPagerFocusable"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerPageSizesComponent, decorators: [{
type: Component,
args: [{
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'kendo-datapager-page-sizes, kendo-pager-page-sizes',
template: `
<kendo-dropdownlist kendoPagerFocusable
#dropdownlist
[size]="size"
[data]="_pageSizes"
textField="text"
valueField="value"
[valuePrimitive]="true"
[value]="pageSize"
(valueChange)="pageSizeChange($event, dropdownlist)"
[adaptiveMode]="adaptiveMode"
[attr.aria-label]="textFor('itemsPerPage')">
</kendo-dropdownlist>
@if (showItemsText) {
{{ textFor('itemsPerPage') }}
}
`,
standalone: true,
imports: [DropDownListComponent, PagerFocusableDirective]
}]
}], ctorParameters: () => [{ type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }, { type: PagerContextService }, { type: i0.ElementRef }, { type: i0.NgZone }], propDecorators: { dropDownList: [{
type: ViewChild,
args: ['dropdownlist', { static: true }]
}], showItemsText: [{
type: Input
}], pageSizes: [{
type: Input
}], size: [{
type: Input
}], adaptiveMode: [{
type: Input
}], classes: [{
type: HostBinding,
args: ["class.k-pager-sizes"]
}] } });
/**
* Represents the Kendo UI Pager template directive for Angular.
* Use this directive to customize the Pager appearance. To define a Pager template, nest an `<ng-template>` tag with the `kendoPagerTemplate` directive inside `<kendo-pager>`.
*
* The template context provides the following fields:
*
* * `currentPage`—The index of the displayed page.
* * `pageSize`—The value of the current `pageSize`.
* * `skip`—The current skip value.
* * `total`—The total number of records.
* * `totalPages`—The total number of available pages.
*
* @example
* ```html
* <kendo-pager [skip]="0" [pageSize]="10" [total]="100">
* <ng-template kendoPagerTemplate let-currentPage="currentPage" let-pageSize="pageSize" let-skip="skip" let-total="total" let-totalPages="totalPages">
* <span>Page {{currentPage}} of {{totalPages}}</span>
* <span>Items per page: {{pageSize}}</span>
* </ng-template>
* </kendo-pager>
* ```
*/
class PagerTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: PagerTemplateDirective, isStandalone: true, selector: "[kendoDataPagerTemplate], [kendoPagerTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoDataPagerTemplate], [kendoPagerTemplate]',
standalone: true
}]
}], ctorParameters: () => [{ type: i0.TemplateRef, decorators: [{
type: Optional
}] }] });
/**
* Represents the Kendo UI Pager Numeric Buttons component for Angular. Displays numeric buttons to enable navigation between the pages.
*
* @example
* ```html
* <kendo-pager [skip]="skip" [pageSize]="pageSize" [total]="total">
* <ng-template kendoPagerTemplate>
* <kendo-pager-numeric-buttons [buttonCount]="5"></kendo-pager-numeric-buttons>
* </ng-template>
* </kendo-pager>
* ```
*/
class PagerNumericButtonsComponent extends PagerElementComponent {
pagerContext;
renderer;
selectElement;
numbersElement;
/**
* Specifies the count of the displayed buttons.
*
* @type {number}
* @memberOf PagerNumericButtonsComponent
*/
buttonCount;
/**
* Specifies the padding of the numeric buttons.
*
* @default 'medium'
*/
set size(size) {
const newSize = size ? size : DEFAULT_SIZE;
this.handleClasses(newSize, 'size');
this._size = newSize;
}
get size() {
return this._size;
}
/**
* @hidden
*
* @readonly
* @type {number[]}
* @memberOf PagerNumericButtonsComponent
*/
get buttons() {
const result = [];
for (let idx = this.start; idx <= this.end; idx++) {
result.push(idx);
}
return result;
}
/**
* @hidden
*/
get end() {
return Math.min((this.start + this.buttonCount) - 1, this.totalPages);
}
/**
* @hidden
*/
get start() {
const page = this.currentPage;
const buttonCount = this.buttonCount;
if (page > buttonCount) {
const reminder = (page % buttonCount);
return (reminder === 0) ? (page - buttonCount) + 1 : (page - reminder) + 1;
}
return 1;
}
constructor(localization, cd, pagerContext, renderer) {
super(localization, pagerContext, cd);
this.pagerContext = pagerContext;
this.renderer = renderer;
}
_size = DEFAULT_SIZE;
ngAfterViewInit() {
this.handleClasses(this.size, 'size');
}
/**
* @hidden
*/
pageLabel(num) {
const pageText = this.textFor('page');
if (pageText) {
return pageText + ' ' + num;
}
return num.toString();
}
/**
* @hidden
*/
onSelectChange(e) {
const target = e.target;
const valueAsNumber = Number(target.value);
if (!Number.isNaN(valueAsNumber)) {
this.changePage(valueAsNumber - 1);
}
else {
if (target.value === 'previousButtons') {
this.changePage(this.start - 2);
}
else {
this.changePage(this.end);
}
}
}
onChanges({ total, skip, pageSize }) {
this.total = total;
this.skip = skip;
this.pageSize = pageSize;
this.cd.markForCheck();
}
get pageChooserLabel() {
return this.textFor('selectPage');
}
handleClasses(value, input) {
const elem = this.selectElement?.nativeElement;
const classes = getStylingClasses('picker', input, this[input], value);
if (!elem) {
return;
}
if (classes.toRemove) {
this.renderer.removeClass(elem, classes.toRemove);
}
if (classes.toAdd) {
this.renderer.addClass(elem, classes.toAdd);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerNumericButtonsComponent, deps: [{ token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }, { token: PagerContextService }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: PagerNumericButtonsComponent, isStandalone: true, selector: "kendo-datapager-numeric-buttons, kendo-pager-numeric-buttons", inputs: { buttonCount: "buttonCount", size: "size" }, viewQueries: [{ propertyName: "selectElement", first: true, predicate: ["select"], descendants: true, read: ElementRef }, { propertyName: "numbersElement", first: true, predicate: ["numbers"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: `
<div class="k-pager-numbers" #numbers>
@if (start > 1) {
<button
type="button"
kendoPagerFocusable
kendoButton
[size]="size"
fillMode="flat"
themeColor="primary"
rounded="none"
[attr.aria-label]="pageLabel(start - 1)"
[attr.title]="pageLabel(start - 1)"
(click)="changePage(start - 2)">...</button>
}
@for (num of buttons; track num) {
<button
type="button"
kendoPagerFocusable
kendoButton
[size]="size"
fillMode="flat"
themeColor="primary"
rounded="none"
[attr.aria-label]="pageLabel(num)"
[attr.title]="pageLabel(num)"
[attr.aria-current]="currentPage === num ? 'page' : undefined"
[selected]="currentPage === num"
(click)="currentPage === num ? false : changePage(num - 1)">
{{num}}
</button>
}
@if (end < totalPages) {
<button
type="button"
kendoPagerFocusable
kendoButton
[size]="size"
fillMode="flat"
themeColor="primary"
rounded="none"
[attr.aria-label]="pageLabel(end + 1)"
[attr.title]="pageLabel(end + 1)"
(click)="changePage(end)">...</button>
}
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: PagerFocusableDirective, selector: "[kendoPagerFocusable]", exportAs: ["kendoPagerFocusable"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerNumericButtonsComponent, decorators: [{
type: Component,
args: [{
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'kendo-datapager-numeric-buttons, kendo-pager-numeric-buttons',
template: `
<div class="k-pager-numbers" #numbers>
@if (start > 1) {
<button
type="button"
kendoPagerFocusable
kendoButton
[size]="size"
fillMode="flat"
themeColor="primary"
rounded="none"
[attr.aria-label]="pageLabel(start - 1)"
[attr.title]="pageLabel(start - 1)"
(click)="changePage(start - 2)">...</button>
}
@for (num of buttons; track num) {
<button
type="button"
kendoPagerFocusable
kendoButton
[size]="size"
fillMode="flat"
themeColor="primary"
rounded="none"
[attr.aria-label]="pageLabel(num)"
[attr.title]="pageLabel(num)"
[attr.aria-current]="currentPage === num ? 'page' : undefined"
[selected]="currentPage === num"
(click)="currentPage === num ? false : changePage(num - 1)">
{{num}}
</button>
}
@if (end < totalPages) {
<button
type="button"
kendoPagerFocusable
kendoButton
[size]="size"
fillMode="flat"
themeColor="primary"
rounded="none"
[attr.aria-label]="pageLabel(end + 1)"
[attr.title]="pageLabel(end + 1)"
(click)="changePage(end)">...</button>
}
</div>
`,
standalone: true,
imports: [PagerFocusableDirective, ButtonComponent]
}]
}], ctorParameters: () => [{ type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }, { type: PagerContextService }, { type: i0.Renderer2 }], propDecorators: { selectElement: [{
type: ViewChild,
args: ['select', { read: ElementRef }]
}], numbersElement: [{
type: ViewChild,
args: ['numbers', { read: ElementRef }]
}], buttonCount: [{
type: Input
}], size: [{
type: Input
}] } });
// eslint-disable no-access-missing-member
/**
* Represents the Kendo UI Pager Next Buttons component for Angular. Displays buttons for navigating to the next and to the last page ([see example]({% slug pager_settings %})).
*
* @example
* ```html
* <kendo-pager [skip]="skip" [pageSize]="pageSize" [total]="total">
* <ng-template kendoPagerTemplate>
* <kendo-pager-next-buttons></kendo-pager-next-buttons>
* </ng-template>
* </kendo-pager>
* ```
*/
class PagerNextButtonsComponent extends PagerElementComponent {
/**
* @hidden
*
* @readonly
* @type {boolean}
* @memberOf PagerNextButtonsComponent
*/
get disabled() {
return this.currentPage === this.totalPages || !this.total;
}
/**
* Specifies the padding of the navigation buttons.
*
* @default 'medium'
*/
size = DEFAULT_SIZE;
constructor(localization, pagerContext, cd) {
super(localization, pagerContext, cd);
}
/**
* @hidden
*/
onClick(isLast = false) {
if (this.disabled) {
return false;
}
const targetPage = isLast ? this.totalPages - 1 : this.currentPage;
return this.currentPage !== this.totalPages ? this.changePage(targetPage) : false;
}
onChanges({ total, skip, pageSize }) {
this.total = total;
this.skip = skip;
this.pageSize = pageSize;
this.cd.markForCheck();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerNextButtonsComponent, deps: [{ token: i1.LocalizationService }, { token: PagerContextService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: PagerNextButtonsComponent, isStandalone: true, selector: "kendo-datapager-next-buttons, kendo-pager-next-buttons", inputs: { size: "size" }, usesInheritance: true, ngImport: i0, template: `
<button kendoButton kendoPagerFocusable
type="button"
[size]="size"
[icon]="nextArrowIcons[0]"
[svgIcon]="nextArrowSVGIcons[0]"
fillMode="flat"
rounded="none"
class="k-pager-nav"
[attr.aria-disabled]="disabled"
[class.k-disabled]="disabled"
[title]="textFor('nextPage')"
[attr.aria-label]="textFor('nextPage')"
(click)="onClick()">
</button>
<button kendoButton kendoPagerFocusable
type="button"
[size]="size"
[icon]="nextArrowIcons[1]"
[svgIcon]="nextArrowSVGIcons[1]"
fillMode="flat"
rounded="none"
class="k-pager-nav k-pager-last"
[attr.aria-disabled]="disabled"
[class.k-disabled]="disabled"
[title]="textFor('lastPage')"
[attr.aria-label]="textFor('lastPage')"
(click)="onClick(true)">
</button>
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: PagerFocusableDirective, selector: "[kendoPagerFocusable]", exportAs: ["kendoPagerFocusable"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerNextButtonsComponent, decorators: [{
type: Component,
args: [{
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'kendo-datapager-