代码之家  ›  专栏  ›  技术社区  ›  Guruprasad J Rao

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

  •  0
  • Guruprasad J Rao  · 技术社区  · 7 年前

    我正在将一组简单的数据加载到 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);
      });
    }
    

    我的UI看起来像

    <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');
    }
    
    1 回复  |  直到 7 年前
        1
  •  3
  •   Yanis-git    7 年前

    你需要 Observable 自我管理,专注于 task list lifecycle

    随附示例 BehaviorSuject TaskService .对于本例,我只是在1秒后填充虚拟数据,而不是从ajax请求加载。

    然后,您有更新/删除操作,这两个操作都必须根据用户所做的操作更新列表。

    组成部分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上,我们希望从服务器加载,然后如果复选框正在更改,我们希望更新引用,当我们单击delete按钮时,我们希望从列表中删除(也可能在服务器上)。

    组成部分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>
    

    现在主代码已打开 任务服务 :

    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