@@ -108,88 +108,71 @@ export function FirebaseListFactory (
108108 * is loaded, the observable starts emitting values.
109109 */
110110function firebaseListObservable ( ref : firebase . database . Reference | firebase . database . Query , { preserveSnapshot} : FirebaseListFactoryOpts = { } ) : FirebaseListObservable < any > {
111+
111112 const toValue = preserveSnapshot ? ( snapshot => snapshot ) : utils . unwrapMapFn ;
112113 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+
115115 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- }
134116
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 = [ ] ;
158122
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.
160126
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 ;
179131 } ) ;
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 ) ;
186135 }
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 } ) ;
193176
194177 return ( ) => {
195178 // Loop through callback handles and dispose of each event with handle
0 commit comments