Ionic2 with Real-time data not updating(firebase)

I’ve been using Ionic2 + angular2 and its awesome. Then add firebase on top of that it is even awesomer! However, I’m having one issue. When I update my data in firebase and the app is either running on the device using the IONIC View app or the emulator on my computer - that UI wont update with the newly added data until I do something in the device, like click the hamburger, then the UI will update with the new data on the device. When running the app using Ionic serve, that data updates in my browser as soon as the database updates, so the browser everything seems to be working fine with real-time. I’m wondering what causes this? Do I need to somehow refresh the interface after the .on() method is triggered inside my service? Or is there something unique to the ionic framework to work with real-time databases and updated content on the UI…

Any ideas or help is greatly appreciated!

-S

1 Like

So there could be a few things happening, but its a bit hard to tell.

When running a real device, outside of ionic view, does it update?
Are there any errors in the console?

@mhartington - Thx for the reply. Currently no errors - it does update properly, but you only see the data after you interact with the interface. For example when you update firebase - if you dont touch the app - it wont update the list. However if interact with the UI in anyway, click a button, hit a tab to change views etc, the list automatically populates with the new item added to firebase. It appears to me like the UI doesn’t know new data came in, and then when you do something to the UI - its like oh new data - add to the list. Hopefully that makes sense…

1 Like

Hmm, I’m still having a bit of trouble understanding. Maybe you could try to provide a minimal demo? I have a firebase that I can use for testing to update the data.

Well shoot ha. Let me give you this demo on screen - and if you still need a code demo - Ill need a little time to put it together for you. But thank you for the help in the mean time.
here is a .mov link to dropbox - https://dl.dropboxusercontent.com/u/10729686/Ionic%20ui.mov

Hopefully you can see what is going on now :slight_smile:

From the looks of things, it looks like it’s an async issue.
Could you put together a simple demo. Nothing crazy, but just a small single page app

Sure - whats the best way to hand that off to you? Zip file of just my app you can place in an ionic startup or what?

Could you put together a small git repo

OK got home and put a small demo together - a small explanation of what is going on is in the first page that loads. I also added a screen shot of the database structure to help. Either way if you are able to help fix whats going on or not, any advice on coding will be well received so I would love input on if I’m not doing something correctly as well.

Thanks,
Spencer

You use push, it is your issue. Maybe Ionic Team changed it, but by default Angular 2 watches only the object pointer (performance). So the right code is:

_arr = _arr.concat([obj]);

Whether I use .concat() or I use push() - the emulator and the actual device still does not update the ui in realtime after new data gets added or is removed from the DB. Like if there was a way to refresh the UI after new data has come in via FB - that maybe could work…

Right now from the tests I’ve been doing - it looks like the observables are getting and sending data because I can console.log out the data when the next item gets added or removed from the database but it doesnt look like ionic will refresh the UI when an observable gets a new item.

I tested this against setting up a function that calls HTTP after the observables gets its next item and have the HTTP then get the data from the DB that was just updated and that will refresh the UI lol

Also if you leave the device idle and then do an update to the database - the app seems to timeout and wont receive any realtime data until you press a button to update the ui state

Facing the exact same issue from the past one week!! Even tried using SetTimeout, but couldn’t get it to work.

Ha!! Wokring!! use NgZone. Whatever you want to update like, this.someArray.push(element), put it inside
this.zone.run(()=>{
this.someArray.push(element);
});

but make sure you import {NgZone} from ‘angular2/core’;
and then instantiate your zone via this.zone=new NgZone({enableLongStackTrace: false}); inside your constructor.

you’re welcome!!

Use ngZone is bad practice. Be careful.

2 Likes

I tried NGzone the other day and it kinda worked - it was updating the data on an android - but the ui still didn’t update correctly on iOS. I ended up writing a directive on the element that was getting the new data so when new data comes in I used the event emitter to signal data has changed and run a function to get the new cached data and that worked on both iOS and android to instantly update the ui inside of angulars natural change detection. But that was also still using NGzone , so I need to remove NGzone and test it without and make sure it all still works and updates on each device.

2 Likes

If you don’t mind, could you kindly share the gist of the code? thanks!!

@ yadu4992 - sure I updated the github link above so just check it out.

A few notes to keep in mind:
I did end up needing ngZone to make sure that ios and android would update the view, but I also had to make sure that the digest cycle of angular was doing a full loop on its own to ensure that the app on the actual ios device would update immediately when new data is sent using an observable. I made notes in the code for you to follow.

2 Likes

Hi, I use subscribing for that problem.

Probably there are better solutions but this is what I am using right now. With angular 1 I got used to holding data inside services and in Angular 1 data change in service triggered it in UI. If anybody knows better solution let me know as well.

Inside the provider / service

import {Injectable} from 'angular2/core';
import {Events} from 'ionic-angular';
import {Http} from 'angular2/http';

@Injectable()
export class DataService {
    static get parameters() {
        return [[Http], [Events]];
    }

    constructor(http, events) {
        this.http = http;
        this.events = events;

        this._data = {};

        this.dataRef = new Firebase("https://xxxxx.firebaseio.com/dataref");
    }

    getData() {
        return this.dataRef.on('value', snap => {
            this._data = snap.val();
            this.events.publish('data:valueChanged');
        });
    }
}

and then inside @Page I am listening to data:valueChanged event, also, if leaving page, you should unsubscribe, otherwise it will double the listeners when coming to this page again.

import {Page, NavController, NavParams, Events} from 'ionic-angular';
import {DataService} from '../../providers/tables-service';
import {NgZone} from 'angular2/core';


@Page({
    templateUrl: 'build/pages/data/data.html'
})
export class DataPage {
    static get parameters() {
        return [[NavController], [NavParams], [DataService], [Events], [NgZone]];
    }

    constructor(nav, navParams, dataService, events, ngZone) {
        this.nav = nav;
        this.events = events;
        this.ngZone = ngZone;

        this.dataService = dataService;
        this.listenToDataChangeEvents();
    }

    listenToDataChangeEvents() {
        this.events.subscribe('data:valueChanged', () => {
            console.log("got change");
             this.ngZone.run(() => {
                this.data = this.dataService._data;
             });
        });
    }

    onPageWillEnter() {
        this.data = this.dataService._data;
    }

    onPageDidLeave() {
        return this.events.unsubscribe('data:valueChanged');
    }
}
2 Likes

Hey good call on the remove listeners on page leave I didn’t know about them doubling each page unit but that makes sense. I will try the ionic events library and see how that handles the ui in the iOS device. I’m curious to see how it performs. I’ve found the iOS devices and android are not as forgiving as the browser haha. Thanks for the post @YourPrivateCoder