кутова 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.