Angular 6 中不纯管道的替代品?

Alternative for impure pipes in Angular 6?

我正在尝试编写一个简单的待办事项应用程序来学习Angular 6. 在我的应用程序中,待办事项可以完成或未完成,我想在页脚组件中显示未完成待办事项的数量。

我有一个显示待办事项列表的待办事项组件:

todos.component.ts

export class TodosComponent implements OnInit {
  todos: Todo[];
  constructor(private todoService: TodoService) { 
    this.todos = todoService.GetAll();
  }
  ngOnInit() {}
  ToggleTodoCompleted(id: number): void{
    this.todoService.Toggle(id);
  }
}

要添加待办事项的另一个组件:

todo-add.component.ts

export class TodoAddComponent implements OnInit {
  constructor(private todoService: TodoService) { }
  ngOnInit() {}
  AddTodo(todoTitle){
    let todo = new Todo();
    todo.title = todoTitle;
    this.todoService.Add(todo);
  }
}

一个页脚组件,我用一个不纯的管道来显示其中未完成的待办事项的数量:

footer.component.ts

export class FooterComponent implements OnInit {
  todos: Todo[] = [];
  constructor(private todoService: TodoService) { 
    this.todos = todoService.GetAll();
  }
  ngOnInit() {}
}

未完成-todos.pipe.ts

@Pipe({
  name: 'uncompletedTodos',
  pure: false
})
export class UncompletedTodosPipe implements PipeTransform {

  transform(todos: Todo[]): any {
    return todos.filter(t=>t.completed===false);
  }
}

footer.component.html

{{(todos|uncompletedTodos).length}} items left

和简单的服务:

todo.service.ts

export class TodoService {
  private todos: Todo[] = [];
  GetAll(): Todo[]{
    return this.todos;
  }
  Add(todo: Todo): void{
    todo.id = this.todos.length + 1;
    todo.completed = false;
    this.todos.push(todo);
  }
  Toggle(id: number): void{
    let todo = this.todos.find(t => t.id === id); 
    todo.completed = !todo.completed;
  }
}

但我在 Angular 文档中读到,不纯的管道会导致性能问题。那么替代方案是什么?如果没有这个不纯的管道,我怎么能写我的代码?

这是解释right in the documentation:

Angular doesn't provide pipes for filtering or sorting lists [...] This isn't an oversight. Angular doesn't offer such pipes because they perform poorly and prevent aggressive minification [...] The Angular team and many experienced Angular developers strongly recommend moving filtering and sorting logic into the component itself

这意味着你应该摆脱你的管道,并将逻辑直接放在你的组件中。

EDIT 例如,将逻辑放入功能本身:

export class TodoService {
  private todos: Todo[] = [];
  GetAll(): Todo[]{
    return this.todos;
  }
  GetUncompleted() {
    return this.todos.filter(td => !td.completed);
  }
  ...

编辑 2 你的问题来自于你只在组件启动时分配一次待办事项的值。

这意味着当您将项目添加到待办事项列表时,您看不到更改,因为您没有更新值。

对此,有两种解决方案:第一种是使用吸气剂。

Getter 是一种特殊的函数,只要被调用就会更新它们的值。使用起来非常简单。例如,在您的 todo.component 中,它会给出:

get todos() { return this.todoService.getAll(); }

您现在可以在您的模板中使用它

*ngFor="let todo of todos"

这将被更新。

Here is a stackblitz to show you how getters work

第二种解决方案,是使用 RxJS。这是一个事件解决方案:当您的列表更新时,您必须触发一个事件。由于这个解决方案比较难,我做了this stackblitz来帮助你理解它。

基本上发生的事情是,每当您的列表更新时,您的组件都会收到一个事件,告诉它们必须更新待办事项列表。