我将简单的数据集加载到observable
中,如下所示:
public tasks: Observable<UserTask[]>;
constructor(private dataService: HttpdataService, private changeDetector: ChangeDetectorRef) { }
ngOnInit() {
this.loadTasks();
}
loadTasks() {
this.tasks = this.dataService.loadTasks(someurl);
}
completeTasks(task: UserTask, url: string) {
this.dataService.finishTasks(url, task.id).then(() => {
this.toastr.success('Task completed successfully!', 'Success');
this.tasks.subscribe(() => {
this.changeDetector.markForCheck();
});
}).catch(err => {
this.toastr.error('The request has errored out!', 'Error');
console.error(err);
});
}
我的用户界面看起来像
<tr *ngFor="let task of tasks | async">
//td data
</tr>
单击按钮将调用 completeTasks()并成功执行但在完成任务操作后,UI永远不会更新。使用ChangeDetectionRef
是我最后的选择。我尝试使用ngZone
运行该操作,但无法成功。
当我写入this.tasks.subscribe()
和console.log
数据时,我发现该任务已从Observable中删除,但是不是UI更新。我还能尝试什么。有人可以指出我正确的方向。
更新
这是dataservice
中的方法:
loadTasks(ep: string): Observable<any> {
return this.http.get(ep + '/usertask');
}
答案 0 :(得分:3)
您需要Observable
自我管理并专注于task list lifecycle
。
BehaviorSuject
和TaskService
的附加示例。对于此示例,而是从ajax请求加载,我只在1秒后填充虚拟数据。
然后你有更新/删除动作,他们都必须根据用户的动作更新列表。
Component.ts:
import {
Component, OnInit
} from '@angular/core';
import {TaskModel, TaskService} from './services/task.service';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
constructor(public taskService: TaskService) { }
ngOnInit() {
this.taskService.fetchTask();
}
onChangeHandler(task: TaskModel)
{
this.taskService.save(task);
}
onDeleteHandler(task: TaskModel) {
this.taskService.remove(task);
}
}
这里我们只是根据动作(或生命周期钩子)管理视图和询问服务。在init上我们想从服务器加载,如果复选框正在改变,我们想要更新我们的引用,当我们点击删除按钮时,我们想要从列表中删除(也可以在服务器上)。
<强> component.html 强>
<h2>TODO LIST</h2>
<div *ngFor="let task of (taskService.task$ | async)">
<p>
{{ task.title }} | <input type="checkbox" [(ngModel)]="task.status" (change)="onChangeHandler(task)"> | <button (click)="onDeleteHandler(task)"> Delete </button>
</p>
</div>
现在主要代码在 task.service :
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import {isUndefined} from 'util';
export interface TaskModel {
id: number;
title: string;
status: boolean;
}
@Injectable()
export class TaskService {
/**
* Observable who should always be the replica of last tasks state.
*/
private _tasks$: BehaviorSubject<TaskModel[]>;
/**
* array of task, use for each action done on task.
*/
private tasks: TaskModel[];
constructor() {
// We init by empty array.
this._tasks$ = new BehaviorSubject([]);
this.tasks = [];
}
/**
* Fake fetch data from server.
*/
fetchTask()
{
// Fake request.
Observable.create(obs => {
/**
* After 1 secs, we update internal array and observable.
*/
setTimeout(() => {
this.tasks = this.getDummyData();
obs.next(this.tasks);
}, 1000);
}).subscribe(state => this._tasks$.next(state));
}
/**
* Magic getter
* @return {Observable<{id: number; title: string; status: boolean}[]>}
*/
get task$(): Observable<TaskModel[]> {
// return only observable, don't put public your BehaviorSubject
return this._tasks$.asObservable();
}
/**
* We update from internal array reference, and we next fresh data with our observable.
* @param {TaskModel} task
*/
save(task: TaskModel) {
const index = this.tasks.findIndex(item => item.id === task.id);
if(!isUndefined(this.tasks[index]))
{
this.tasks[index] = task;
}
// Notify rest of application.
this._tasks$.next(this.tasks);
}
/**
* We remove from internal array reference, and we next data with our observable.
* @param {TaskModel} task
*/
remove(task: TaskModel) {
this.tasks = this.tasks.filter(item => item.id !== task.id);
this._tasks$.next(this.tasks);
}
/**
* Fake data.
* @return {{id: number; title: string; status: boolean}[]}
*/
private getDummyData() : TaskModel[]
{
return [
{
id: 1,
title: 'task1',
status: true
},
{
id: 2,
title: 'task2',
status: false
},
{
id: 3,
title: 'task3',
status: true
}
];
}
}