@progress/kendo-angular-listview
Version:
Kendo UI Angular listview component
861 lines (846 loc) • 34.2 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 { Component, HostBinding, Input, Output, ContentChild, ChangeDetectionStrategy, EventEmitter, NgZone, Renderer2, ElementRef, ViewChild, ViewChildren, QueryList, ChangeDetectorRef } from '@angular/core';
import { EventsOutsideAngularDirective, hasObservers, isChanged } from '@progress/kendo-angular-common';
import { validatePackage } from '@progress/kendo-licensing';
import { packageMetadata } from './package-metadata';
import { L10N_PREFIX, LocalizationService } from '@progress/kendo-angular-l10n';
import { NavigationService } from './navigation/navigation.service';
import { ListViewNavigableItemDirective } from './navigation/listview-navigable-item.directive';
import { ItemTemplateDirective } from './templates/item-template.directive';
import { HeaderTemplateDirective } from './templates/header-template.directive';
import { FooterTemplateDirective } from './templates/footer-template.directive';
import { LoaderTemplateDirective } from './templates/loader-template.directive';
import { EditTemplateDirective } from './editing/edit-template.directive';
import { EditService } from './editing/edit.service';
import { isPresent } from './utils';
import { FormGroup, FormControl } from '@angular/forms';
import { NgIf, NgTemplateOutlet, NgClass, NgStyle, NgFor } from '@angular/common';
import { PagerComponent } from '@progress/kendo-angular-pager';
import * as i0 from "@angular/core";
import * as i1 from "./editing/edit.service";
import * as i2 from "./navigation/navigation.service";
const DEFAULT_PAGER_SETTINGS = {
position: 'bottom',
buttonCount: 5,
info: true,
previousNext: true,
type: 'numeric',
pageSizeValues: [5, 10, 20]
};
const createControl = (source) => (acc, key) => {
acc[key] = new FormControl(source[key]);
return acc;
};
/**
* Represents the Kendo UI ListView component for Angular.
* Displays a list of data items and supports paging, editing, and custom templates
* ([see overview]({% slug overview_listview %})).
*
* @example
* ```typescript
* @Component({
* selector: 'my-app',
* template: `
* <kendo-listview
* [data]="items"
* [pageable]="true"
* [pageSize]="5">
* <ng-template kendoListViewItemTemplate let-dataItem>
* <div class="item">
* <h3>{{ dataItem.name }}</h3>
* <p>{{ dataItem.description }}</p>
* </div>
* </ng-template>
* </kendo-listview>
* `
* })
* export class AppComponent {
* items = [
* { name: 'Item 1', description: 'First item' },
* { name: 'Item 2', description: 'Second item' }
* ];
* }
* ```
*/
export class ListViewComponent {
ngZone;
element;
renderer;
changeDetectorRef;
editService;
navigationService;
/**
* @hidden
*/
className = true;
/**
* @hidden
*/
itemTemplate;
/**
* @hidden
*/
headerTemplate;
/**
* @hidden
*/
footerTemplate;
/**
* @hidden
*/
loaderTemplate;
/**
* @hidden
*/
contentContainer;
/**
* @hidden
*/
editTemplate;
/**
* @hidden
*/
listViewItems;
/**
* Specifies if a border should be rendered around the listview element.
*
* @default false
*/
bordered = false;
/**
* Specifies the data collection that populates the ListView
* ([see data binding examples]({% slug paging_listview %})).
*/
set data(value) {
this.lastScrollTop = this.contentContainer?.nativeElement.scrollTop ?? 0;
this._data = value;
}
get data() {
return this._data;
}
/**
* Specifies whether the loading indicator of the ListView displays
* ([see example]({% slug paging_listview %}#toc-remote-binding)).
*
* @default false
*/
loading = false;
/**
* Specifies the CSS styles that render on the content container element of the ListView.
* Supports the type of values that [`ngStyle`](link:site.data.urls.angular['ngstyleapi']) supports.
*/
containerStyle;
/**
* Specifies the CSS styles that render on each item element wrapper of the ListView.
* Supports the type of values that [`ngStyle`](link:site.data.urls.angular['ngstyleapi']) supports.
*/
itemStyle;
/**
* Specifies the CSS class that renders on the content container element of the ListView.
* Supports the type of values that [`ngClass`](link:site.data.urls.angular['ngclassapi']) supports.
*/
containerClass;
/**
* Specifies the CSS class that renders on each item element wrapper of the ListView.
* Supports the type of values that [`ngClass`](link:site.data.urls.angular['ngclassapi']) supports.
*/
itemClass;
/**
* Specifies the content container `aria-label` attribute
* ([see example]({% slug accessibility_listview %}#toc-accessible-names)).
*/
containerLabel;
/**
* Specifies the content container `role` attribute
* ([more details]({% slug accessibility_listview %}#toc-wai-aria-support)).
*
* @default 'list'
*/
containerRole = 'list';
/**
* Specifies the list item `role` attribute
* ([more details]({% slug accessibility_listview %}#toc-wai-aria-support)).
*
* @default 'listitem'
*/
listItemRole = 'listitem';
/**
* Specifies whether keyboard navigation is enabled
* ([see example]({% slug keyboard_navigation_listview %})).
*
* @default true
*/
set navigable(navigable) {
if (!navigable && isPresent(this.removeNavigationListeners)) {
this.removeNavigationListeners();
this.removeNavigationListeners = null;
this.navigationService.isEnabled = false;
}
else if (navigable && !isPresent(this.removeNavigationListeners)) {
this.addNavigationListeners();
this.navigationService.isEnabled = true;
}
this._navigable = navigable;
}
get navigable() {
return this._navigable;
}
/**
* Specifies the page size used by the ListView pager
* ([more details]({% slug paging_listview %})).
*/
pageSize;
/**
* Defines the number of records to be skipped by the pager
* ([more details]({% slug paging_listview %})).
*/
set skip(skip) {
const parsed = parseInt(skip, 10);
const defaultSkipValue = 0;
this._skip = !isNaN(parsed) ? parsed : defaultSkipValue;
}
get skip() {
return this._skip;
}
/**
* Configures whether the ListView renders a pager
* ([more details]({% slug paging_listview %})).
* When you provide a boolean value, it renders a pager with the default settings.
*/
set pageable(pageable) {
this._pageable = pageable;
this.pagerSettings = pageable ? Object.assign({}, DEFAULT_PAGER_SETTINGS, pageable) : null;
}
get pageable() {
return this._pageable;
}
/**
* Specifies the height (in pixels) of the ListView component.
* When the content height exceeds the component height, a vertical scrollbar renders.
*
* To set the height of the ListView, you can also use `style.height`. The `style.height`
* option supports units such as `px`, `%`, `em`, `rem`, and others.
*/
height;
/**
* Fires when you scroll to the last record on the page
* ([see endless scrolling example]({% slug scrollmodes_listview %}#toc-endless-scrolling)).
*/
scrollBottom = new EventEmitter();
/**
* Fires when you change the page or the page size of the ListView
* ([see example]({% slug paging_listview %}#toc-remote-binding)).
* You have to handle the event yourself and page the data.
*/
pageChange = new EventEmitter();
/**
* Fires when you change the page size of the ListView. You can prevent this event (`$event.preventDefault()`).
* When not prevented, the `pageChange` event fires subsequently.
*/
pageSizeChange = new EventEmitter();
/**
* Fires when you click the **Edit** command button to edit an item
* ([see example]({% slug editing_template_forms_listview %}#toc-editing-records)).
*/
edit = new EventEmitter();
/**
* Fires when you click the **Cancel** command button to close an item
* ([see example]({% slug editing_template_forms_listview %}#toc-cancelling-editing)).
*/
cancel = new EventEmitter();
/**
* Fires when you click the **Save** command button to save changes in an item
* ([see example]({% slug editing_template_forms_listview %}#toc-saving-records)).
*/
save = new EventEmitter();
/**
* Fires when you click the **Remove** command button to remove an item
* ([see example]({% slug editing_template_forms_listview %}#toc-removing-records)).
*/
remove = new EventEmitter();
/**
* Fires when you click the **Add** command button to add a new item
* ([see example]({% slug editing_template_forms_listview %}#toc-adding-records)).
*/
add = new EventEmitter();
/**
* @hidden
*/
pagerSettings;
/**
* @hidden
*
* Gets the data items passed to the ListView.
* If a `ListViewDataResult` is passed, the data value is used. If an array is passed - it's directly used.
*/
get items() {
if (!isPresent(this.data)) {
return [];
}
return Array.isArray(this.data) ? this.data : this.data.data;
}
/**
* @hidden
*
* Gets the total number of records passed to the ListView.
* If a `ListViewDataResult` is passed, the total value is used. If an array is passed - its length is used.
*/
get total() {
if (!this.pageable) {
return;
}
if (!isPresent(this.data)) {
return 0;
}
return Array.isArray(this.data) ? this.data.length : this.data.total;
}
/**
* @hidden
*/
get containerTabindex() {
// workaround for FF, where a scrollable container is focusable even without a tabindex and creates an unwanted tab stop
// https://bugzilla.mozilla.org/show_bug.cgi?id=616594
return this.navigable ? -1 : null;
}
/**
* Gets the current active item index
* ([see example]({% slug keyboard_navigation_listview %}#toc-controlling-the-focus)).
* Returns `null` when keyboard navigation is disabled.
*/
get activeIndex() {
return this.navigationService.activeIndex;
}
removeNavigationListeners;
_skip = 0;
_navigable = true;
_pageable;
lastScrollTop;
_data;
editServiceSubscription;
constructor(ngZone, element, renderer, changeDetectorRef, editService, navigationService) {
this.ngZone = ngZone;
this.element = element;
this.renderer = renderer;
this.changeDetectorRef = changeDetectorRef;
this.editService = editService;
this.navigationService = navigationService;
validatePackage(packageMetadata);
this.attachEditHandlers();
}
ngAfterViewInit() {
this.lastScrollTop = this.contentContainer?.nativeElement.scrollTop;
}
ngOnChanges(changes) {
if (isChanged('height', changes, false)) {
this.renderer.setStyle(this.element.nativeElement, 'height', `${this.height}px`);
}
}
ngOnDestroy() {
if (isPresent(this.editServiceSubscription)) {
this.editServiceSubscription.unsubscribe();
}
}
/**
* @hidden
*/
templateContext(index) {
return {
"$implicit": this.items[index],
"isLast": index === this.items.length - 1,
"isFirst": index === 0,
"dataItem": this.items[index],
"index": index
};
}
/**
* @hidden
*/
editTemplateContext(index) {
const isNew = index === -1;
const group = isNew ? this.editService.newItemGroup : this.editService.editGroup(index);
return {
"$implicit": group,
"formGroup": group,
"dataItem": isNew ? this.editService.newDataItem : this.items[index],
"isNew": isNew,
"index": index
};
}
/**
* Focuses the item at the specified index ([see example]({% slug keyboard_navigation_listview %}#toc-controlling-the-focus)):
* - When you specify no index, the current active index receives focus.
* - When the passed value is below `0`, the first item receives focus.
* - When the passed value is above the last available index, the last item receives focus.
*
* > The `index` parameter is based on the logical structure of the ListView and does not correspond to the data item index&mdash
* > the index `0` corresponds to the first rendered list item. Paging is not taken into account.
* > Also, the `navigable` property must first be set to `true` for the method to work as expected.
*/
focus(index) {
const totalRenderedItems = this.listViewItems.length;
this.navigationService.focusIndex(index, totalRenderedItems);
}
/**
* Creates a new item editor ([see example]({% slug editing_template_forms_listview %}#toc-adding-records)).
*
* @param {FormGroup} group - The [`FormGroup`](link:site.data.urls.angular['formgroupapi']) that describes
* the edit form. When called with a data item, it builds the `FormGroup` from the data item fields.
*/
addItem(group) {
const isFormGroup = group instanceof FormGroup;
if (!isFormGroup) {
const fields = Object.keys(group).reduce(createControl(group), {});
group = new FormGroup(fields);
}
this.editService.addItem(group);
}
/**
* Switches the specified item to edit mode ([see example]({% slug editing_template_forms_listview %}#toc-editing-records)).
*
* @param index - The item index that switches to edit mode.
* @param group - The [`FormGroup`](link:site.data.urls.angular['formgroupapi'])
* that describes the edit form.
*/
editItem(index, group) {
this.editService.editItem(index, group);
this.changeDetectorRef.markForCheck();
}
/**
* Closes the editor for a given item ([see example]({% slug editing_template_forms_listview %}#toc-cancelling-editing)).
*
* @param {number} index - The item index that switches out of the edit mode. When you provide no index, the editor of the new item will close.
*/
closeItem(index) {
this.editService.close(index);
this.changeDetectorRef.markForCheck();
}
/**
* @hidden
*/
isEdited(index) {
return this.editService.isEdited(index);
}
/**
* @hidden
*/
handlePageChange(event) {
this.scrollToContainerTop();
const firstIndex = 0;
this.navigationService.setActiveIndex(firstIndex);
this.pageChange.emit(event);
}
/**
* @hidden
*/
handleContentScroll = () => {
if (!hasObservers(this.scrollBottom)) {
return;
}
const THRESHOLD = 2;
const { scrollHeight, scrollTop, clientHeight } = this.contentContainer.nativeElement;
const isScrollUp = this.lastScrollTop > scrollTop;
this.lastScrollTop = scrollTop;
if (isScrollUp) {
return;
}
const atBottom = scrollHeight - clientHeight - scrollTop <= THRESHOLD;
if (atBottom) {
this.ngZone.run(() => {
const event = { sender: this };
this.scrollBottom.emit(event);
});
}
};
/**
* @hidden
*/
itemPosInSet(index) {
if (!this.pageable) {
return;
}
// adds 1 as the aria-posinset is not zero-based and the counting starts from 1
return this.skip + index + 1;
}
scrollToContainerTop() {
const container = this.contentContainer.nativeElement;
container.scrollTop = 0;
container.scrollLeft = 0;
}
addNavigationListeners() {
this.ngZone.runOutsideAngular(() => {
const removeKeydownListener = this.renderer.listen(this.contentContainer.nativeElement, 'keydown', event => this.navigationService.handleKeyDown(event, this.listViewItems.length));
const removeFocusInListener = this.renderer.listen(this.contentContainer.nativeElement, 'focusin', event => this.navigationService.handleFocusIn(event));
const removeFocusOutListener = this.renderer.listen(this.contentContainer.nativeElement, 'focusout', event => this.navigationService.handleFocusOut(event));
this.removeNavigationListeners = () => {
removeKeydownListener();
removeFocusInListener();
removeFocusOutListener();
};
});
}
attachEditHandlers() {
if (!isPresent(this.editService)) {
return;
}
this.editServiceSubscription = this.editService
.changes.subscribe(this.emitCRUDEvent.bind(this));
}
emitCRUDEvent(args) {
const { action, itemIndex, formGroup } = args;
let dataItem = this.items[itemIndex];
if (action !== 'add' && formGroup) {
dataItem = formGroup.value;
}
Object.assign(args, {
dataItem: dataItem,
sender: this
});
this[action].emit(args);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ListViewComponent, deps: [{ token: i0.NgZone }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i1.EditService }, { token: i2.NavigationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ListViewComponent, isStandalone: true, selector: "kendo-listview", inputs: { bordered: "bordered", data: "data", loading: "loading", containerStyle: "containerStyle", itemStyle: "itemStyle", containerClass: "containerClass", itemClass: "itemClass", containerLabel: "containerLabel", containerRole: "containerRole", listItemRole: "listItemRole", navigable: "navigable", pageSize: "pageSize", skip: "skip", pageable: "pageable", height: "height" }, outputs: { scrollBottom: "scrollBottom", pageChange: "pageChange", pageSizeChange: "pageSizeChange", edit: "edit", cancel: "cancel", save: "save", remove: "remove", add: "add" }, host: { properties: { "class.k-listview": "this.className", "class.k-listview-bordered": "this.bordered" } }, providers: [
EditService,
NavigationService,
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.listview'
}
], queries: [{ propertyName: "itemTemplate", first: true, predicate: ItemTemplateDirective, descendants: true }, { propertyName: "headerTemplate", first: true, predicate: HeaderTemplateDirective, descendants: true }, { propertyName: "footerTemplate", first: true, predicate: FooterTemplateDirective, descendants: true }, { propertyName: "loaderTemplate", first: true, predicate: LoaderTemplateDirective, descendants: true }, { propertyName: "editTemplate", first: true, predicate: EditTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "contentContainer", first: true, predicate: ["contentContainer"], descendants: true, static: true }, { propertyName: "listViewItems", predicate: ListViewNavigableItemDirective, descendants: true }], exportAs: ["kendoListView"], usesOnChanges: true, ngImport: i0, template: `
<!-- top pager -->
<ng-template
*ngIf="pagerSettings?.position !== 'bottom'"
[ngTemplateOutlet]="pagerTemplate"
[ngTemplateOutletContext]="{ pagerClass: 'k-listview-pager k-listview-pager-top' }"
>
</ng-template>
<!-- header -->
<div
*ngIf="headerTemplate"
class="k-listview-header"
>
<ng-template
[ngTemplateOutlet]="headerTemplate?.templateRef"
>
</ng-template>
</div>
<!-- content -->
<div
#contentContainer
[attr.tabindex]="containerTabindex"
class="k-listview-content"
[ngClass]="containerClass"
[ngStyle]="containerStyle"
[kendoEventsOutsideAngular]="{
scroll: handleContentScroll
}"
[scope]="this"
[attr.role]="containerRole"
[attr.aria-label]="containerLabel"
>
<!-- new item edit template -->
<div
*ngIf="editService.hasNewItem"
class="k-listview-item"
[attr.role]="listItemRole"
kendoListViewNavigableItem
[index]="-1"
[attr.data-kendo-listview-item-index]="-1"
[ngClass]="itemClass"
[ngStyle]="itemStyle"
>
<ng-template
*ngIf="editTemplate"
[ngTemplateOutlet]="editTemplate?.templateRef"
[ngTemplateOutletContext]="editTemplateContext(-1)"
>
</ng-template>
</div>
<!-- items -->
<div
*ngFor="let dataItem of items; let index = index; let first = first; let last = last;"
class="k-listview-item"
[attr.role]="listItemRole"
[attr.aria-posinset]="itemPosInSet(index)"
[attr.aria-setsize]="total"
kendoListViewNavigableItem
[index]="index"
[attr.data-kendo-listview-item-index]="index"
[ngClass]="itemClass"
[ngStyle]="itemStyle"
>
<ng-template
[ngTemplateOutlet]="isEdited(index) ? editTemplate?.templateRef : itemTemplate?.templateRef"
[ngTemplateOutletContext]="isEdited(index) ? editTemplateContext(index) : templateContext(index)"
>
</ng-template>
</div>
</div>
<!-- loading indicator -->
<div
*ngIf="loading && !loaderTemplate"
class="k-loading-mask"
>
<!-- TODO: the k-loading-text is hidden with css but read by readers - review when implementing accessibility + possible localization case -->
<span class="k-loading-text">Loading</span>
<div class="k-loading-image"></div>
<div class="k-loading-color"></div>
</div>
<ng-template
*ngIf="loading && loaderTemplate"
[ngTemplateOutlet]="loaderTemplate.templateRef"
>
</ng-template>
<!-- footer -->
<div
*ngIf="footerTemplate"
class="k-listview-footer"
>
<ng-template
[ngTemplateOutlet]="footerTemplate?.templateRef"
>
</ng-template>
</div>
<!-- bottom pager -->
<ng-template
*ngIf="pagerSettings?.position !== 'top'"
[ngTemplateOutlet]="pagerTemplate"
[ngTemplateOutletContext]="{ pagerClass: 'k-listview-pager' }"
>
</ng-template>
<!-- pager template -->
<ng-template #pagerTemplate let-pagerClass="pagerClass">
<kendo-datapager
*ngIf="pageable"
[class]="pagerClass"
[total]="total"
[pageSize]="pageSize"
[skip]="skip"
[buttonCount]="pagerSettings.buttonCount"
[info]="pagerSettings.info"
[previousNext]="pagerSettings.previousNext"
[type]="pagerSettings.type"
[pageSizeValues]="pagerSettings.pageSizeValues"
(pageChange)="handlePageChange($event)"
(pageSizeChange)="pageSizeChange.emit($event)"
>
</kendo-datapager>
</ng-template>
`, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: EventsOutsideAngularDirective, selector: "[kendoEventsOutsideAngular]", inputs: ["kendoEventsOutsideAngular", "scope"] }, { kind: "directive", type: ListViewNavigableItemDirective, selector: "[kendoListViewNavigableItem]", inputs: ["index"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: PagerComponent, selector: "kendo-datapager, kendo-pager", inputs: ["externalTemplate", "total", "skip", "pageSize", "buttonCount", "info", "type", "pageSizeValues", "previousNext", "navigable", "size", "responsive", "adaptiveMode"], outputs: ["pageChange", "pageSizeChange", "pagerInputVisibilityChange", "pageTextVisibilityChange", "itemsTextVisibilityChange"], exportAs: ["kendoDataPager", "kendoPager"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ListViewComponent, decorators: [{
type: Component,
args: [{
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs: 'kendoListView',
selector: 'kendo-listview',
providers: [
EditService,
NavigationService,
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.listview'
}
],
template: `
<!-- top pager -->
<ng-template
*ngIf="pagerSettings?.position !== 'bottom'"
[ngTemplateOutlet]="pagerTemplate"
[ngTemplateOutletContext]="{ pagerClass: 'k-listview-pager k-listview-pager-top' }"
>
</ng-template>
<!-- header -->
<div
*ngIf="headerTemplate"
class="k-listview-header"
>
<ng-template
[ngTemplateOutlet]="headerTemplate?.templateRef"
>
</ng-template>
</div>
<!-- content -->
<div
#contentContainer
[attr.tabindex]="containerTabindex"
class="k-listview-content"
[ngClass]="containerClass"
[ngStyle]="containerStyle"
[kendoEventsOutsideAngular]="{
scroll: handleContentScroll
}"
[scope]="this"
[attr.role]="containerRole"
[attr.aria-label]="containerLabel"
>
<!-- new item edit template -->
<div
*ngIf="editService.hasNewItem"
class="k-listview-item"
[attr.role]="listItemRole"
kendoListViewNavigableItem
[index]="-1"
[attr.data-kendo-listview-item-index]="-1"
[ngClass]="itemClass"
[ngStyle]="itemStyle"
>
<ng-template
*ngIf="editTemplate"
[ngTemplateOutlet]="editTemplate?.templateRef"
[ngTemplateOutletContext]="editTemplateContext(-1)"
>
</ng-template>
</div>
<!-- items -->
<div
*ngFor="let dataItem of items; let index = index; let first = first; let last = last;"
class="k-listview-item"
[attr.role]="listItemRole"
[attr.aria-posinset]="itemPosInSet(index)"
[attr.aria-setsize]="total"
kendoListViewNavigableItem
[index]="index"
[attr.data-kendo-listview-item-index]="index"
[ngClass]="itemClass"
[ngStyle]="itemStyle"
>
<ng-template
[ngTemplateOutlet]="isEdited(index) ? editTemplate?.templateRef : itemTemplate?.templateRef"
[ngTemplateOutletContext]="isEdited(index) ? editTemplateContext(index) : templateContext(index)"
>
</ng-template>
</div>
</div>
<!-- loading indicator -->
<div
*ngIf="loading && !loaderTemplate"
class="k-loading-mask"
>
<!-- TODO: the k-loading-text is hidden with css but read by readers - review when implementing accessibility + possible localization case -->
<span class="k-loading-text">Loading</span>
<div class="k-loading-image"></div>
<div class="k-loading-color"></div>
</div>
<ng-template
*ngIf="loading && loaderTemplate"
[ngTemplateOutlet]="loaderTemplate.templateRef"
>
</ng-template>
<!-- footer -->
<div
*ngIf="footerTemplate"
class="k-listview-footer"
>
<ng-template
[ngTemplateOutlet]="footerTemplate?.templateRef"
>
</ng-template>
</div>
<!-- bottom pager -->
<ng-template
*ngIf="pagerSettings?.position !== 'top'"
[ngTemplateOutlet]="pagerTemplate"
[ngTemplateOutletContext]="{ pagerClass: 'k-listview-pager' }"
>
</ng-template>
<!-- pager template -->
<ng-template #pagerTemplate let-pagerClass="pagerClass">
<kendo-datapager
*ngIf="pageable"
[class]="pagerClass"
[total]="total"
[pageSize]="pageSize"
[skip]="skip"
[buttonCount]="pagerSettings.buttonCount"
[info]="pagerSettings.info"
[previousNext]="pagerSettings.previousNext"
[type]="pagerSettings.type"
[pageSizeValues]="pagerSettings.pageSizeValues"
(pageChange)="handlePageChange($event)"
(pageSizeChange)="pageSizeChange.emit($event)"
>
</kendo-datapager>
</ng-template>
`,
standalone: true,
imports: [NgIf, NgTemplateOutlet, NgClass, NgStyle, EventsOutsideAngularDirective, ListViewNavigableItemDirective, NgFor, PagerComponent]
}]
}], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i1.EditService }, { type: i2.NavigationService }]; }, propDecorators: { className: [{
type: HostBinding,
args: ['class.k-listview']
}], itemTemplate: [{
type: ContentChild,
args: [ItemTemplateDirective, { static: false }]
}], headerTemplate: [{
type: ContentChild,
args: [HeaderTemplateDirective, { static: false }]
}], footerTemplate: [{
type: ContentChild,
args: [FooterTemplateDirective, { static: false }]
}], loaderTemplate: [{
type: ContentChild,
args: [LoaderTemplateDirective, { static: false }]
}], contentContainer: [{
type: ViewChild,
args: ['contentContainer', { static: true }]
}], editTemplate: [{
type: ContentChild,
args: [EditTemplateDirective, { static: false }]
}], listViewItems: [{
type: ViewChildren,
args: [ListViewNavigableItemDirective]
}], bordered: [{
type: Input
}, {
type: HostBinding,
args: ['class.k-listview-bordered']
}], data: [{
type: Input
}], loading: [{
type: Input
}], containerStyle: [{
type: Input
}], itemStyle: [{
type: Input
}], containerClass: [{
type: Input
}], itemClass: [{
type: Input
}], containerLabel: [{
type: Input
}], containerRole: [{
type: Input
}], listItemRole: [{
type: Input
}], navigable: [{
type: Input
}], pageSize: [{
type: Input
}], skip: [{
type: Input
}], pageable: [{
type: Input
}], height: [{
type: Input
}], scrollBottom: [{
type: Output
}], pageChange: [{
type: Output
}], pageSizeChange: [{
type: Output
}], edit: [{
type: Output
}], cancel: [{
type: Output
}], save: [{
type: Output
}], remove: [{
type: Output
}], add: [{
type: Output
}] } });