Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1b191b0

Browse files
authored
fix(segmented-bar): listview crash when scrolling (#2128)
1 parent f10a8fb commit 1b191b0

File tree

4 files changed

+156
-0
lines changed

4 files changed

+156
-0
lines changed

‎e2e/tests-app-ng/app/app.routes.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { ListViewComponent } from "./list-view/list-view-page.component";
1717
import { ListViewControlComponent } from "./list-view/list-view-item-template.component";
1818
import { ListViewAsyncPipeComponent } from "./list-view/async-pipe-template.component";
1919
import { ListViewMainPageComponent } from "./list-view/list-view-main-page.component";
20+
import { ListViewSegmentedBarPageComponent } from "./list-view/list-view-nested-segmented-bar-page.component";
2021
import { ListViewWithNestedTemplateComponent } from "./list-view/list-view-nested-template.component";
2122
import { ListViewMultipleTemplatesComponent } from "./list-view/multiple-templates.component";
2223

@@ -68,6 +69,7 @@ export const routableComponents = [
6869
ListViewComponent,
6970
ListViewControlComponent,
7071
ListViewAsyncPipeComponent,
72+
ListViewSegmentedBarPageComponent,
7173
ListViewWithNestedTemplateComponent,
7274
ListViewMultipleTemplatesComponent,
7375

@@ -131,6 +133,10 @@ export const routes = [
131133
{ path: "ListViewExamples/commonTemplate", component: ListViewComponent, data: { title: "commonTemplate" } },
132134
{ path: "ListViewExamples/customTemplate", component: ListViewControlComponent, data: { title: "customTemplate" } },
133135
{ path: "listView/asyncPipeTemplate", component: ListViewAsyncPipeComponent, data: { title: "asyncPipeTemplate" } },
136+
{
137+
path: "ListViewExamples/segmentedBarTemplate",
138+
component: ListViewSegmentedBarPageComponent,
139+
data: { title: "segmentedBarTemplate" } },
134140
{
135141
path: "listView/nestedTemplate",
136142
component: ListViewWithNestedTemplateComponent,

‎e2e/tests-app-ng/app/list-view/list-view-main-page.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Component } from "@angular/core";
77
<Button text="ListView" [nsRouterLink]="'commonTemplate'"></Button>
88
<Button text="ListViewCustomTemplate" [nsRouterLink]="'customTemplate'"></Button>
99
<Button text="ListViewAsyncPipe" [nsRouterLink]="['/listView','asyncPipeTemplate']"></Button>
10+
<Button text="ListViewSegmentedBarTemplate" [nsRouterLink]="'segmentedBarTemplate'"></Button>
1011
<Button text="NestedTemplate" [nsRouterLink]="['/listView','nestedTemplate']"></Button>
1112
<Button text="MultipleTemplates" [nsRouterLink]="['/listView','multiple-templates']"></Button>
1213
</StackLayout>
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { Component, ViewChild, ElementRef, OnInit } from "@angular/core";
2+
import { SegmentedBarItem, SegmentedBar } from "tns-core-modules/ui/segmented-bar/segmented-bar";
3+
import { ListView } from "tns-core-modules/ui/list-view/list-view";
4+
import { EventData } from "tns-core-modules/ui/page/page";
5+
6+
interface DataItem {
7+
id: number;
8+
name: string;
9+
type: string;
10+
}
11+
12+
@Component({
13+
moduleId: module.id,
14+
selector: "segmented-bar-list-test",
15+
template: `
16+
<GridLayout automationText="mainView" iosOverflowSafeArea="false" style="height: 100%;">
17+
<ListView
18+
#listViewTest
19+
[itemTemplateSelector]="templateSelector"
20+
[items]="displayedItems"
21+
>
22+
<ng-template let-item="item">
23+
<label [text]="'Unsupported Element ' + item.type" color="red"></label>
24+
</ng-template>
25+
26+
<ng-template nsTemplateKey="segmentedBarTemplate" let-item="item">
27+
<SegmentedBar
28+
[items]="segmentedBarItems"
29+
(selectedIndexChange)="onSegmentedBarPress($event)"
30+
></SegmentedBar>
31+
</ng-template>
32+
33+
<ng-template nsTemplateKey="dataItemTemplate" let-item="item">
34+
<StackLayout>
35+
<Label [text]="'Item ID: ' + item.id" height="50"></Label>
36+
<Label [text]="item.name" height="50"></Label>
37+
</StackLayout>
38+
</ng-template>
39+
40+
<ng-template nsTemplateKey="buttonTemplate" let-item="item">
41+
<button text="Pushing me shouldn't crash!" (tap)="onButtonPress()"></button>
42+
</ng-template>
43+
</ListView>
44+
</GridLayout>
45+
`,
46+
})
47+
export class ListViewSegmentedBarPageComponent implements OnInit {
48+
public displayedItems: Array<DataItem> = [];
49+
public items: Array<DataItem>;
50+
public segmentedBarItems: SegmentedBarItem[] = this.createSegmentedBarItems();
51+
52+
@ViewChild("listViewTest", { static: false })
53+
private listViewTest?: ElementRef;
54+
55+
constructor() {
56+
this.items = [];
57+
58+
for (let i = 0; i < 20; i++) {
59+
const type = "dataItemTemplate";
60+
61+
this.items.push({
62+
id: i,
63+
name: `data item ${i}`,
64+
type: type,
65+
});
66+
}
67+
}
68+
69+
public ngOnInit() {
70+
this.displayedItems = this.updateItems(true);
71+
}
72+
73+
public onButtonPress() {
74+
// tslint:disable-next-line: no-unused-expression
75+
new Promise((resolve) => {
76+
setTimeout(() => {
77+
if (this.listViewTest) {
78+
console.log("Scrolling to the top of the list...");
79+
const listView = this.listViewTest.nativeElement as ListView;
80+
listView.scrollToIndex(0);
81+
}
82+
resolve();
83+
}, 150);
84+
});
85+
86+
this.displayedItems = this.updateItems(false);
87+
}
88+
89+
public onSegmentedBarPress(args: EventData) {
90+
if (args && args.object) {
91+
const segmentBar = args.object as SegmentedBar;
92+
const selectedOdd = segmentBar.selectedIndex === 0;
93+
this.displayedItems = this.updateItems(selectedOdd);
94+
}
95+
}
96+
97+
public createSegmentedBarItems() {
98+
const itemOdd = new SegmentedBarItem();
99+
itemOdd.title = "Odd Items";
100+
const itemEven = new SegmentedBarItem();
101+
itemEven.title = "Even Items";
102+
return [itemOdd, itemEven];
103+
}
104+
105+
public templateSelector(item: DataItem): string {
106+
return item.type;
107+
}
108+
109+
private updateItems(odd: boolean) {
110+
const items = [
111+
{
112+
id: -1,
113+
name: "Segmented Bar",
114+
type: "segmentedBarTemplate",
115+
},
116+
...(odd
117+
? this.items.filter((item) => item.id % 2 === 1)
118+
: this.items.filter((item) => item.id % 2 === 0)),
119+
{
120+
id: 999,
121+
name: "Refresh test",
122+
type: "buttonTemplate",
123+
},
124+
];
125+
return items;
126+
}
127+
}

‎nativescript-angular/view-util.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,10 @@ export class ViewUtil {
260260
}
261261

262262
private removeLayoutChild(parent: NgLayoutBase, child: NgView): void {
263+
if (isLogEnabled()) {
264+
traceLog(`ViewUtil.removeLayoutChild parent: ${parent} child: ${child}`);
265+
}
266+
263267
const index = parent.getChildIndex(child);
264268

265269
if (index !== -1) {
@@ -371,6 +375,12 @@ export class ViewUtil {
371375

372376
const propMap = this.getProperties(view);
373377
const propertyName = propMap.get(attributeName);
378+
379+
// Ensure the children of a collection currently have no parent set.
380+
if (Array.isArray(value)) {
381+
this.removeParentReferencesFromItems(value);
382+
}
383+
374384
if (propertyName) {
375385
// We have a lower-upper case mapped property.
376386
view[propertyName] = value;
@@ -381,6 +391,18 @@ export class ViewUtil {
381391
view[attributeName] = value;
382392
}
383393

394+
private removeParentReferencesFromItems(items: any[]): void {
395+
for (const item of items) {
396+
if (item.parent && item.parentNode) {
397+
if (isLogEnabled()) {
398+
traceLog(`Unassigning parent ${item.parentNode} on value: ${item}`);
399+
}
400+
item.parent = undefined;
401+
item.parentNode = undefined;
402+
}
403+
}
404+
}
405+
384406
private getProperties(instance: any): Map<string, string> {
385407
const type = instance && instance.constructor;
386408
if (!type) {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /