1
1
import {
2
- Component ,
3
- DoCheck ,
4
- ElementRef ,
2
+ Component ,
3
+ DoCheck ,
4
+ OnDestroy ,
5
+ ElementRef ,
5
6
ViewContainerRef ,
6
- TemplateRef ,
7
- ContentChild ,
7
+ TemplateRef ,
8
+ ContentChild ,
8
9
EmbeddedViewRef ,
9
- HostListener ,
10
- IterableDiffers ,
10
+ IterableDiffers ,
11
11
IterableDiffer ,
12
12
ChangeDetectorRef ,
13
13
EventEmitter ,
14
14
ViewChild ,
15
15
Output ,
16
- ChangeDetectionStrategy } from '@angular/core' ;
16
+ ChangeDetectionStrategy } from '@angular/core' ;
17
17
import { isBlank } from '@angular/core/src/facade/lang' ;
18
18
import { isListLikeIterable } from '@angular/core/src/facade/collection' ;
19
- import { Observable as RxObservable } from 'rxjs'
20
19
import { ListView } from 'ui/list-view' ;
21
20
import { View } from 'ui/core/view' ;
22
- import { NgView } from '../view-util' ;
23
21
import { ObservableArray } from 'data/observable-array' ;
24
22
import { LayoutBase } from 'ui/layouts/layout-base' ;
25
- import { rendererLog , rendererError } from "../trace" ;
23
+ import { listViewLog } from "../trace" ;
24
+
26
25
const NG_VIEW = "_ngViewRef" ;
27
26
28
27
export class ListItemContext {
@@ -51,15 +50,15 @@ export interface SetupItemViewArgs {
51
50
inputs : [ 'items' ] ,
52
51
changeDetection : ChangeDetectionStrategy . OnPush
53
52
} )
54
- export class ListViewComponent {
53
+ export class ListViewComponent implements DoCheck , OnDestroy {
55
54
public get nativeElement ( ) : ListView {
56
55
return this . listView ;
57
56
}
58
-
57
+
59
58
private listView : ListView ;
60
59
private _items : any ;
61
60
private _differ : IterableDiffer ;
62
-
61
+
63
62
@ViewChild ( 'loader' , { read : ViewContainerRef } ) loader : ViewContainerRef ;
64
63
65
64
@Output ( ) public setupItemView : EventEmitter < SetupItemViewArgs > = new EventEmitter < SetupItemViewArgs > ( ) ;
@@ -73,21 +72,24 @@ export class ListViewComponent {
73
72
needDiffer = false ;
74
73
}
75
74
if ( needDiffer && ! this . _differ && isListLikeIterable ( value ) ) {
76
- this . _differ = this . _iterableDiffers . find ( this . _items ) . create ( this . _cdr , ( index , item ) => { return item ; } ) ;
75
+ this . _differ = this . _iterableDiffers . find ( this . _items ) . create ( this . _cdr , ( index , item ) => { return item ; } ) ;
77
76
}
77
+
78
78
this . listView . items = this . _items ;
79
79
}
80
80
81
- private timerId : number ;
82
- private doCheckDelay = 5 ;
83
-
84
81
constructor ( private _elementRef : ElementRef ,
85
- private _iterableDiffers : IterableDiffers ,
86
- private _cdr : ChangeDetectorRef ) {
82
+ private _iterableDiffers : IterableDiffers ,
83
+ private _cdr : ChangeDetectorRef ) {
87
84
this . listView = _elementRef . nativeElement ;
85
+
86
+ this . listView . on ( "itemLoading" , this . onItemLoading , this ) ;
87
+ }
88
+
89
+ ngOnDestroy ( ) {
90
+ this . listView . off ( "itemLoading" , this . onItemLoading , this ) ;
88
91
}
89
92
90
- @HostListener ( "itemLoading" , [ '$event' ] )
91
93
public onItemLoading ( args ) {
92
94
if ( ! this . itemTemplate ) {
93
95
return ;
@@ -99,20 +101,22 @@ export class ListViewComponent {
99
101
let viewRef : EmbeddedViewRef < ListItemContext > ;
100
102
101
103
if ( args . view ) {
102
- rendererLog ( "ListView. onItemLoading: " + index + " - Reusing existing view" ) ;
104
+ listViewLog ( " onItemLoading: " + index + " - Reusing existing view" ) ;
103
105
viewRef = args . view [ NG_VIEW ] ;
104
106
// getting angular view from original element (in cases when ProxyViewContainer is used NativeScript internally wraps it in a StackLayout)
105
107
if ( ! viewRef ) {
106
108
viewRef = ( args . view . _subViews && args . view . _subViews . length > 0 ) ? args . view . _subViews [ 0 ] [ NG_VIEW ] : undefined ;
107
109
}
108
110
}
109
111
else {
110
- rendererLog ( "ListView. onItemLoading: " + index + " - Creating view from template" ) ;
112
+ listViewLog ( " onItemLoading: " + index + " - Creating view from template" ) ;
111
113
viewRef = this . loader . createEmbeddedView ( this . itemTemplate , new ListItemContext ( ) , 0 ) ;
112
114
args . view = getSingleViewFromViewRef ( viewRef ) ;
113
115
args . view [ NG_VIEW ] = viewRef ;
114
116
}
115
117
this . setupViewRef ( viewRef , currentItem , index ) ;
118
+
119
+ this . detectChangesOnChild ( viewRef , index ) ;
116
120
}
117
121
118
122
public setupViewRef ( viewRef : EmbeddedViewRef < ListItemContext > , data : any , index : number ) : void {
@@ -126,49 +130,61 @@ export class ListViewComponent {
126
130
context . even = ( index % 2 == 0 ) ;
127
131
context . odd = ! context . even ;
128
132
129
- this . setupItemView . next ( { view : viewRef , data : data , index : index , context : context } ) ;
133
+ this . setupItemView . next ( { view : viewRef , data : data , index : index , context : context } ) ;
130
134
}
131
135
132
- ngDoCheck ( ) {
133
- if ( this . timerId ) {
134
- clearTimeout ( this . timerId ) ;
135
- }
136
+ private detectChangesOnChild ( viewRef : EmbeddedViewRef < ListItemContext > , index : number ) {
137
+ // Manually detect changes in child view ref
138
+ // TODO: Is there a better way of getting viewRef's change detector
139
+ const childChangeDetector = < ChangeDetectorRef > ( < any > viewRef ) ;
136
140
137
- this . timerId = setTimeout ( ( ) => {
138
- clearTimeout ( this . timerId ) ;
139
- if ( this . _differ ) {
140
- var changes = this . _differ . diff ( this . _items ) ;
141
- if ( changes ) {
142
- this . listView . refresh ( ) ;
143
- }
141
+ listViewLog ( "Manually detect changes in child: " + index )
142
+ childChangeDetector . markForCheck ( ) ;
143
+ childChangeDetector . detectChanges ( ) ;
144
+ }
145
+
146
+ ngDoCheck ( ) {
147
+ if ( this . _differ ) {
148
+ listViewLog ( "ngDoCheck() - execute differ" )
149
+ const changes = this . _differ . diff ( this . _items ) ;
150
+ if ( changes ) {
151
+ listViewLog ( "ngDoCheck() - refresh" )
152
+ this . listView . refresh ( ) ;
144
153
}
145
- } , this . doCheckDelay ) ;
154
+ }
146
155
}
147
156
}
148
157
149
- function getSingleViewFromViewRef ( viewRef : EmbeddedViewRef < any > ) : View {
150
- var getSingleViewRecursive = ( nodes : Array < any > , nestLevel : number ) => {
151
- var actualNodes = nodes . filter ( ( n ) => ! ! n && n . nodeName !== "#text" ) ;
152
158
153
- if ( actualNodes . length === 0 ) {
154
- throw new Error ( "No suitable views found in list template! Nesting level: " + nestLevel ) ;
155
- }
156
- else if ( actualNodes . length > 1 ) {
157
- throw new Error ( "More than one view found in list template! Nesting level: " + nestLevel ) ;
159
+ function getSingleViewRecursive ( nodes : Array < any > , nestLevel : number ) {
160
+ const actualNodes = nodes . filter ( ( n ) => ! ! n && n . nodeName !== "#text" ) ;
161
+
162
+ if ( actualNodes . length === 0 ) {
163
+ throw new Error ( "No suitable views found in list template! Nesting level: " + nestLevel ) ;
164
+ }
165
+ else if ( actualNodes . length > 1 ) {
166
+ throw new Error ( "More than one view found in list template! Nesting level: " + nestLevel ) ;
167
+ }
168
+ else {
169
+ if ( actualNodes [ 0 ] ) {
170
+ let parentLayout = actualNodes [ 0 ] . parent ;
171
+ if ( parentLayout instanceof LayoutBase ) {
172
+ parentLayout . removeChild ( actualNodes [ 0 ] ) ;
173
+ }
174
+ return actualNodes [ 0 ] ;
158
175
}
159
176
else {
160
- if ( actualNodes [ 0 ] ) {
161
- let parentLayout = actualNodes [ 0 ] . parent ;
162
- if ( parentLayout instanceof LayoutBase ) {
163
- parentLayout . removeChild ( actualNodes [ 0 ] ) ;
164
- }
165
- return actualNodes [ 0 ] ;
166
- }
167
- else {
168
- return getSingleViewRecursive ( actualNodes [ 0 ] . children , nestLevel + 1 )
169
- }
177
+ return getSingleViewRecursive ( actualNodes [ 0 ] . children , nestLevel + 1 )
170
178
}
171
179
}
180
+ }
172
181
182
+ function getSingleViewFromViewRef ( viewRef : EmbeddedViewRef < any > ) : View {
173
183
return getSingleViewRecursive ( viewRef . rootNodes , 0 ) ;
174
184
}
185
+
186
+ const changeDetectorMode = [ "CheckOnce" , "Checked" , "CheckAlways" , "Detached" , "OnPush" , "Default" ] ;
187
+ const changeDetectorStates = [ "Never" , "CheckedBefore" , "Error" ] ;
188
+ function getChangeDetectorState ( cdr : any ) {
189
+ return "Mode: " + changeDetectorMode [ parseInt ( cdr . cdMode ) ] + " State: " + changeDetectorStates [ parseInt ( cdr . cdState ) ] ;
190
+ }
0 commit comments