programing tip

OrderBy 파이프 문제

itbloger 2020. 9. 5. 09:25
반응형

OrderBy 파이프 문제


이 코드를 Angualr 1에서 Angular 2로 번역 할 수 없습니다.

ng-repeat="todo in todos | orderBy: 'completed'"

이것은 Thierry Templier의 답변에 따라 내가 한 일입니다.

구성 요소 템플릿 :

*ngFor="#todo of todos | sort"

구성품 코드 :

@Component({
    selector: 'my-app',
    templateUrl: "./app/todo-list.component.html",
    providers: [TodoService],
    pipes: [ TodosSortPipe ]

})

파이프 코드 :

import { Pipe } from "angular2/core";
import {Todo} from './todo';

@Pipe({
  name: "sort"
})
export class TodosSortPipe {
  transform(array: Array<Todo>, args: string): Array<Todo> {
    array.sort((a: any, b: any) => {
      if (a < b) {
        return -1;
      } else if (a > b) {
        return 1;
      } else {
        return 0;
      }
    });
    return array;
  }
}

Todo속성별로 정렬 된 배열을 정렬하려고 합니다 completed. 먼저 todo.completed = false다음 todo.complete = true.

나는 그 transform방법과 방법과 방법에서 인수를 전달하는 방법을 잘 이해하지 못합니다 sort.

args: string논쟁 은 무엇입니까 ? 무엇 ab그들이 어디에서 온?


파이프가 사용자 지정 개체를 각도 4로 정렬 할 수 있도록 @Thierry Templier의 응답을 수정했습니다.

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

@Pipe({
  name: "sort"
})
export class ArraySortPipe  implements PipeTransform {
  transform(array: any, field: string): any[] {
    if (!Array.isArray(array)) {
      return;
    }
    array.sort((a: any, b: any) => {
      if (a[field] < b[field]) {
        return -1;
      } else if (a[field] > b[field]) {
        return 1;
      } else {
        return 0;
      }
    });
    return array;
  }
}

그리고 그것을 사용하려면 :

*ngFor="let myObj of myArr | sort:'fieldName'"

바라건대 이것은 누군가를 도울 것입니다.


전체 토론 https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe참조 하십시오 . 이 인용문은 가장 관련성이 있습니다. 기본적으로 적극적으로 축소해야하는 대규모 앱의 경우 필터링 및 정렬 논리가 구성 요소 자체로 이동해야합니다.

"우리 중 일부는 이것을 공격적으로 축소하는 데 신경 쓰지 않을 수 있습니다. 그것이 우리의 선택입니다. 그러나 Angular 제품은 다른 사람이 공격적으로 축소하는 것을 막아서는 안됩니다. 따라서 Angular 팀은 Angular에 제공된 모든 것이 안전하게 축소 될 것이라고 결정했습니다.

Angular 팀과 경험 많은 Angular 개발자는 필터링 및 정렬 논리를 구성 요소 자체로 이동할 것을 강력히 권장합니다. 구성 요소는 filterHeroes 또는 sortedHeroes 속성을 노출하고 지원 논리를 실행할시기와 빈도를 제어 할 수 있습니다. 파이프에 넣고 앱 전체에서 공유 할 수있는 모든 기능을 필터링 / 정렬 서비스로 작성하고 구성 요소에 삽입 할 수 있습니다. "


sort배열 방법 을 활용하는 사용자 지정 파이프를 구현할 수 있습니다.

import { Pipe } from "angular2/core";

@Pipe({
  name: "sort"
})
export class ArraySortPipe {
  transform(array: Array<string>, args: string): Array<string> {
    array.sort((a: any, b: any) => {
      if (a < b) {
        return -1;
      } else if (a > b) {
        return 1;
      } else {
        return 0;
      }
    });
    return array;
  }
}

그리고 아래에 설명 된대로이 파이프를 사용합니다. pipes구성 요소 속성에 파이프를 지정하는 것을 잊지 마십시오 .

@Component({
  (...)
  template: `
    <li *ngFor="list | sort"> (...) </li>
  `,
  pipes: [ ArraySortPipe ]
})
(...)

문자열 값이있는 배열에 대한 간단한 샘플이지만 일부 고급 정렬 처리를 수행 할 수 있습니다 (정렬 매개 변수를 기반으로하는 객체 배열의 경우 객체 속성을 기반으로 함).

