кутова 2 сортування та фільтрування


78

В Angularjs 1 можна сортувати та фільтрувати таким чином:

<ul ng-repeat="friend in friends | filter:query | orderBy: 'name' ">
   <li>{{friend.name}}</li>
</ul>

Але я не міг знайти прикладів того, як це зробити в Angularjs 2.0. Моє питання полягає в тому, як сортувати та фільтрувати в Angularjs 2.0? Якщо він все ще не підтримується, хтось знає, коли і чи буде він доданий до Angularjs 2.0?



Дякую, я спробую застосувати власну трубу для фільтрування та сортування. Дивно, що команда Angular вирішила видалити цю функцію. Сподіваюся, вони повернуть його назад, щоб простіше було фільтрувати та сортувати.
alexsoftware

Ви не можете просто відсортувати friendsкод компонента?
Red Cricket

Відповіді:


81

Це не додається з коробки, оскільки команда Angular хоче, щоб Angular 2 працював у мініфікованій версії. OrderBy вибігає з роздумів, що розривається із зменшенням. Перевірте відповідь Мішко Гевері з цього приводу.

Я знайшов час, щоб створити конвеєр OrderBy, який підтримує одно- і багатовимірні масиви. Він також підтримує можливість сортування за кількома стовпцями багатовимірного масиву.

<li *ngFor="let person of people | orderBy : ['-lastName', 'age']">{{person.firstName}} {{person.lastName}}, {{person.age}}</li>

Цей конвеєр дозволяє додавати більше елементів до масиву після рендеринга сторінки, і все одно правильно сортувати масиви з новими елементами.

У мене є запис про процес тут .

І ось робоча демонстрація: http://fuelinteractive.github.io/fuel-ui/#/pipe/orderby та https://plnkr.co/edit/DHLVc0?p=info

РЕДАГУВАТИ: Додано нову демонстрацію до http://fuelinteractive.github.io/fuel-ui/#/pipe/orderby

EDIT 2: оновлено ngFor до нового синтаксису


2
Невелике оновлення. Останній Angular2 * ngFor використовував би * ngFor = "нехай людина людей ... замість хештегу #
Pat M

2
@CoryShaw чудова труба! молодець **** плескаючи смайлики *****
Мавпа Хаосу

1
@invot Правильно, ця труба є лише функцією orderBy. Для фільтрації на масиві слід використовувати другу трубу. Відповідь select нижче є хорошим прикладом для фільтрації
Cory Shaw

2
@ 72GM багатовимірним насправді було б [][], тож ви праві. Чи було б кращим формулювання багаторівневим? [].SomeObjectProperty.SomeProperty
Кори Шоу

1
Я використовую Angular 6 і змусив його працювати приблизно протягом 5 хв. Просто створив конвеєр з CLI, а потім скопіював код і виправив усі дрібниці, які TS-Lint показав (лише помилки з лайнтами), і це спрацювало як шарм. Використовував його вже 5 разів у моєму додатку за першу годину - чудова труба!
Alfa Bravo,

22

Це не підтримується дизайном. Труба sortBy може спричинити реальні проблеми з продуктивністю програми масштабу виробництва. Це була проблема з кутовою версією 1.

Не слід створювати власну функцію сортування. Натомість вам слід відсортувати свій масив спочатку у файлі TypeScript, а потім відобразити його. Якщо замовлення потрібно оновити, коли, наприклад, вибрано спадне меню, нехай цей випадаючий вибір запускає функцію і викликає вашу функцію сортування, викликану з неї. Цю функцію сортування можна витягти в службу, щоб її можна було використовувати повторно. Таким чином, сортування застосовуватиметься лише тоді, коли це потрібно, і ефективність вашого додатку буде набагато кращою.


1
Хоча я розумію аргументацію, яка стоїть за цим, мені буде дуже неприємно втратити таку загальну особливість без очевидної заміни. Звичайно, я можу реалізувати своє власне сортування тощо, але чому немає простої заміни, яка призначена для використання в сервісах замість шаблонів.
schneida

1
@schneida: може, тому, що існує безліч інших бібліотек, які можуть робити сортування за вас, як вам подобається, і з компромісами, які ви знаєте і з якими можна жити? порівняти тобто. чому momentабо moment-timezoneне включено за замовчуванням, що це така загальна риса без очевидної заміни теж (до речі. див. зовнішній пакет angular2-momentвідповідних труб для моментів - це також показує, як легко зробити плагін, який заповнить прогалину)
quetzalcoatl

