简体   繁体   English

用异步管道可观察到不会更新UI Angular 4

[英]Observable with async pipe doesn't update UI Angular 4

I am having simple set of data loaded into observable as below: 我正在将一组简单的数据加载到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);
  });
}

My UI looks like 我的用户界面看起来像

<tr *ngFor="let task of tasks | async">
   //td data
</tr>

completeTasks() will be called on a button click and executes successfully But the UI is never updated after completing the task operation. 单击按钮将调用completeTasks()并成功执行,但是完成任务操作后,UI永远不会更新。 Using ChangeDetectionRef was my last option to try. 使用ChangeDetectionRef是我尝试的最后一个选择。 I tried to run the operation using ngZone but couldn't succeed. 我尝试使用ngZone运行该操作,但无法成功。

When I write this.tasks.subscribe() and console.log the data, I see that task has been removed from Observable but yea not UI update. 当我编写this.tasks.subscribe()console.log数据时,我看到该任务已从Observable中删除,但不是UI更新。 What else I can try. 我还能尝试什么。 Could someone please point me right direction. 有人可以给我指出正确的方向。

Update 更新

Here's the method within dataservice : 这是dataservice的方法:

loadTasks(ep: string): Observable<any> {
    return this.http.get(ep + '/usertask');
}

you need Observable self managed and dedicated for task list lifecycle . 您需要Observable自我管理并专门用于task list lifecycle

Attached example with BehaviorSuject and TaskService . 附带有BehaviorSujectTaskService For this example, instead to load from ajax request, i just populate dummy data after 1 secs. 对于此示例,不是从ajax请求中加载,而是在1秒后填充伪数据。

Then you have update / delete action who both have to update list according to action done by user. 然后,您将执行更新/删除操作,他们都必须根据用户执行的操作来更新列表。

Component.ts : 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);
    }
}

Here we just manage view and ask service according to action (or lifecycle hook). 在这里,我们只管理视图并根据操作(或生命周期挂钩)请求服务。 On init we want to load from server, then if checkbox is changing, we want to update our reference, when we click on delete button, we want to remove from list (and may on server as well). 在初始化时,我们要从服务器加载,然后如果复选框更改,我们要更新引用,当我们单击删除按钮时,我们要从列表中删除(也可能在服务器上)。

component.html 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>

now main code is on task.service : 现在主要代码在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
            }
        ];
    }
}

Online code 在线代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM