diff --git a/e2e/tests-app-ng/app/app.routes.ts b/e2e/tests-app-ng/app/app.routes.ts index d68882440..486328ba2 100644 --- a/e2e/tests-app-ng/app/app.routes.ts +++ b/e2e/tests-app-ng/app/app.routes.ts @@ -17,6 +17,7 @@ import { ListViewComponent } from "./list-view/list-view-page.component"; import { ListViewControlComponent } from "./list-view/list-view-item-template.component"; import { ListViewAsyncPipeComponent } from "./list-view/async-pipe-template.component"; import { ListViewMainPageComponent } from "./list-view/list-view-main-page.component"; +import { ListViewSegmentedBarPageComponent } from "./list-view/list-view-nested-segmented-bar-page.component"; import { ListViewWithNestedTemplateComponent } from "./list-view/list-view-nested-template.component"; import { ListViewMultipleTemplatesComponent } from "./list-view/multiple-templates.component"; @@ -68,6 +69,7 @@ export const routableComponents = [ ListViewComponent, ListViewControlComponent, ListViewAsyncPipeComponent, + ListViewSegmentedBarPageComponent, ListViewWithNestedTemplateComponent, ListViewMultipleTemplatesComponent, @@ -131,6 +133,10 @@ export const routes = [ { path: "ListViewExamples/commonTemplate", component: ListViewComponent, data: { title: "commonTemplate" } }, { path: "ListViewExamples/customTemplate", component: ListViewControlComponent, data: { title: "customTemplate" } }, { path: "listView/asyncPipeTemplate", component: ListViewAsyncPipeComponent, data: { title: "asyncPipeTemplate" } }, + { + path: "ListViewExamples/segmentedBarTemplate", + component: ListViewSegmentedBarPageComponent, + data: { title: "segmentedBarTemplate" } }, { path: "listView/nestedTemplate", component: ListViewWithNestedTemplateComponent, diff --git a/e2e/tests-app-ng/app/list-view/list-view-main-page.component.ts b/e2e/tests-app-ng/app/list-view/list-view-main-page.component.ts index d08c565ba..3b7e95756 100644 --- a/e2e/tests-app-ng/app/list-view/list-view-main-page.component.ts +++ b/e2e/tests-app-ng/app/list-view/list-view-main-page.component.ts @@ -7,6 +7,7 @@ import { Component } from "@angular/core"; + diff --git a/e2e/tests-app-ng/app/list-view/list-view-nested-segmented-bar-page.component.ts b/e2e/tests-app-ng/app/list-view/list-view-nested-segmented-bar-page.component.ts new file mode 100644 index 000000000..ec0d9d963 --- /dev/null +++ b/e2e/tests-app-ng/app/list-view/list-view-nested-segmented-bar-page.component.ts @@ -0,0 +1,127 @@ +import { Component, ViewChild, ElementRef, OnInit } from "@angular/core"; +import { SegmentedBarItem, SegmentedBar } from "tns-core-modules/ui/segmented-bar/segmented-bar"; +import { ListView } from "tns-core-modules/ui/list-view/list-view"; +import { EventData } from "tns-core-modules/ui/page/page"; + +interface DataItem { + id: number; + name: string; + type: string; +} + +@Component({ + moduleId: module.id, + selector: "segmented-bar-list-test", + template: ` + + + + + + + + + + + + + + + + + + + + + + + `, +}) +export class ListViewSegmentedBarPageComponent implements OnInit { + public displayedItems: Array = []; + public items: Array; + public segmentedBarItems: SegmentedBarItem[] = this.createSegmentedBarItems(); + + @ViewChild("listViewTest", { static: false }) + private listViewTest?: ElementRef; + + constructor() { + this.items = []; + + for (let i = 0; i < 20; i++) { + const type = "dataItemTemplate"; + + this.items.push({ + id: i, + name: `data item ${i}`, + type: type, + }); + } + } + + public ngOnInit() { + this.displayedItems = this.updateItems(true); + } + + public onButtonPress() { + // tslint:disable-next-line: no-unused-expression + new Promise((resolve) => { + setTimeout(() => { + if (this.listViewTest) { + console.log("Scrolling to the top of the list..."); + const listView = this.listViewTest.nativeElement as ListView; + listView.scrollToIndex(0); + } + resolve(); + }, 150); + }); + + this.displayedItems = this.updateItems(false); + } + + public onSegmentedBarPress(args: EventData) { + if (args && args.object) { + const segmentBar = args.object as SegmentedBar; + const selectedOdd = segmentBar.selectedIndex === 0; + this.displayedItems = this.updateItems(selectedOdd); + } + } + + public createSegmentedBarItems() { + const itemOdd = new SegmentedBarItem(); + itemOdd.title = "Odd Items"; + const itemEven = new SegmentedBarItem(); + itemEven.title = "Even Items"; + return [itemOdd, itemEven]; + } + + public templateSelector(item: DataItem): string { + return item.type; + } + + private updateItems(odd: boolean) { + const items = [ + { + id: -1, + name: "Segmented Bar", + type: "segmentedBarTemplate", + }, + ...(odd + ? this.items.filter((item) => item.id % 2 === 1) + : this.items.filter((item) => item.id % 2 === 0)), + { + id: 999, + name: "Refresh test", + type: "buttonTemplate", + }, + ]; + return items; + } +} diff --git a/nativescript-angular/view-util.ts b/nativescript-angular/view-util.ts index c16794e6c..5d0e4a9db 100644 --- a/nativescript-angular/view-util.ts +++ b/nativescript-angular/view-util.ts @@ -260,6 +260,10 @@ export class ViewUtil { } private removeLayoutChild(parent: NgLayoutBase, child: NgView): void { + if (isLogEnabled()) { + traceLog(`ViewUtil.removeLayoutChild parent: ${parent} child: ${child}`); + } + const index = parent.getChildIndex(child); if (index !== -1) { @@ -371,6 +375,12 @@ export class ViewUtil { const propMap = this.getProperties(view); const propertyName = propMap.get(attributeName); + + // Ensure the children of a collection currently have no parent set. + if (Array.isArray(value)) { + this.removeParentReferencesFromItems(value); + } + if (propertyName) { // We have a lower-upper case mapped property. view[propertyName] = value; @@ -381,6 +391,18 @@ export class ViewUtil { view[attributeName] = value; } + private removeParentReferencesFromItems(items: any[]): void { + for (const item of items) { + if (item.parent && item.parentNode) { + if (isLogEnabled()) { + traceLog(`Unassigning parent ${item.parentNode} on value: ${item}`); + } + item.parent = undefined; + item.parentNode = undefined; + } + } + } + private getProperties(instance: any): Map { const type = instance && instance.constructor; if (!type) {