Логіка сортування та фільтрації Imho належить селекторам магазину (якщо ви використовуєте Redux / RxJS або інші подібні шаблони).
Спок

18

Ось проста фільтрувальна труба для масиву об'єктів, що містять атрибути із рядковими значеннями (ES6)

filter-array-pipe.js

import {Pipe} from 'angular2/core';

// # Filter Array of Objects
@Pipe({ name: 'filter' })
export class FilterArrayPipe {
  transform(value, args) {
    if (!args[0]) {
      return value;
    } else if (value) {
      return value.filter(item => {
        for (let key in item) {
          if ((typeof item[key] === 'string' || item[key] instanceof String) && 
              (item[key].indexOf(args[0]) !== -1)) {
            return true;
          }
        }
      });
    }
  }
}

Ваш компонент

myobjComponent.js

import {Component} from 'angular2/core';
import {HTTP_PROVIDERS, Http} from 'angular2/http';
import {FilterArrayPipe} from 'filter-array-pipe';

@Component({
  templateUrl: 'myobj.list.html',
  providers: [HTTP_PROVIDERS],
  pipes: [FilterArrayPipe]
})
export class MyObjList {
  static get parameters() {
    return [[Http]];
  }
  constructor(_http) {
    _http.get('/api/myobj')
      .map(res => res.json())
      .subscribe(
        data => this.myobjs = data,
        err => this.logError(err))
      );
  }
  resetQuery(){
    this.query = '';
  }
}

У вашому шаблоні

myobj.list.html

<input type="text" [(ngModel)]="query" placeholder="... filter" > 
<div (click)="resetQuery()"> <span class="icon-cross"></span> </div>
</div>
<ul><li *ngFor="#myobj of myobjs| filter:query">...<li></ul>

Файли дуже схожі на те, як було б написано машинопис. Файли насправді є .ts?
Alex J,

Вони не є Typepscript, вам доведеться додавати типи в заголовки функцій transform(value: ..., args: ...)і в оголошення змінних з let.
виберіть

але при використанні з node це видає помилку для filer: query для об'єкта json. Ви знаєте, чому прийшла ця помилка?
Jignesh Vagh

1
@JigneshVagh filter- це функція масиву, тому це буде працювати лише у списках об'єктів, а не самих об'єктів, сподіваюся, це допоможе.
виберіть

13

Конвеєр приймає дані як вхідні дані та перетворює їх на бажаний вихід. Додайте цей файл конвеєра: orderby.tsвсередині вашої /appпапки.

orderby.ts

//The pipe class implements the PipeTransform interface's transform method that accepts an input value and an optional array of parameters and returns the transformed value.

import { Pipe,PipeTransform } from "angular2/core";

//We tell Angular that this is a pipe by applying the @Pipe decorator which we import from the core Angular library.

@Pipe({

  //The @Pipe decorator takes an object with a name property whose value is the pipe name that we'll use within a template expression. It must be a valid JavaScript identifier. Our pipe's name is orderby.

  name: "orderby"
})

export class OrderByPipe implements PipeTransform {
  transform(array:Array<any>, args?) {

    // Check if array exists, in this case array contains articles and args is an array that has 1 element : !id

    if(array) {

      // get the first element

      let orderByValue = args[0]
      let byVal = 1

      // check if exclamation point 

      if(orderByValue.charAt(0) == "!") {

        // reverse the array

        byVal = -1
        orderByValue = orderByValue.substring(1)
      }
      console.log("byVal",byVal);
      console.log("orderByValue",orderByValue);

      array.sort((a: any, b: any) => {
        if(a[orderByValue] < b[orderByValue]) {
          return -1*byVal;
        } else if (a[orderByValue] > b[orderByValue]) {
          return 1*byVal;
        } else {
          return 0;
        }
      });
      return array;
    }
    //
  }
}

У файлі компонента (app.component.ts) імпортуйте конвеєр, який ви щойно додали за допомогою: import {OrderByPipe} from './orderby';

Потім додайте *ngFor="#article of articles | orderby:'id'"всередину вашого шаблону, якщо ви хочете сортувати статті за ідентифікатором у порядку зростання або orderby:'!id'"у порядку зменшення.

