在 NativeScript ListView 中异步显示来自 Firebase 的消息
Display messages from Firebase asynchronously in NativeScript ListView
我正在尝试在 ListView 中异步显示简单消息。这些消息是通过 the de-facto standard NativeScript Plugin 从 Firebase 获取的。我认为我的插件交互没有任何问题,因为我能够初始化、登录甚至接收消息。我只是无法让它们显示在 ListView 中。
我设法通过创建 EventEmitter 将事件回调从 Firebase 消息推送映射到可观察对象。我不确定这是否是正确的方法,但它显示了最好的结果,因为我可以看到通过我的 observable 推送的消息。
这是我正在做的事情:
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");
}
}
这是视图:
<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>
我可以看到订阅工作正常,因为每个数组变体都被增量记录,但我的视图没有显示它们。我为 ChangeDetectionStragety 尝试了不同的模式,这似乎没有什么不同。
我发现当我的视图中有一个调用组件函数的按钮时,我可以在单击它后看到元素。但是,如果在我看来存在对 let 变量的绑定,例如 [text]="msg.text"
,则应用程序会崩溃并出现以下错误:
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
我做错了什么?为什么在 Angular 中很容易在 NativeScript 中实现异步列表却如此困难?这里的文档有点薄弱..
您的 firebase 连接器 运行 在 angular 区域之外,也许将您的下一个呼叫包装在 ngZone.run
中有助于:
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");
}
}
除了与 ngZone 相关的问题外,项目模板中还存在语法错误。将此 <template let-item="msg">
更改为
<template let-msg="item">
详情见。
我正在尝试在 ListView 中异步显示简单消息。这些消息是通过 the de-facto standard NativeScript Plugin 从 Firebase 获取的。我认为我的插件交互没有任何问题,因为我能够初始化、登录甚至接收消息。我只是无法让它们显示在 ListView 中。
我设法通过创建 EventEmitter 将事件回调从 Firebase 消息推送映射到可观察对象。我不确定这是否是正确的方法,但它显示了最好的结果,因为我可以看到通过我的 observable 推送的消息。
这是我正在做的事情:
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");
}
}
这是视图:
<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>
我可以看到订阅工作正常,因为每个数组变体都被增量记录,但我的视图没有显示它们。我为 ChangeDetectionStragety 尝试了不同的模式,这似乎没有什么不同。
我发现当我的视图中有一个调用组件函数的按钮时,我可以在单击它后看到元素。但是,如果在我看来存在对 let 变量的绑定,例如 [text]="msg.text"
,则应用程序会崩溃并出现以下错误:
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
我做错了什么?为什么在 Angular 中很容易在 NativeScript 中实现异步列表却如此困难?这里的文档有点薄弱..
您的 firebase 连接器 运行 在 angular 区域之外,也许将您的下一个呼叫包装在 ngZone.run
中有助于:
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");
}
}
除了与 ngZone 相关的问题外,项目模板中还存在语法错误。将此 <template let-item="msg">
更改为
<template let-msg="item">
详情见