여기에 대한 plunkr가 있습니다 : https://plnkr.co/edit/WbzqDDOqN1oAhvqMkQRQ?p=preview .

도움이 되었기를 바랍니다, Thierry


OrderByPipe 업데이트 : 정렬되지 않는 문자열 수정.

OrderByPipe 클래스를 만듭니다.

import { Pipe, PipeTransform } from "@angular/core";
@Pipe( {
name: 'orderBy'
} )
export class OrderByPipe implements PipeTransform {
transform( array: Array<any>, orderField: string, orderType: boolean ): Array<string> {
    array.sort( ( a: any, b: any ) => {
        let ae = a[ orderField ];
        let be = b[ orderField ];
        if ( ae == undefined && be == undefined ) return 0;
        if ( ae == undefined && be != undefined ) return orderType ? 1 : -1;
        if ( ae != undefined && be == undefined ) return orderType ? -1 : 1;
        if ( ae == be ) return 0;
        return orderType ? (ae.toString().toLowerCase() > be.toString().toLowerCase() ? -1 : 1) : (be.toString().toLowerCase() > ae.toString().toLowerCase() ? -1 : 1);
    } );
    return array;
  }
}

컨트롤러에서 :

@Component({
pipes: [OrderByPipe]
})

또는 당신의

 declarations: [OrderByPipe]

귀하의 HTML에서 :

<tr *ngFor="let obj of objects | orderBy : ObjFieldName: OrderByType">

ObjFieldName : 정렬하려는 개체 필드 이름입니다.

OrderByType : 부울; 참 : 내림차순; 거짓 : 오름차순;


Angular는 orderBy 필터를 기본 제공하지 않지만 필요하다고 결정하면 쉽게 만들 수 있습니다. 그러나 속도 및 축소와 관련하여 알아야 할 몇 가지주의 사항이 있습니다. 아래를 참조하십시오.

간단한 파이프는 다음과 같습니다.

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

@Pipe({
  name: 'sort'
})
export class SortPipe implements PipeTransform {
  transform(ary: any, fn: Function = (a,b) => a > b ? 1 : -1): any {
    return ary.sort(fn)
  }
}

이 파이프는 정렬 함수 ( fn)를 받아들이고 기본 배열을 합리적인 방식으로 정렬하는 기본값을 제공합니다. 원하는 경우이 정렬 기능을 재정의 할 수 있습니다.

속성 이름은 축소 될 수 있으므로 속성 이름을 문자열로 허용하지 않습니다. 코드를 축소하면 변경되지만 축소자는 템플릿 문자열의 값도 축소 할만큼 똑똑하지 않습니다.

기본 요소 (숫자 및 문자열) 정렬

이를 사용하여 기본 비교기를 사용하여 숫자 또는 문자열 배열을 정렬 할 수 있습니다.

import { Component } from '@angular/core';

@Component({
  selector: 'cat',
  template: `
    {{numbers | sort}}
    {{strings | sort}}
  `
})
export class CatComponent
  numbers:Array<number> = [1,7,5,6]
  stringsArray<string> = ['cats', 'hats', 'caveats']
}

개체 배열 정렬

객체 배열을 정렬하려면 비교 함수를 제공 할 수 있습니다.

import { Component } from '@angular/core';

@Component({
  selector: 'cat',
  template: `
    {{cats | sort:byName}}
  `
})
export class CatComponent
  cats:Array<Cat> = [
    {name: "Missy"},
    {name: "Squoodles"},
    {name: "Madame Pompadomme"}
  ]
  byName(a,b) {
    return a.name > b.name ? 1 : -1
  }
}

주의 사항-순수 파이프와 불순 파이프

Angular 2는 순수하고 불순한 파이프의 개념을 가지고 있습니다.

순수 파이프는 객체 ID를 사용하여 변경 감지를 최적화합니다. 즉, 입력 개체가 ID를 변경하는 경우에만 파이프가 실행됩니다 (예 : 배열에 새 항목을 추가하는 경우). 물체로 내려 가지 않습니다. 즉, 중첩 된 속성을 변경 this.cats[2].name = "Fluffy"하면 파이프가 다시 실행되지 않습니다. 이것은 Angular가 빠르도록 도와줍니다. 각도 파이프는 기본적으로 순수합니다.