Ми додаємо параметри до труби, слідуючи назві труби двокрапкою (:), а потім значенням параметра

Ми повинні вказати нашу трубу в масиві труб декоратора @Component. pipes: [ OrderByPipe ].

app.component.ts

import {Component, OnInit} from 'angular2/core';
import {OrderByPipe} from './orderby';

@Component({
    selector: 'my-app',
    template: `
      <h2>orderby-pipe by N2B</h2>
      <p *ngFor="#article of articles | orderby:'id'">
        Article title : {{article.title}}
      </p>
    `,
    pipes: [ OrderByPipe ]

})
export class AppComponent{
    articles:Array<any>
    ngOnInit(){
        this.articles = [
        {
            id: 1,
            title: "title1"
        },{
            id: 2,
            title: "title2",
        }]  
    }

}

Більше інформації тут на моєму github і цей пост на моєму веб-сайті


1
Будь ласка, не публікуйте дублікатів відповідей . Натомість розгляньте інші дії, які можуть допомогти майбутнім користувачам знайти потрібну відповідь, як описано у зв’язаному дописі. Особливо, коли публікація містить посилання на ваш веб-сайт, оскільки ці дописи починають здаватися спамом.
Могсдад,


Добре, хлопці @Mogsdad - Вибачте за це, сподіваюся, це допоможе до речі!
Nicolas2bert

4
Мені сподобалось, як це структуровано, легко зрозуміти. Дякую. АЛЕ, оновіть свій сценарій, будь ласка, тут І на вашому веб-сайті / github. У першому рядку змініть "angular2 / core" на "@ angular / core". Окрім цього, спочатку я не зміг змусити його працювати, потім я пролетів ваш код і зрозумів, що ваш крок "шаблон" має велику помилку. У шаблоні це повинен бути масив, щоб усе працювало за призначенням: "| orderby: ['id']"
Starwave

1
@Starwave +1 за згадку про помилку в шаблоні. Цінується.
Gary

4

Ви повинні створити власну трубу для сортування масивів, ось один приклад, як це можна зробити.

<li *ngFor="#item of array | arraySort:'-date'">{{item.name}} {{item.date | date:'medium' }}</li>

https://plnkr.co/edit/DU6pxr?p=preview


10
Чому вони не надають це нестандартно? Це така звичайна річ, що смішно, якщо вони цього не надають.
берслінг

Також я думаю, що у вашій реалізації є проблема, вона працює з '-date', але якщо ви просто напишете 'date', let column = args[0].slice(1);команда робить стовпець просто таким, ateщо вже не є дійсним ключем.
берслінг

1
Аргументи @bersling полягають у тому, що вони хочуть, щоб Angular 2 міг бути мініфікованим і при цьому працювати коректно. OrderBy вимагає роздумів, які неможливо зменшити
Кори Шоу

2
Це не має сенсу ... всі вищезазначені рішення можна зменшити, чи не так? Як такий великий фреймворк може пропустити таку основну функціональність ...
Кокодоко,

1

Це мій сорт. Це зробить сортування за номерами, рядкове сортування та сортування за датою.

import { Pipe , PipeTransform  } from "@angular/core";

@Pipe({
  name: 'sortPipe'
 })

export class SortPipe implements PipeTransform {

    transform(array: Array<string>, key: string): Array<string> {

        console.log("Entered in pipe*******  "+ key);


        if(key === undefined || key == '' ){
            return array;
        }

        var arr = key.split("-");
        var keyString = arr[0];   // string or column name to sort(name or age or date)
        var sortOrder = arr[1];   // asc or desc order
        var byVal = 1;


        array.sort((a: any, b: any) => {

            if(keyString === 'date' ){

                let left    = Number(new Date(a[keyString]));
                let right   = Number(new Date(b[keyString]));

                return (sortOrder === "asc") ? right - left : left - right;
            }
            else if(keyString === 'name'){

                if(a[keyString] < b[keyString]) {
                    return (sortOrder === "asc" ) ? -1*byVal : 1*byVal;
                } else if (a[keyString] > b[keyString]) {
                    return (sortOrder === "asc" ) ? 1*byVal : -1*byVal;
                } else {
                    return 0;
                }  
            }
            else if(keyString === 'age'){
                return (sortOrder === "asc") ? a[keyString] - b[keyString] : b[keyString] - a[keyString];
            }

        });

        return array;

  }

}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.