角度删除全部完成不刷新不起作用

时间:2018-11-25 19:28:59

标签: javascript angular typescript rxjs observable

我是不熟悉Angular并创建一个CRUD todos应用程序的,该应用程序将todos存储到localStorage中。 添加,更新,删除,使所有工作正常进行,但是如果我删除所有已完成的待办事项,则仅在刷新时有效,这意味着单击它会从localStorage中删除,但不会从屏幕上删除

这是我的项目文件

app.component.html

<div class="container">
  <div class="todo-wrapper">
    <app-todo-input></app-todo-input>
    <div *ngFor="let todo of allTodos">
        <app-todo-item [todo]="todo"></app-todo-item>
    </div>
    <app-todo-footer [style.display]="allTodos.length <= 0 ? 'none': 'inline'"></app-todo-footer>
  </div>
</div>

app.component.ts

import { Component } from '@angular/core';
import { TodoService } from './todo.service';
import { StorageService } from './storage.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
    public allTodos = [];
    constructor(private todoService: TodoService, private storageService: StorageService){
    };

    ngOnInit(){
        this.todoService.getTodos().subscribe(todos => this.allTodos = todos);
        // this.storageService.getTodos().subscribe(todos => this.allTodos = todos);
    }
}

todo.ts

export class Todo {
    id: number;
    text: string;
    completed: boolean;

    constructor(id: number, text: string, completed: boolean){
        this.id = id;
        this.text = text;
        this.completed = completed;
    }
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {MatButtonModule, MatCheckboxModule} from '@angular/material';

import { AppComponent } from './app.component';
import { TodoInputComponent } from './todo-input/todo-input.component';
import { TodoService } from './todo.service';
import { StorageService } from './storage.service';
import { TodoItemComponent } from './todo-item/todo-item.component';
import { TodoFooterComponent } from './todo-footer/todo-footer.component';
import { AppRoutingModule } from './app-routing.module';

@NgModule({
  declarations: [
    AppComponent,
    TodoInputComponent,
    TodoItemComponent,
    TodoFooterComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    BrowserAnimationsModule,
    MatButtonModule,
    MatCheckboxModule,
    AppRoutingModule
  ],
  providers: [
    TodoService,
    StorageService
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

storage.service.ts

import { Injectable } from '@angular/core';
import { Todo } from './todo';
import { Observable, of, BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class StorageService {

  constructor() { }

  public setTodos(todos: Todo[]): void {
    localStorage.setItem('todos', JSON.stringify({ todos: todos }))
  }

  public getTodos(): Observable<Todo[]>{
    let localStorageItem = JSON.parse(localStorage.getItem('todos'));
    if(localStorageItem == null){
        return of([]);
    }else{
        return of(localStorageItem.todos);
    }
  }
}

todo.service.ts

import { Injectable, Input } from '@angular/core';
import { StorageService } from './storage.service';
import { Observable, of, BehaviorSubject } from 'rxjs';

import { Todo } from './todo';

@Injectable({
  providedIn: 'root'
})
export class TodoService {

  @Input()
  private todo: Todo;

    public allTodos: Todo[] = [];
    private nextId: number; 

  constructor(private storageService: StorageService) {
    this.loadTodos();
  }  

  public addTodo(text: string) : void{
    let todos = this.allTodos;
    if (todos.length == 0) { 
      this.nextId = 0;
    } else {
      let maxId = todos[todos.length - 1].id;
      this.nextId = maxId + 1;
    }
    let todo = new Todo(this.nextId, text, false);
    todos.push(todo);
    this.storageService.setTodos(todos);
    this.nextId++;
    // this.lengthTodos();
  }

  // public getTodos() {
  //    return this.allTodos;
  // }

  public loadTodos (){
    return this.storageService.getTodos().subscribe(todos => this.allTodos = todos);
  }

  public getTodos(): Observable<Todo[]>{
    return of(this.allTodos)
  }

  public removeTodo(selectedTodo): void{
    let todos = this.allTodos;
    todos.splice(todos.findIndex((todo) => todo.id == selectedTodo), 1);
    this.storageService.setTodos(todos);
  }

  public deleteCompleted(){
    let todos = this.allTodos;
    let completedTodos = todos.filter(todo => todo.completed !== true);
    todos = completedTodos;
    this.storageService.setTodos(todos);
  }

  public update(id, newValue){
    let todos = this.allTodos;
    let todoToUpdate = todos.find((todo) => todo.id == id);
    todoToUpdate.text = newValue;
    this.storageService.setTodos(todos);
  } 

  public isCompleted(id: number, completed: boolean){
    let todos = this.allTodos;
    let todoToComplete = todos.find((todo) => todo.id == id);
    todoToComplete.completed = !todoToComplete.completed;
    this.storageService.setTodos(todos);
  }

  // public lengthTodos(){
  //   let todos = this.storageService.getTodos();
  //   let activeTodos = todos.filter((todo) => !todo.completed).length;
  //   return activeTodos;
  // }
}

todo-footer.component.ts

    import { Component, OnInit, Input } from '@angular/core';
    import { TodoService } from '../todo.service';
    import { Todo } from '../todo';

    @Component({
      selector: 'app-todo-footer',
      templateUrl: './todo-footer.component.html',
      styleUrls: ['./todo-footer.component.css']
    })
    export cl

ass TodoFooterComponent implements OnInit {

  public allTodos;

    private activeTasks : number = 0;

  constructor(private todoService: TodoService) {
    this.todoService.getTodos().subscribe(todos => this.allTodos = todos);
  }

  public getLength(){
    // this.activeTasks = this.todoService.lengthTodos();
  }

  private clearCompleted(){
    this.todoService.deleteCompleted(); 
  }

  ngOnInit() {
    // this.getLength();
  }

}

todo-footer.component.html

<footer class="footer">

    <button class="clear-completed" (click)="clearCompleted()">Clear completed</button> 
</footer>

在todo.service中,deleteCompleted方法不起作用,该方法由todo-footer.component用于删除所有已完成的待办事项== true。

1 个答案:

答案 0 :(得分:2)

您在这里有一个Observable,但实际上并没有使用它。相反,您将数组的单个实例包含在多个组件中,并依赖于该实例被修改,但是filter不会修改内存中的实例:它将返回一个新实例。

创建一个BehaviourSubject,如下所示:

private _todos = new BehaviorSubject<Todo[]>(null);

我们可以根据需要使用它来更新Observable值。

像这样更改getTodos函数:

public getTodos(): Observable<Todo[]>{
  return this._todos.asObservable();
}

现在,无论何时更改todos的值,都应在next上调用BehaviourSubject。例如:

public deleteCompleted(){
  let todos = this.allTodos;
  let completedTodos = todos.filter(todo => todo.completed === false);
  this.allTodos = completedTodos;
  this.storageService.setTodos(this.allTodos);
  // Emit the new value from the Observable
  this._todos.next(this.allTodos);
}

Here is a fork of your Stackblitz to show it working