반면에 불순한 파이프 는 객체 속성을 확인합니다. 이것은 잠재적으로 훨씬 느리게 만듭니다. 파이프 함수가 수행 할 작업을 보장 할 수 없기 때문에 (예를 들어 시간에 따라 다르게 정렬 될 수 있음) 비동기 이벤트가 발생할 때마다 불순한 파이프가 실행됩니다. 배열이 큰 경우 앱 속도가 상당히 느려집니다.

위의 파이프는 순수합니다. 즉, 배열의 개체가 변경 불가능할 때만 실행됩니다. 고양이를 변경하는 경우 전체 고양이 개체를 새 개체로 바꿔야합니다.

this.cats[2] = {name:"Tomy"}

pure 속성을 설정하여 위를 불순한 파이프로 변경할 수 있습니다.

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

@Pipe({
  name: 'sort',
  pure: false
})
export class SortPipe implements PipeTransform {
  transform(ary: any, fn: Function = (a,b) => a > b ? 1 : -1): any {
    return ary.sort(fn)
  }
}

이 파이프는 물체로 내려가지만 속도가 느려집니다. 주의해서 사용하십시오.


필요한 작업을 수행하는 OrderBy 파이프를 만들었습니다. 또한 개체 열거 형의 여러 열에 대해 정렬 할 수 있도록 지원합니다.

<li *ngFor="#todo in todos | orderBy : ['completed']">{{todo.name}} {{todo.completed}}</li>

이 파이프는 페이지를 렌더링 한 후 배열에 더 많은 항목을 추가 할 수 있도록하며 업데이트 된 배열을 동적으로 정렬합니다.

여기에 과정에 대한 글이 있습니다 .

그리고 여기에 작동하는 데모가 있습니다 : http://fuelinteractive.github.io/fuel-ui/#/pipe/orderbyhttps://plnkr.co/edit/DHLVc0?p=info


각도와 함께 lodash를 사용하는 것이 좋습니다. 그러면 파이프가 다음이 될 것입니다.

import {Pipe, PipeTransform} from '@angular/core';
import * as _ from 'lodash'
@Pipe({
    name: 'orderBy'
})
export class OrderByPipe implements PipeTransform {

    transform(array: Array<any>, args?: any): any {
        return _.sortBy(array, [args]);
    }

}

html에서 사용하십시오.

*ngFor = "#todo of todos | orderBy:'completed'"

모듈에 파이프를 추가하는 것을 잊지 마십시오.

@NgModule({
    ...,
    declarations: [OrderByPipe, ...],
    ...
})

이것은 전달하는 모든 필드에서 작동합니다. ( 중요 : 알파벳순으로 만 정렬되므로 날짜가 지나면 날짜가 아닌 알파벳순으로 정렬됩니다.)

/*
 *      Example use
 *      Basic Array of single type: *ngFor="let todo of todoService.todos | orderBy : '-'"
 *      Multidimensional Array Sort on single column: *ngFor="let todo of todoService.todos | orderBy : ['-status']"
 *      Multidimensional Array Sort on multiple columns: *ngFor="let todo of todoService.todos | orderBy : ['status', '-title']"
 */

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

@Pipe({name: "orderBy", pure: false})
export class OrderByPipe implements PipeTransform {

    value: string[] = [];

    static _orderByComparator(a: any, b: any): number {

        if (a === null || typeof a === "undefined") { a = 0; }
        if (b === null || typeof b === "undefined") { b = 0; }

        if (
            (isNaN(parseFloat(a)) ||
            !isFinite(a)) ||
            (isNaN(parseFloat(b)) || !isFinite(b))
        ) {
            // Isn"t a number so lowercase the string to properly compare
            a = a.toString();
            b = b.toString();
            if (a.toLowerCase() < b.toLowerCase()) { return -1; }
            if (a.toLowerCase() > b.toLowerCase()) { return 1; }
        } else {
            // Parse strings as numbers to compare properly
            if (parseFloat(a) < parseFloat(b)) { return -1; }
            if (parseFloat(a) > parseFloat(b)) { return 1; }
        }

        return 0; // equal each other
    }

