我经常设法找到我在浏览现有问题时遇到的错误,但在这里,没有任何帮助。
我正在使用一个简单的Ng2模块来尝试列出和更新NeDB商店的内容。
请注意,我对NeDB商店没有任何问题,我已经确认它已正确更新,并且最初正确加载,所以我在其他地方遇到的问题。
我遇到的问题如下:
"异步管道不起作用"。
我有这个模块。
@NgModule({
imports: [CommonModule],
exports: [],
declarations: [WikiComponent],
providers: [WikiDbService],
})
export class WikiModule { }
我有这个组件。
@Component({
selector: 'wiki',
templateUrl: './wiki.component.html'
})
export class WikiComponent implements OnInit {
items: Observable<WikiItem[]>;
constructor(private _db : WikiDbService) { }
ngOnInit() {
this.items = this._db.items;
this.items.subscribe({
next: x => console.log("got value", x),
error: e => console.error("observable error", e),
complete: () => console.log("done")
});
}
}
我有这个模板。
<p>{{items | async | json}}</p>
<ul>
<li *ngFor="let item of (items | async)">{{item.name}}</li>
</ul>
<input #newName (keyup)="0">
<button (click)="_db.addByName(newName.value)">ADD</button>
我有这项服务。
@Injectable()
export class WikiDbService {
private sub: BehaviorSubject<WikiItem[]> = new BehaviorSubject<WikiItem[]>([]);
private db: DataStore;
public items: Observable<WikiItem[]> = this.sub.asObservable();
constructor() {
console.log("BehaviorSubject", this.sub);
console.log("Observable", this.items);
this.db = new DataStore(
{
filename: path.join(app.getAppPath(),"wiki.db"),
autoload: true,
onload:
(err)=>{
if(!err) {
this.db.find<WikiItem>({},
(e,docs) => {
if(!e) {
this.sub.next(docs);
}
})
}
}
});
}
public add(v: WikiItem) {
this.db.insert(
v,
(e, nDoc) =>
{
if(!e) {
this.sub.next([...this.sub.getValue(),nDoc]);
}
}
)
}
public addByName(str:string) {
this.add({name: str, _id: undefined});
}
}
当使用非空的持久性存储路由到我的组件时,我得到以下控制台日志(对应于组件的OnInit方法中的日志记录):
got value > [] (wiki.component.ts:20)
got value > [Object, Object, Object, Object] (wiki.component.ts:20)
但是我的DOM保持不变:
<wiki>
<p>[]</p>
<ul>
<!--template bindings={
"ng-reflect-ng-for-of": ""
}-->
</ul>
<input>
<button>ADD</button>
</wiki>
因此,对我的observable的手动订阅确实有效,并为我提供了价值观。但异步管道无法获得它们。
我在这里做错了什么,或者这是一个错误?
EDITS
12/19/16 3:45 pm
ngFor
指令是&#34; let item of items |异步&#34;之前,我想也许异步管道的范围是项目,而不是我的观察,所以我添加了括号,但结果没有变化。这与此问题无关。
12/20/16 3.06pm
根据@ olsn的建议,使用自动日志初始化组件的items
属性,以检查模板是否订阅了Observable。
确实如此。所以它归结为检测变化,我想。修改标题。
添加以下信息: 我的组件现在是这样的(注释更改)
@Component({
selector: 'wiki',
templateUrl: './wiki.component.html',
changeDetection: ChangeDetectionStrategy.OnPush // <=== I've read this might help. It doesn't.
})
export class WikiComponent implements OnInit {
items: Observable<WikiItem[]> = this._db.items //
.do(x => console.log("got value", x)) // <== new initialization, with a stream
.publishReplay().refCount(); //
constructor(private _db : WikiDbService, private _cd: ChangeDetectorRef) { }
ngOnInit() {
// <=== moved items initialization
}
reload() : void {
this._cd.markForCheck(); // <== added a button to force the change detector to react. Does not do anything.
}
}
在模板中添加此内容:
<button (click)="reload()">REFRESH</button>
@osln给出了正确答案。
问题并不是从根本上考虑订阅或检测更改,这是因为我的sub.next
调用是在外部库中进行的回调,这具体意味着我在Angular区域之外进行调用。 / p>
使用NgZone调用强迫他们回到Angular土地是解决这个问题的方法。
谢谢@osln。
答案 0 :(得分:8)
尝试在 ngInit之前初始化项目对象并将临时日志直接添加到流中,这样您就知道模板是否真正订阅了流,因为您当前的日志是在完全分开的流。
@Component({
selector: 'wiki',
templateUrl: './wiki.component.html'
})
export class WikiComponent implements OnInit {
items: Observable<WikiItem[]> = this._db.items
.do(x => console.log("got value", x)
// if items is not a Behavior- or ReplaySubject or ReplayObservable, also add the following:
.publishReplay()
.refCount();
constructor(private _db : WikiDbService) { }
ngOnInit() {
// ..nothing to do here
}
}
此外,您可能会尝试将数据检索包装在NgZone.run
:
首先在您的DbService中注入此内容:private ngZone: NgZone
(来自@angular/core
),然后使用this.sub.next(docs);
而不是仅使用this.ngZone.run(() => this.sub.next(docs));
。
merge
(也适用于add-call)