如何在 angular2 中制作带有对象数组的排序管道
原始问题:
我有一个待办事项列表(Todo[ ](,每次进行一些更改时,我都想对其进行排序。我希望完成的待办事项显示在列表底部。Todo 对象有一个名为 .done 的属性,它存储一个布尔值,它会告诉我们 todo 是否完成。
创建管道:
在 Angular2 中,"OrderBy"管道不存在。所以我们必须构建它:
import { Pipe, PipeTransform } from "angular2/core";
//Todo is the interface for our todo object
import {Todo} from './todo';
@Pipe({
name: "sort",
//set to false so it will always update, read below the code.
pure: false
})
export class TodosSortPipe implements PipeTransform {
transform(array: Todo[], args: any): Todo[] {
//watch the console to see how many times you pipe is called
console.log("calling pipe");
/* javascript is async, so could be that the pipe is called before
that the todos list is created, in this case we do nothing
returning the array as it is */
if (isBlank(array)) return null;
array.sort((a, b) => {
if (a.completed < b.completed) {
return -1;
//.completed because we want to sort the list by completed property
} else if (a.completed > b.completed) {
return 1;
} else {
return 0;
}
});
return array;
}
}
如果您不了解排序方法,请检查MDN:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
管道完成,让我们转到组件。
创建组件:
AppComponent 类创建一个名为 Todo 的待办事项数组,从带有服务的模拟中获取对象。
import {Component, OnInit} from 'angular2/core';
import {Todo} from './todo';
import {TodoService} from './todo.service';
import {TodosSortPipe} from './sort-pipe.component'
@Component({
//name of the html element
selector: 'my-app',
//view of the selector, " ` " is alt + 9
templateUrl: "./app/todo-list.component.html",
providers: [TodoService],
pipes: [ TodosSortPipe ]
})
export class AppComponent implements OnInit{
public todos: Todo[];
public edited = false;
public changes = 0;
//creating an istance of todoService
constructor(private _todoService: TodoService) { };
//getting the todos list from the service
getTodos() {
this._todoService.getTodos().then(todos => this.todos = todos);
}
(...)
editTodo(todo: Todo): void {
//slice is very important, read below the code
this.todos = this.todos.slice();
this.saveTodos();
}
}
模板实现
这是管道调用:
<li *ngFor="#todo of todos | sort; #i=index">
(...)
</li>
演示:
有关所有代码的完整示例:https://plnkr.co/edit/VICRMVNhqdqK9V4rJZYm?p=preview在github上观看:https://github.com/AndreaMiotto/Angular2-TodoApp
管道不纯
默认情况下,管道仅在管道输入参数更改时更改,而不会在数据更改时更改。将纯设置为假,您将使其"不纯",因此您的管道将始终更新。
也许值todos
在开始时null
,因为它是使用 HTTP 异步加载的。
为了防止出现此类用例,您可以在管道中添加以下内容:
@Pipe({
name: "sort"
})
export class TodosSortPipe implements PipeTransform {
transform(array: Todo[], args: any): Todo[] {
if (array == null) {
return null;
}
(...)
}
}
然后将接收值todos
,并且将使用此非空值再次调用管道的transform
方法...
此外,您的<li>
标签似乎没有结束。组件模板中必须包含有效的 HTML。我不知道它是完整的代码还是截断的代码......
希望对您有所帮助,蒂埃里
我创建了一个支持单维和多维数组的 OrderBy 管道。它还支持能够对多维数组的多列进行排序。
<li *ngFor="#todo of todos | orderBy : ['completed']; #i=index">
{{i}}) {{todo.name}} - {{todo.completed}}
</li>
此管道确实允许在呈现页面后向数组添加更多项,并且仍然使用新项动态对数组进行排序。
我在这里写了一篇关于这个过程的文章。
这是一个工作演示:http://fuelinteractive.github.io/fuel-ui/#/pipe/orderby 和 https://plnkr.co/edit/DHLVc0?p=info
您需要更改 html 模板,以便管道可以容纳异步代码。
更改此行:
<li *ngFor="#todo of todos | sort; #i=index">
(...)
</li>
对此:
<li *ngFor="#todo of todos | async | sort; #i=index">
(...)
</li>
我把你的管道代码复制到这个 Plunker 中:
https://plnkr.co/edit/RBpZilgxIyRDLwktNZN1?p=preview