    public transform(input: any, config = "+"): any {
        if (!input) { return input; }

        // make a copy of the input"s reference
        this.value = [...input];
        let value = this.value;
        if (!Array.isArray(value)) { return value; }

        if (!Array.isArray(config) || (Array.isArray(config) && config.length === 1)) {
            let propertyToCheck: string = !Array.isArray(config) ? config : config[0];
            let desc = propertyToCheck.substr(0, 1) === "-";

            // Basic array
            if (!propertyToCheck || propertyToCheck === "-" || propertyToCheck === "+") {
                return !desc ? value.sort() : value.sort().reverse();
            } else {
                let property: string = propertyToCheck.substr(0, 1) === "+" || propertyToCheck.substr(0, 1) === "-"
                    ? propertyToCheck.substr(1)
                    : propertyToCheck;

                return value.sort(function(a: any, b: any) {
                    let aValue = a[property];
                    let bValue = b[property];

                    let propertySplit = property.split(".");

                    if (typeof aValue === "undefined" && typeof bValue === "undefined" && propertySplit.length > 1) {
                        aValue = a;
                        bValue = b;
                        for (let j = 0; j < propertySplit.length; j++) {
                            aValue = aValue[propertySplit[j]];
                            bValue = bValue[propertySplit[j]];
                        }
                    }

                    return !desc
                        ? OrderByPipe._orderByComparator(aValue, bValue)
                        : -OrderByPipe._orderByComparator(aValue, bValue);
                });
            }
        } else {
            // Loop over property of the array in order and sort
            return value.sort(function(a: any, b: any) {
                for (let i = 0; i < config.length; i++) {
                    let desc = config[i].substr(0, 1) === "-";
                    let property = config[i].substr(0, 1) === "+" || config[i].substr(0, 1) === "-"
                        ? config[i].substr(1)
                        : config[i];

                    let aValue = a[property];
                    let bValue = b[property];

                    let propertySplit = property.split(".");

                    if (typeof aValue === "undefined" && typeof bValue === "undefined" && propertySplit.length > 1) {
                        aValue = a;
                        bValue = b;
                        for (let j = 0; j < propertySplit.length; j++) {
                            aValue = aValue[propertySplit[j]];
                            bValue = bValue[propertySplit[j]];
                        }
                    }

                    let comparison = !desc
                        ? OrderByPipe._orderByComparator(aValue, bValue)
                        : -OrderByPipe._orderByComparator(aValue, bValue);

                    // Don"t return 0 yet in case of needing to sort by next property
                    if (comparison !== 0) { return comparison; }
                }

                return 0; // equal each other
            });
        }
    }
}

이것은 angular 4의 AngularJs orderby 파이프를 대체하는 좋은 방법 입니다. 사용하기 쉽고 간단합니다.

자세한 내용은 github URL입니다. https://github.com/VadimDez/ngx-order-pipe

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

@Pipe({
  name: 'orderBy'
})
export class OrderPipe implements PipeTransform {

  transform(value: any | any[], expression?: any, reverse?: boolean): any {
    if (!value) {
      return value;
    }

    const isArray = value instanceof Array;

    if (isArray) {
      return this.sortArray(value, expression, reverse);
    }

    if (typeof value === 'object') {
      return this.transformObject(value, expression, reverse);
    }

    return value;
  }

  /**
   * Sort array
   *
   * @param value
   * @param expression
   * @param reverse
   * @returns {any[]}
   */
  private sortArray(value: any[], expression?: any, reverse?: boolean): any[] {
    const isDeepLink = expression && expression.indexOf('.') !== -1;

    if (isDeepLink) {
      expression = OrderPipe.parseExpression(expression);
    }

    let array: any[] = value.sort((a: any, b: any): number => {
      if (!expression) {
        return a > b ? 1 : -1;
      }

      if (!isDeepLink) {
        return a[expression] > b[expression] ? 1 : -1;
      }

      return OrderPipe.getValue(a, expression) > OrderPipe.getValue(b, expression) ? 1 : -1;
    });

    if (reverse) {
      return array.reverse();
    }

    return array;
  }


