Milan Milanovic
Milan Milanovic

Reputation: 433

angular2 firebase realtime updating not working

I have simple app that inserts new record to Firebase and below the input field it simply lists last 10 items in database.

PROBLEM:

  1. I need to start inputing someting to input field or to click on "update" for data from Firebase to appear in my listing. It seems that data comes in after the processing by angular has been already done, causing it now to show the list initialy. I tried adding "| async" to ngFor, but does not work and causes errors in console. Everything is working good, just need to load and show the data onload, without me inputing a keystroke in input or clicking to update button.
  2. when I open two tabs with same app, they do not update realtime as I supposed they would once I start inputing data zig-zag from one tab to another, I only appears in the tab in which I inserted the data.

import {Component,enableProdMode} from 'angular2/core'; enableProdMode();
import {FirebaseService} from 'firebase-angular2/core';
var myFirebaseRef = new Firebase("https://xxx.firebaseio.com/messages");

@Component({
    selector: 'my-app',
    template: `
        <input type=text [(ngModel)]="newmsg" #newmsgref (keyup.enter)="updateHello(newmsgref)">
        <button (click)="updateHello(newmsgref)">Update</button>
        <ul>
            <li *ngFor="#item of items">
              {{item}}
            </li>
        </ul>
    `
})
export class AppComponent {
    newmsg:string;
    items:Array<string>=[];

    constructor() {
        myFirebaseRef.limitToLast(10).on('child_added', (childSnapshot, prevChildKey) => {
            childSnapshot.forEach((records) => {
              this.items.push(records.val());
            });
        });
    }

    updateHello(r){
        myFirebaseRef.push({
            title: this.newmsg
        });
        this.newmsg="";
        r.focus();
    }
}

SOLUTION #1 WITH NGZONE MANUAL UPDATE WHICH WORKED (thanks to: Günter Zöchbauer) Since the definition was outside the A2, the use of NgZone is really easy and corrected the problem. Thanks Günter ;)

import {Component,enableProdMode,NgZone} from 'angular2/core'; enableProdMode();
import {FirebaseService} from 'firebase-angular2/core';
var myFirebaseRef = new Firebase("https://xxx.firebaseio.com/messages");

@Component({
    selector: 'my-app',
    template: `
        <input type=text [(ngModel)]="newmsg" #newmsgref (keyup.enter)="updateHello(newmsgref)">
        <button (click)="updateHello(newmsgref)">Update</button>
        <ul>
            <li *ngFor="#item of items">
              {{item}}
            </li>
        </ul> 
    `
})
export class AppComponent {
    newmsg:string;
    items:Array<string>=[];

    constructor(private zone: NgZone) {
        myFirebaseRef.limitToLast(10).on('child_added', (childSnapshot, prevChildKey) => {
            zone.run(() => {
                childSnapshot.forEach((records) => {
                    this.items.push(records.val());
                });
            });
        });
    }

    updateHello(r){
        myFirebaseRef.push({
            title: this.newmsg
        });
        this.newmsg="";
        r.focus();
    }
}

SOLUTION #2 AUTOMATIC A2 UPDATING WHICH WORKED (thanks to: Thierry) I simply put the definition inside the class of angular2, not outside, and everything started working as I assumed initialy. Thank you Thierry for the insight ;).

import {Component,enableProdMode} from 'angular2/core'; enableProdMode();
import {FirebaseService} from 'firebase-angular2/core';

@Component({
    selector: 'my-app',
    template: `
        <input type=text [(ngModel)]="newmsg" #newmsgref (keyup.enter)="updateHello(newmsgref)">
        <button (click)="updateHello(newmsgref)">Update</button>
        <ul>
            <li *ngFor="#item of items">
              {{item}}
            </li>
        </ul>
    `
})
export class AppComponent {
    newmsg:string;
    items:Array<string>=[];
    myFirebaseRef = new Firebase("https://xxx.firebaseio.com/messages");

    constructor() {
        this.myFirebaseRef.limitToLast(10).on('child_added', (childSnapshot, prevChildKey) => {
            childSnapshot.forEach((records) => {
                this.items.push(records.val());
            });
        });
    }

    updateHello(r){
        this.myFirebaseRef.push({
            title: this.newmsg
        });
        this.newmsg="";
        r.focus();
    }
}

Upvotes: 5

Views: 2848

Answers (2)

Thierry Templier
Thierry Templier

Reputation: 202336

Günter exactly points the problem out ;-) In fact the myFirebaseRef is created outside Angular2 processing.

If you're interested in a custom pipe for Firebase you could have a look at the source for the Sarah Robinson's talk at Angular Connect 2015:

Hope it helps you, Thierry

Upvotes: 5

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 658225

constructor(private zone: NgZone)

...
zone.run(() => {
  childSnapshot.forEach((records) => {
    this.items.push(records.val());
  });
});
...

See also Triggering Angular2 change detection manually

Upvotes: 5

Related Questions