Skip to content

Instantly share code, notes, and snippets.

@mdmoin7
Last active June 1, 2021 11:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mdmoin7/13828acc95b3bf6c32eb98b9e7a6c581 to your computer and use it in GitHub Desktop.
Save mdmoin7/13828acc95b3bf6c32eb98b9e7a6c581 to your computer and use it in GitHub Desktop.
/*
*ngFor="let c of oneDimArray | sortBy:true/false:'asc'"
*ngFor="let c of arrayOfObjects | sortBy:true/false:'asc':'propertyName'"
*/
import { Pipe, PipeTransform } from "@angular/core";
import { orderBy, sortBy } from "lodash";
@Pipe({ name: "sortBy" })
export class SortByPipe implements PipeTransform {
transform<T>(
value: T[],
caseInsensitive = false,
order = "",
column: string = ""
): T[] {
if (!value || order === "" || !order) {
return value;
} // no array
if (!column || column === "") {
const sorted = this.sortOnCaseSensitivity(value, caseInsensitive);
if (order === "asc") {
return sorted;
} else {
return sorted.reverse();
}
} // sort 1d array
if (value.length <= 1) {
return value;
} // array with only one item
else {
const converted = this.convertMultiOnCaseSensitivity(
value,
column,
caseInsensitive
);
return orderBy(converted, ["sortCol"], [order]).map(v => {
delete v["sortCol"];
return v;
});
}
}
sortOnCaseSensitivity<T>(value: T[], caseInsensitive: boolean): T[] {
return sortBy(value, (v: T) => {
if (typeof v === "string" && caseInsensitive) {
return v.toLowerCase();
}
return v;
});
}
convertMultiOnCaseSensitivity<T>(
value: T[],
column: string,
caseInsensitive: boolean
): T[] {
let converted = value.map((v: T) => ({ ...v, sortCol: v[column] }));
if (caseInsensitive) {
converted = value.map((v: T) => {
if (typeof v[column] === "string") {
return { ...v, sortCol: v[column].toLowerCase() };
}
return { ...v, sortCol: v[column] };
});
}
return converted;
}
}
@gcko
Copy link

gcko commented Dec 18, 2020

If you pass caseInsensitive as false, it will not sort value - 'sortCol' will not be defined in that case and will just be ignored.

@gcko
Copy link

gcko commented Dec 18, 2020

hey @mdmoin7, I went ahead and forked your gist and made some changes to fix the issue regarding no sort when caseInsensitive = false. I have also changed the code to import lodash-es, as latest Angular warns against using CommonJS or AMD modules - they prefer es modules

@mdmoin7
Copy link
Author

mdmoin7 commented Dec 18, 2020

If you pass caseInsensitive as false, it will not sort value - 'sortCol' will not be defined in that case and will just be ignored.

@gcko can you help me with the usage Syntax as well so that I can also understand the exact behavior here and its problem and thanks for the fork.

@gcko
Copy link

gcko commented Dec 18, 2020

Sure, lets look at the following sections of code:

First, the call to this.convertMultiOnCaseSensitivity

else{  
      const converted=this.convertMultiOnCaseSensitivity(value,column,caseInsensitive);
      return orderBy(converted, ['sortCol'], [order]).map(v=>{
        delete v['sortCol'];
        return v;
      });
    }

And the function that it calls:

convertMultiOnCaseSensitivity(value:any[],column,caseInsensitive){
    let converted=value;
      if(caseInsensitive){
        converted=value.map(v=>{
          if(typeof v[column]==='string'){
          return {...v,sortCol:v[column].toLowerCase()}
        }
        return v;
        })
      }
      return converted;
  }

The key part is that sortCol will only be added if caseInsensitive is a falsey value. That means when caseInsensitive = true, in the call to orderBy, (orderBy(converted, ['sortCol'], [order]), the items in converted do not have a sortItem key.

@mdmoin7
Copy link
Author

mdmoin7 commented Dec 18, 2020

@gcko thanks for the clarity, what i think here seems to be a problem when user doesn't provide sorting column name, correct me if I'm wrong. So in that case does placing sensitivity argument last in sequence to pipe help!!

@gcko
Copy link

gcko commented Dec 18, 2020

@mdmoin7 No, the issue is the same whether or not the user passes a value to caseInsensitivity. You can confirm this because the caseInsensitivity is initialized as false, so unless you pass a value of true, it will be false.

The issue is not related to whether the user provides a sorting column name, to be clear.

For example, the issue will appear if you do the following call:

*ngFor="let item of items|sortBy:false:'asc':'keyToSortOn';

@gcko
Copy link

gcko commented Jan 4, 2021

@mdmoin7 I made a followup revision on my gist here. The latest version now uses Generics so that passed in types are respected. In previous versions, any type passed in would come out as any[], and would lose other typing information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment