8

I am trying to create a pipe that will sort an array of a custom type.

// custom-object.ts
export class CustomObject {
    constructor(
        public someString: string,
        public someNumber: number
    ) {}
}

In my html is:

// custom-object-form.component.ts
<div class="form-group">
    <label for="cricos_course_code">Object: </label>
    <select class="form-control" required [(ngModel)]="model.someString">
        <option *ngFor="#object of (customObjects | sortArrayOfCustomObjects)" [value]="object.someString">{{object.someString}}</option>
    </select>
</div>

Then the code for the pipe:

// sort-custom-object.pipe.ts
import {Pipe, PipeTransform} from 'angular2/core';
import {CustomObject} from '../custom-object';

@Pipe({name: 'sortArrayOfCustomObjects'})
export class SortArrayOfCustomObjectsPipe implements PipeTransform {
  transform(arr:Array<CustomObject>): any {
    return arr.sort((a, b) => {
      if (a.someString > b.someString) {
        return 1;
      }
      if (a.someString < b.someString) {
        return -1;
      }
      // a must be equal to b
      return 0;
    });
  }
}

Now I am getting an error in the console:

EXCEPTION: TypeError: Cannot read property 'sort' of undefined in [(customObjects | sortArrayOfCustomObjects) in FormComponent@7:24]
4
  • Are you looking for args: Array<string | number>? Commented Feb 3, 2016 at 2:22
  • More along the lines of args: Array<CustomObject.someString | CustomObject.someNumber>. Then in my sort function (which doesn't seem to work?) I can change the sorting based on the supplied arguements. Commented Feb 3, 2016 at 3:44
  • The issue with Array<CustomObject.someString | CustomObject.someNumber> is that those are properties not types. The type of CustomObject.someString is a string. Therefor you cannot use CustomObject.someString as a type. Can you provide more information about your needs? Commented Feb 3, 2016 at 3:47
  • I have an array of objects that contain properties p1: string, p2: number etc. In my form I want to have 2 select fields that show a list of p1 in alphabetical order and p2 in descending order. I thought I could use a pipe like *ngFor="item of items | sortItems". Commented Feb 3, 2016 at 4:43

1 Answer 1

9

Based off of your limited information I believe you want the following.

@Pipe({name: 'sortArrayOfCustomObjects'})
export class SortArrayOfCustomObjectsPipe implements PipeTransform {

  transform(arr: CustomObject[], args: any): CustomObject[]{
    return arr.sort((a, b) => {
      if (a.p1 > b.p1 || a.p2 < b.p2) {
        return 1;
      }
      if (a.p1 < b.p1 || a.p2 > b.p2) {
        return -1;
      }
      return 0;
    });
  }
}

This will sort the objects first by p1, and then by p2. For instance.

{p1: 'AA', p2: 3},
{p1: 'CC', p2: 2},
{p1: 'BB', p2: 5},
{p1: 'BB', p2: 1},
{p1: 'AA', p2: 2},
{p1: 'DD', p2: 4}

Would be sorted to

{p1: 'AA', p2: 3},
{p1: 'AA', p2: 2},
{p1: 'BB', p2: 5},
{p1: 'BB', p2: 1},
{p1: 'CC', p2: 2},
{p1: 'DD', p2: 4}

This is based on your comment:

I have an array of objects that contain properties p1: string, p2: number etc. In my form I want to have 2 select fields that show a list of p1 in alphabetical order and p2 in descending order.

Usage would be

*ngFor="#item of (items | sortArrayOfCustomObjects)"

UPDATE

For your error that you are now receiving be sure to guard against undefined values in arrays by using a guard.

transform(arr: CustomObject[], args: any): CustomObject[]{
  if(!arr){ return; }
  ...
}
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, I am getting a TypeError: arr is undefined...? What would be causing this? The code works if I just return arr in my transform method though.
Updated answer to include parenthesis around usage (found in angular docs here way down close to the bottom).
I tried the parenthesis, but the error is still showing up. I have updated the question to try and provide some more detail as well.
Can you post the relevant parts of your component code, where you are assigning the value of customObjects is it possible that you are not assigning it a value? or perhaps an async issue. You could guard against this with an if statement in the transform function that checks if arr is undefined and if so returns either an empty array or undefined before it reaches the arr.sort(...) line.
Ah that was it! if (arr === undefined) { return arr; } else { ... } works. Would it be best practice to use the stateful AsyncPipe mentioned here? angular.io/docs/ts/latest/guide/pipes.html
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.