feat(core): Repeater multiple item templates implementation (#8981)

This commit is contained in:
Dimitris - Rafail Katsampas
2020-10-27 05:13:22 +02:00
committed by GitHub
parent 0bbdeaf0b5
commit b113f1916d
12 changed files with 343 additions and 21 deletions

View File

@@ -1,6 +1,6 @@
import { Label } from '../label';
import { LayoutBase } from '../layouts/layout-base';
import { View, CSSType, CustomLayoutView, Template } from '../core/view';
import { View, CSSType, CustomLayoutView, Template, KeyedTemplate } from '../core/view';
import { Property } from '../core/properties';
import { layout } from '../../utils';
import { StackLayout } from '../layouts/stack-layout';
@@ -19,7 +19,12 @@ export interface ItemsSource {
*/
@CSSType('Repeater')
export class Repeater extends CustomLayoutView {
// TODO: get rid of such hacks.
public static knownFunctions = ['itemTemplateSelector']; // See component-builder.ts isKnownFunction
private _isDirty = false;
private _itemTemplateSelector: (item: any, index: number, items: any) => string;
private _itemTemplateSelectorBindable;
public ios;
public android;
@@ -29,6 +34,15 @@ export class Repeater extends CustomLayoutView {
this.itemsLayout = new StackLayout();
}
@profile
public onLoaded() {
if (this._isDirty) {
this.refresh();
}
super.onLoaded();
}
/**
* Gets or set the items collection of the Repeater.
* The items property can be set to an array or an object defining length and getItem(index) method.
@@ -38,18 +52,44 @@ export class Repeater extends CustomLayoutView {
* Gets or set the item template of the Repeater.
*/
public itemTemplate: string | Template;
/**
* Gets or set the item templates of the Repeater.
*/
public itemTemplates: string | Array<KeyedTemplate>;
/**
* Gets or set the items layout of the Repeater. Default value is StackLayout with orientation="vertical".
*/
public itemsLayout: LayoutBase;
@profile
public onLoaded() {
if (this._isDirty) {
this.refresh();
}
get itemTemplateSelector(): string | ((item: any, index: number, items: any) => string) {
return this._itemTemplateSelector;
}
set itemTemplateSelector(value: string | ((item: any, index: number, items: any) => string)) {
if (typeof value === 'string') {
if (!this._itemTemplateSelectorBindable) {
this._itemTemplateSelectorBindable = new Label();
}
super.onLoaded();
this._itemTemplateSelectorBindable.bind({
sourceProperty: null,
targetProperty: 'templateKey',
expression: value,
});
this._itemTemplateSelector = (item: any, index: number, items: any) => {
item['$index'] = index;
if (this._itemTemplateSelectorBindable.bindingContext === item) {
this._itemTemplateSelectorBindable.bindingContext = null;
}
this._itemTemplateSelectorBindable.bindingContext = item;
return this._itemTemplateSelectorBindable.get('templateKey');
};
} else if (typeof value === 'function') {
this._itemTemplateSelector = value;
}
}
public _requestRefresh() {
@@ -73,8 +113,25 @@ export class Repeater extends CustomLayoutView {
const length = this.items.length;
for (let i = 0; i < length; i++) {
const viewToAdd = this.itemTemplate ? Builder.parse(this.itemTemplate, this) : this._getDefaultItemContent(i);
const dataItem = this._getDataItem(i);
let viewToAdd = null;
if (this._itemTemplateSelector && this.itemTemplates) {
const key = this._itemTemplateSelector(dataItem, i, this.items);
const length2 = this.itemTemplates.length;
for (let j = 0; j < length2; j++) {
const template = <KeyedTemplate>this.itemTemplates[j];
if (template.key === key) {
viewToAdd = template.createView();
break;
}
}
}
if (!viewToAdd) {
viewToAdd = this.itemTemplate ? Builder.parse(this.itemTemplate, this) : this._getDefaultItemContent(i);
}
viewToAdd.bindingContext = dataItem;
this.itemsLayout.addChild(viewToAdd);
}
@@ -147,7 +204,7 @@ export class Repeater extends CustomLayoutView {
Repeater.prototype.recycleNativeView = 'auto';
/**
* Represents the item template property of each ListView instance.
* Represents the item template property of each Repeater instance.
*/
export const itemTemplateProperty = new Property<Repeater, string | Template>({
name: 'itemTemplate',
@@ -159,7 +216,26 @@ export const itemTemplateProperty = new Property<Repeater, string | Template>({
itemTemplateProperty.register(Repeater);
/**
* Represents the property backing the items property of each ListView instance.
* Represents the items template property of each Repeater instance.
*/
export const itemTemplatesProperty = new Property<Repeater, string | Array<KeyedTemplate>>({
name: 'itemTemplates',
affectsLayout: true,
valueConverter: (value) => {
if (typeof value === 'string') {
return Builder.parseMultipleTemplates(value, null);
}
return value;
},
valueChanged: (target) => {
target._requestRefresh();
},
});
itemTemplatesProperty.register(Repeater);
/**
* Represents the property backing the items property of each Repeater instance.
*/
export const itemsProperty = new Property<Repeater, any[] | ItemsSource>({
name: 'items',