2016-12-20 10 views
1

Ich versuche, einfache Nachrichten asynchron in einer ListView anzuzeigen. Die Nachrichten werden von Firebase über the de-facto standard NativeScript Plugin abgerufen. Ich denke nicht, dass irgendetwas mit meiner Plugin-Interaktion falsch ist, da ich in der Lage bin, die Nachrichten zu initialisieren, einzuloggen und sogar zu empfangen. Ich kann sie einfach nicht in einem ListView anzeigen lassen.Anzeigen von Nachrichten aus Firebase asynchron in NativeScript ListView

Ich habe es geschafft, den Event-Callback von der Firebase-Nachricht abzubilden, indem ich durch Erstellen eines EventEmitter auf eine Observable drängte. Ich bin mir nicht sicher, ob dies der richtige Weg ist, aber es hat die besten Ergebnisse gezeigt, da ich sehen kann, dass die Nachrichten durch mein Observable geschoben werden.

Hier ist, was ich tue:

import { Component, OnInit, EventEmitter } from "@angular/core"; 
import { Observable } from "rxjs/Observable"; 
import * as firebase from "nativescript-plugin-firebase"; 
import { Message } from "./shared/message.model"; 
@Component({ 
    selector: "my-app", 
    templateUrl: "app.component.html" 
}) 
export class AppComponent implements OnInit { 
    public messages: Observable<Array<Message>>; 

    ngOnInit() { 
     this.init() 
      .then(() => this.login()) 
      .then(() => this.getMessages()); 
    } 

    // ... implementations for init() and login(), also post()-method 

    getMessages =() => { 
     let msgs = []; 
     // initialize with asynchronous behaviour 
     let emitter = new EventEmitter(true); 
     this.messages = emitter; 
     // shows messages getting added to array 
     this.messages.subscribe((a) => console.log(JSON.stringify(a))); 

     firebase.addChildEventListener((result) => { 
      msgs.push(new Message(result.value.text, result.value.timestamp)); 
      emitter.next(msgs); 
     }, "/messages"); 
    } 
} 

Und dies ist die Ansicht:

<GridLayout rows="auto, *"> 
    <GridLayout row="0" columns="*, auto"> 
     <TextField #textInput hint="Type message..." col="0"></TextField> 
     <Button text="Post" (tap)="post(textInput)" col="1"></Button> 
    </GridLayout> 

    <ListView row="1" [items]="messages | async"> 
     <template let-item="msg"> 
      <StackLayout> 
       <Label text="a message"></Label> <!-- displays after button click --> 
       <Label [text]="msg.text"></Label> <!-- results in exception when there even are items --> 
      </StackLayout> 
     </template> 
    </ListView> 
</GridLayout> 

ich, dass das Abonnement so weit sehen arbeitet wie jede Array-Variante angemeldet wird schrittweise, aber meine Ansicht zeigt sie nicht an. Ich habe verschiedene Modi für die ChangeDetectionStrategie versucht, die keinen Unterschied zu machen schien.

Ich fand heraus, dass wenn ich einen Knopf in meiner Ansicht habe, der eine Komponentenfunktion aufruft, kann ich die Elemente sehen, nachdem ich darauf geklickt habe. Doch wenn es Bindungen an das let-Variable in meiner Ansicht wie [text]="msg.text" stürzt die Anwendung mit dem folgenden Fehler:

An uncaught Exception occurred on "main" thread. 
com.tns.NativeScriptException: 
Calling js method getView failed 
[object Object] 
File: "/data/data/org.nativescript.firebasetest/files/app/tns_modules/@angular/core/bundles/core.umd.js, line: 9464, column: 20 
StackTrace: 
Frame: function:'ListViewComponent.detectChangesOnChild', file:'/data/data/org.nativescript.firebasetest/files/app/tns_modules/nativescript-angular/directives/list-view-comp.js', line: 134, column: 29 
Frame: function:'ListViewComponent.onItemLoading', file:'/data/data/org.nativescript.firebasetest/files/app/tns_modules/nativescript-angular/directives/list-view-comp.js', line: 114, column: 14 
Frame: function:'Observable.notify', file:'/data/data/org.nativescript.firebasetest/files/app/tns_modules/data/observable/observable.js', line: 146, column: 32 
Frame: function:'ListViewAdapter.getView', file:'/data/data/org.nativescript.firebasetest/files/app/tns_modules/ui/list-view/list-view.js', line: 199, column: 28 
// ... native stacktrace 

Was mache ich falsch? Warum muss es so schwierig sein, eine Async-Liste in NativeScript zu implementieren, wenn es in Angular wohl einfach ist? Die Dokumentation ist ein bisschen hier schwach ..

Antwort

2

Ihre Feuerbasis-Stecker außerhalb der Winkelzone laufen, vielleicht Ihren nächsten Anruf in einem ngZone.run Einwickeln helfen:

import { Component, OnInit, EventEmitter, NgZone } from "@angular/core"; 
import { Observable } from "rxjs/Observable"; 
import * as firebase from "nativescript-plugin-firebase"; 
import { Message } from "./shared/message.model"; 
@Component({ 
    selector: "my-app", 
    templateUrl: "app.component.html" 
}) 
export class AppComponent implements OnInit { 
    public messages: Observable<Array<Message>>; 

    constructor(private ngZone: NgZone) {} 

    ngOnInit() { 
     this.init() 
      .then(() => this.login()) 
      .then(() => this.getMessages()); 
    } 

    // ... implementations for init() and login(), also post()-method 

    getMessages =() => { 
     let msgs = []; 
     // initialize with asynchronous behaviour 
     let emitter = new EventEmitter(true); 
     this.messages = emitter; 
     // shows messages getting added to array 
     this.messages.subscribe((a) => console.log(JSON.stringify(a))); 

     firebase.addChildEventListener((result) => { 
      this.ngZone.run(() => { 
       msgs.push(new Message(result.value.text, result.value.timestamp)); 
       emitter.next(msgs); 
      }); 
     }, "/messages"); 
    } 
} 

dies helfen könnte auch: https://github.com/NathanWalker/angular-seed-advanced/wiki/How-to-integrate-Firebase-across-all-platforms-(web-nativescript-desktop)

+0

Danke, das hat mir sehr geholfen. Meine Ansicht listet nun die Nachrichten auf, aber ich kann immer noch nicht an Eigenschaften einer Nachricht in meiner Vorlage binden, ohne die frühere "getView failed" -Ausnahme zu erhalten. Irgendwelche Ideen dazu? – nilo

+0

Behoben, dass es wie Nick Iliev vorgeschlagen – nilo

3

Abgesehen von dem mit ngZone verbundenen Problem gibt es auch einen Syntaxfehler in der Elementvorlage. Ändern Sie diese <template let-item="msg"> zu

<template let-msg="item"> 

Siehe this thread für weitere Einzelheiten.

+1

Sie sind richtig, ich habe es funktioniert, indem ich es "Element" in einem Schritt nennen, aber ich habe nicht ganz verstanden, was ich getan habe, um es zu beheben. Vielen Dank für Ihre Hilfe, leider kann ich nur eine Antwort als richtig akzeptieren. – nilo

Verwandte Themen