@@ -108,88 +108,71 @@ export function FirebaseListFactory (
108
108
* is loaded, the observable starts emitting values.
109
109
*/
110
110
function firebaseListObservable ( ref : firebase . database . Reference | firebase . database . Query , { preserveSnapshot} : FirebaseListFactoryOpts = { } ) : FirebaseListObservable < any > {
111
+
111
112
const toValue = preserveSnapshot ? ( snapshot => snapshot ) : utils . unwrapMapFn ;
112
113
const toKey = preserveSnapshot ? ( value => value . key ) : ( value => value . $key ) ;
113
- // Keep track of callback handles for calling ref.off(event, handle)
114
- const handles = [ ] ;
114
+
115
115
const listObs = new FirebaseListObservable ( ref , ( obs : Observer < any [ ] > ) => {
116
- ref . once ( 'value' )
117
- . then ( ( snap ) => {
118
- let initialArray = [ ] ;
119
- snap . forEach ( child => {
120
- initialArray . push ( toValue ( child ) )
121
- } ) ;
122
- return initialArray ;
123
- } )
124
- . then ( ( initialArray ) => {
125
- const isInitiallyEmpty = initialArray . length === 0 ;
126
- let hasInitialLoad = false ;
127
- let lastKey ;
128
-
129
- if ( ! isInitiallyEmpty ) {
130
- // The last key in the initial array tells us where
131
- // to begin listening in realtime
132
- lastKey = toKey ( initialArray [ initialArray . length - 1 ] ) ;
133
- }
134
116
135
- const addFn = ref . on ( 'child_added' , ( child : any , prevKey : string ) => {
136
- // If the initial load has not been set and the current key is
137
- // the last key of the initialArray, we know we have hit the
138
- // initial load
139
- if ( ! isInitiallyEmpty && ! hasInitialLoad ) {
140
- if ( child . key === lastKey ) {
141
- hasInitialLoad = true ;
142
- obs . next ( initialArray ) ;
143
- return ;
144
- }
145
- }
146
-
147
- if ( hasInitialLoad ) {
148
- initialArray = onChildAdded ( initialArray , toValue ( child ) , toKey , prevKey ) ;
149
- }
150
-
151
- // only emit the array after the initial load
152
- if ( hasInitialLoad ) {
153
- obs . next ( initialArray ) ;
154
- }
155
- } , err => {
156
- if ( err ) { obs . error ( err ) ; obs . complete ( ) ; }
157
- } ) ;
117
+ // Keep track of callback handles for calling ref.off(event, handle)
118
+ const handles = [ ] ;
119
+ let hasLoaded = false ;
120
+ let lastLoadedKey : string = null ;
121
+ let array = [ ] ;
158
122
159
- handles . push ( { event : 'child_added' , handle : addFn } ) ;
123
+ // The list children are always added to, removed from and changed within
124
+ // the array using the child_added/removed/changed events. The value event
125
+ // is only used to determine when the initial load is complete.
160
126
161
- let remFn = ref . on ( 'child_removed' , ( child : any ) => {
162
- initialArray = onChildRemoved ( initialArray , toValue ( child ) , toKey ) ;
163
- if ( hasInitialLoad ) {
164
- obs . next ( initialArray ) ;
165
- }
166
- } , err => {
167
- if ( err ) { obs . error ( err ) ; obs . complete ( ) ; }
168
- } ) ;
169
- handles . push ( { event : 'child_removed' , handle : remFn } ) ;
170
-
171
- let chgFn = ref . on ( 'child_changed' , ( child : any , prevKey : string ) => {
172
- initialArray = onChildChanged ( initialArray , toValue ( child ) , toKey , prevKey )
173
- if ( hasInitialLoad ) {
174
- // This also manages when the only change is prevKey change
175
- obs . next ( initialArray ) ;
176
- }
177
- } , err => {
178
- if ( err ) { obs . error ( err ) ; obs . complete ( ) ; }
127
+ ref . once ( 'value' , ( snap : any ) => {
128
+ if ( snap . exists ( ) ) {
129
+ snap . forEach ( ( child : any ) => {
130
+ lastLoadedKey = child . key ;
179
131
} ) ;
180
- handles . push ( { event : 'child_changed' , handle : chgFn } ) ;
181
-
182
- // If empty emit the array
183
- if ( isInitiallyEmpty ) {
184
- obs . next ( initialArray ) ;
185
- hasInitialLoad = true ;
132
+ if ( array . find ( ( child : any ) => toKey ( child ) === lastLoadedKey ) ) {
133
+ hasLoaded = true ;
134
+ obs . next ( array ) ;
186
135
}
187
- } , err => {
188
- if ( err ) {
189
- obs . error ( err ) ;
190
- obs . complete ( ) ;
191
- }
192
- } ) ;
136
+ } else {
137
+ hasLoaded = true ;
138
+ obs . next ( array ) ;
139
+ }
140
+ } , err => {
141
+ if ( err ) { obs . error ( err ) ; obs . complete ( ) ; }
142
+ } ) ;
143
+
144
+ const addFn = ref . on ( 'child_added' , ( child : any , prevKey : string ) => {
145
+ array = onChildAdded ( array , toValue ( child ) , toKey , prevKey ) ;
146
+ if ( hasLoaded ) {
147
+ obs . next ( array ) ;
148
+ } else if ( child . key === lastLoadedKey ) {
149
+ hasLoaded = true ;
150
+ obs . next ( array ) ;
151
+ }
152
+ } , err => {
153
+ if ( err ) { obs . error ( err ) ; obs . complete ( ) ; }
154
+ } ) ;
155
+ handles . push ( { event : 'child_added' , handle : addFn } ) ;
156
+
157
+ let remFn = ref . on ( 'child_removed' , ( child : any ) => {
158
+ array = onChildRemoved ( array , toValue ( child ) , toKey ) ;
159
+ if ( hasLoaded ) {
160
+ obs . next ( array ) ;
161
+ }
162
+ } , err => {
163
+ if ( err ) { obs . error ( err ) ; obs . complete ( ) ; }
164
+ } ) ;
165
+ handles . push ( { event : 'child_removed' , handle : remFn } ) ;
166
+
167
+ let chgFn = ref . on ( 'child_changed' , ( child : any , prevKey : string ) => {
168
+ array = onChildChanged ( array , toValue ( child ) , toKey , prevKey ) ;
169
+ if ( hasLoaded ) {
170
+ obs . next ( array ) ;
171
+ }
172
+ } , err => {
173
+ if ( err ) { obs . error ( err ) ; obs . complete ( ) ; }
174
+ } ) ;
175
+ handles . push ( { event : 'child_changed' , handle : chgFn } ) ;
193
176
194
177
return ( ) => {
195
178
// Loop through callback handles and dispose of each event with handle
0 commit comments