  /**
   * Transform Object
   *
   * @param value
   * @param expression
   * @param reverse
   * @returns {any[]}
   */
  private transformObject(value: any | any[], expression?: any, reverse?: boolean): any {
    let parsedExpression = OrderPipe.parseExpression(expression);
    let lastPredicate = parsedExpression.pop();
    let oldValue = OrderPipe.getValue(value, parsedExpression);

    if (!(oldValue instanceof Array)) {
      parsedExpression.push(lastPredicate);
      lastPredicate = null;
      oldValue = OrderPipe.getValue(value, parsedExpression);
    }

    if (!oldValue) {
      return value;
    }

    const newValue = this.transform(oldValue, lastPredicate, reverse);
    OrderPipe.setValue(value, newValue, parsedExpression);
    return value;
  }

  /**
   * Parse expression, split into items
   * @param expression
   * @returns {string[]}
   */
  private static parseExpression(expression: string): string[] {
    expression = expression.replace(/\[(\w+)\]/g, '.$1');
    expression = expression.replace(/^\./, '');
    return expression.split('.');
  }

  /**
   * Get value by expression
   *
   * @param object
   * @param expression
   * @returns {any}
   */
  private static getValue(object: any, expression: string[]) {
    for (let i = 0, n = expression.length; i < n; ++i) {
      const k = expression[i];
      if (!(k in object)) {
        return;
      }
      object = object[k];
    }

    return object;
  }

  /**
   * Set value by expression
   *
   * @param object
   * @param value
   * @param expression
   */
  private static setValue(object: any, value: any, expression: string[]) {
    let i;
    for (i = 0; i < expression.length - 1; i++) {
      object = object[expression[i]];
    }

    object[expression[i]] = value;
  }
}

우리는 ANGULAR 2에서 filter와 order by가 제거되었고 우리 자신을 작성해야한다는 것을 알고 있듯이, 여기에 plunker상세한 기사 에 대한 좋은 예가 있습니다.

필터와 orderby를 모두 사용했습니다. 여기에 주문 파이프 코드가 있습니다.

import { Pipe, PipeTransform } from '@angular/core';    
@Pipe({  name: 'orderBy' })
export class OrderrByPipe implements PipeTransform {

  transform(records: Array<any>, args?: any): any {       
    return records.sort(function(a, b){
          if(a[args.property] < b[args.property]){
            return -1 * args.direction;
          }
          else if( a[args.property] > b[args.property]){
            return 1 * args.direction;
          }
          else{
            return 0;
          }
        });
    };
 }

객체에 사용할 수 있습니다.

@Pipe({
  name: 'sort',
})
export class SortPipe implements PipeTransform {

  transform(array: any[], field: string): any[] {
    return array.sort((a, b) => a[field].toLowerCase() !== b[field].toLowerCase() ? a[field].toLowerCase() < b[field].toLowerCase() ? -1 : 1 : 0);
  }

}

package.json에 다음과 같은 내용을 추가합니다 (이 버전은 Angular 2에 적합합니다).

  "ngx-order-pipe": "^1.1.3",

typescript 모듈 (및 가져 오기 배열)에서 :

  import { OrderModule } from 'ngx-order-pipe';

Angular2의 현재 버전에서는 orderBy 및 ArraySort 파이프가 지원되지 않습니다. 이를 위해 사용자 지정 파이프를 작성 / 사용해야합니다.


Angular JS의 orderby Pipe 는 지원하지만 Angular (상위 버전) . 성능 속도를 높이기 위해 논의 된 세부 사항을 찾으십시오.

https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe


Angular 5+ 버전의 경우 ngx-order-pipe 패키지를 사용할 수 있습니다.

소스 튜토리얼 링크

패키지 설치

$ npm install ngx-order-pipe --save

앱 모듈에서 가져 오기

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { OrderModule } from 'ngx-order-pipe';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    OrderModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

어디서나 사용

  <ul>
    <li *ngFor="let item of (dummyData | orderBy:'name') ">
      {{item.name}}
    </li>
  </ul>

Component template:
todos| sort: ‘property’:’asc|desc’

Pipe code:

import { Pipe,PipeTransform  } from "angular/core";
import {Todo} from './todo';

@Pipe({
  name: "sort"
})
export class TodosSortPipe implements PipeTransform {
  transform(array: Array<Todo>, args: string): Array<Todo> {
    array.sort((a: any, b: any) => {
      if (a < b) {
        return -1;
      } else if (a > b) {
        return 1;
      } else {`enter code here`
        return 0;
      }
    });
    return array;
  }
}

참고 URL : https://stackoverflow.com/questions/35158817/orderby-pipe-issue

반응형