{"id":17082296,"url":"https://github.com/SlyTed/ngx-pipes-toolkit","last_synced_at":"2026-05-21T12:30:17.686Z","repository":{"id":249389521,"uuid":"831025927","full_name":"SlyTed/ngx-pipes-toolkit","owner":"SlyTed","description":"Complementary pipes library for Angular","archived":false,"fork":false,"pushed_at":"2024-10-07T19:36:48.000Z","size":872,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-21T10:06:41.587Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SlyTed.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-19T13:43:03.000Z","updated_at":"2024-10-09T03:48:09.000Z","dependencies_parsed_at":null,"dependency_job_id":"ac5a3591-7e3a-4153-bc3d-0c0a8a3084a8","html_url":"https://github.com/SlyTed/ngx-pipes-toolkit","commit_stats":null,"previous_names":["slyted/ngx-pipes-toolkit"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlyTed%2Fngx-pipes-toolkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlyTed%2Fngx-pipes-toolkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlyTed%2Fngx-pipes-toolkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlyTed%2Fngx-pipes-toolkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SlyTed","download_url":"https://codeload.github.com/SlyTed/ngx-pipes-toolkit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240131743,"owners_count":19752725,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-14T13:00:24.810Z","updated_at":"2026-05-21T12:30:17.564Z","avatar_url":"https://github.com/SlyTed.png","language":"TypeScript","funding_links":[],"categories":["Third Party Components","Recently Updated"],"sub_categories":["Pipes","[Oct 13, 2024](/content/2024/10/13/README.md)"],"readme":"\u003ca href=\"https://www.npmjs.com/package/ngx-pipes-toolkit\"\u003e\n  \u003cimg src=\"https://img.shields.io/npm/v/ngx-pipes-toolkit.svg?style=for-the-badge\" alt=\"NPM package\"\u003e\n\u003c/a\u003e\n\u003ca href=\"http://packagequality.com/#?package=ngx-pipes-toolkit\"\u003e\n  \u003cimg src=\"https://npm.packagequality.com/shield/ngx-pipes-toolkit.svg?style=for-the-badge\" alt=\"Package quality\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://coveralls.io/github/SlyTed/ngx-pipes-toolkit?branch=main\"\u003e\n  \u003cimg src=\"https://img.shields.io/coveralls/SlyTed/ngx-pipes-toolkit.svg?style=for-the-badge\" alt=\"Coveralls\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://www.npmjs.com/package/ngx-pipes-toolkit\"\u003e\n  \u003cimg src=\"https://img.shields.io/npm/dm/ngx-pipes-toolkit.svg?style=for-the-badge\" alt=\"NPM monthly downloads\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://www.npmjs.com/package/ngx-pipes-toolkit\"\u003e\n  \u003cimg src=\"https://img.shields.io/npm/dt/ngx-pipes-toolkit?style=for-the-badge\" alt=\"NPM total downloads\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/SlyTed/ngx-pipes-toolkit/blob/main/LICENSE\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg?style=for-the-badge\" alt=\"MIT licensed\"\u003e\n\u003c/a\u003e\n\n# NGX Pipes Toolkit\n\nA complementary pipes library for Angular\n\n## Table of contents\n\n- [Motivation](#motivation)\n- [Installation](#installation)\n- [Usage](#usage)\n- [Content](#content)\n  - [Array](#array)\n    - [Enumerate](#enumerate)\n  - [Math](#math)\n    - [Convert](#convert)\n    - [MeanBy](#mean-by)\n    - [SumBy](#sum-by)\n    - [MinBy](#min-by)\n    - [MaxBy](#max-by)\n- [Contributing](#contributing)\n\n## Motivation\n\n**ngx-pipes-toolkit** library was born from the need to \"wrap\" the utility functions of [Lodash](https://lodash.com/docs) for a direct usage in the templates, especially the mathematical ones.\n\nTypically, we manipulate collections of objects fetched from a REST API, and we want to display to the users some statistics based on a property of those objects. For example, we might want to display the mean age for a collection of users.\n\nHowever, native Angular pipes or ones from other NPM packages like [NGX Pipes](https://www.npmjs.com/package/ngx-pipes) or [Angular Pipes](https://www.npmjs.com/package/angular-pipes) handle **only** data from native types (i.e. `number`, `string`, or `boolean`). Consequently, it is not possible to compute directly in the template the mean age. Therefore, we need to declare a derived value from the fetched collection in the component class (signals are used for convenience):\n\n```typescript\nimport { meanBy } from 'lodash';\n\nexport type User = {\n  id: string;\n  age: number;\n};\n\n@Component({\n  template: `\n    \u003cp\u003eMean age: {{ $meanAge() }}\n  `,\n})\nexport class DashboardComponent {\n  readonly $users: Signal\u003cUser[]\u003e = this.userApiService.fetchUsers();\n\n  readonly $meanAge = computed\u003cnumber\u003e(() =\u003e {\n    return meanBy(this.$users(), 'age');\n  });\n}\n```\n\nEven if this derived value `$meanAge` is relatively simple, it adds an extra layer for a straightforward computation using utility functions.\n\nThe primary motivation behind **ngx-pipes-toolkit** is to allow direct manipulation of collection of objets without declaring intermediate fields in the component class, thereby simplifying the code:\n\n```typescript\nimport { MeanByPipe } from 'ngx-pipes-toolkit';\n\nexport type User = {\n  id: string;\n  age: number;\n};\n\n@Component({\n  imports: [MeanByPipe],\n  template: `\n    \u003cp\u003eMean age: {{ $users() | meanBy:'age' }}\n  `,\n})\nexport class DashboardComponent {\n  readonly $users: Signal\u003cUser[]\u003e = this.userApiService.fetchUsers();\n}\n```\n\nMoreover, the aim of **ngx-pipes-toolkit** is **not** to replace other libraries, but to complement them. That's why there are no duplicate pipes with the other main Angular pipes library: [NGX Pipes](https://www.npmjs.com/package/ngx-pipes).\n\n## Installation\n\nUse NPM to install the package\n\n```bash\n$ npm install ngx-pipes-toolkit --save\n```\n\n## Usage\n\nAll pipes in **ngx-pipes-toolkit** are implemented as standalone pipes. There are no Angular modules that wrap the pipes. Therefore, you can directly use them in your components or templates by importing them where needed. Furthermore, all pipes are pure.\n\n- In templates:\n\n```html\n\u003cp\u003e{{ 1_000 | convert:'m':'km' }}\u003c/p\u003e \u003c!-- Returns \"1\" --\u003e\n```\n\n- In components:\n\n```typescript\nimport { ConvertPipe } from 'ngx-pipes-toolkit';\n\n@Component({\n  providers: [ConvertPipe],\n})\nexport class MyComponent {\n  readonly convertPipe = inject(ConvertPipe);\n\n  readonly conversion = this.convertPipe.transform(1_000, 'm', 'km'); // Returns \"1\"\n}\n```\n\n## Content\n\n### Array\n\n#### Enumerate\n\nAllows to use `*ngFor` directive or `@for` control flow block like a classic `for` loop (sometimes we just want to render something in the template a certain number of times, independently from a collection of objets)\n\n```html\n@for (index of $loadingCount() | enumerate; track index) {\n  \u003c!-- Display skeletons while loading... --\u003e\n}\n\u003cngx-skeleton *ngFor=\"let index of $loadingCount() | enumerate\" /\u003e\n```\n\n### Math\n\n#### Convert\n\nConverts a value with its current unit to the final unit\n\n```html\n\u003cp\u003e{{ 1_000 | convert:'m':'km' }}\u003c/p\u003e \u003c!-- Output: \"1\" --\u003e\n\u003cp\u003e{{ 32 | convert:'F':'C' }}\u003c/p\u003e \u003c!-- Output: \"0\" --\u003e\n```\n\n#### Mean by\n\nCalculates the mean of an array of objects based on one of their `number`, parsable `string` or `Date` property\n\n```typescript\nconst users = [\n  { name: 'Alice', age: 20 },\n  { name: 'Bob', age: 30 },\n]\nconst games = [\n  { name: 'Mass Effect 1', price: 30 }\n  { name: 'Mass Effect Andromeda', price: 40 }\n]\n```\n```html\n\u003cp\u003e{{ users | meanBy:'age' }}\u003c/p\u003e \u003c!-- Output: \"25\" --\u003e\n\u003cp\u003e{{ games | meanBy:'price' }}\u003c/p\u003e \u003c!-- Output: \"35\" --\u003e\n```\n\n#### Sum by\n\nCalculates the sum of an array of objects based on one of their `number`, parsable `string` or `Date` property\n\n```typescript\nconst users = [\n  { name: 'Alice', age: 20 },\n  { name: 'Bob', age: 30 },\n]\nconst games = [\n  { name: 'Mass Effect 1', price: 30 }\n  { name: 'Mass Effect Andromeda', price: 40 }\n]\n```\n```html\n\u003cp\u003e{{ users | sumBy:'age' }}\u003c/p\u003e \u003c!-- Output: \"50\" --\u003e\n\u003cp\u003e{{ games | sumBy:'price' }}\u003c/p\u003e \u003c!-- Output: \"70\" --\u003e\n```\n\n#### Min by\n\nReturns the item with the smallest value of an array of object based on one of their `number`, parsable `string` or `Date` property\n\n```typescript\nconst users = [\n  { name: 'Alice', age: 20 },\n  { name: 'Bob', age: 30 },\n]\nconst games = [\n  { name: 'Mass Effect 1', price: 30 }\n  { name: 'Mass Effect Andromeda', price: 40 }\n]\n```\n```html\n\u003cp\u003e{{ users | minBy:'age' }}\u003c/p\u003e \u003c!-- Output: \"{ name: 'Alice', age: 20 }\" --\u003e\n\u003cp\u003e{{ games | minBy:'price' }}\u003c/p\u003e \u003c!-- Output: \"{ name: 'Mass Effect 1', price: 30 }\" --\u003e\n```\n\n#### Max by\n\nReturns the item with the largest value of an array of object based on one of their `number`, parsable `string` or `Date` property\n\n```typescript\nconst users = [\n  { name: 'Alice', age: 20 },\n  { name: 'Bob', age: 30 },\n]\nconst games = [\n  { name: 'Mass Effect 1', price: 30 }\n  { name: 'Mass Effect Andromeda', price: 40 }\n]\n```\n```html\n\u003cp\u003e{{ users | maxBy:'age' }}\u003c/p\u003e \u003c!-- Output: \"{ name: 'Bob', age: 30 }\" --\u003e\n\u003cp\u003e{{ games | maxBy:'price' }}\u003c/p\u003e \u003c!-- Output: \"{ name: 'Mass Effect Andromeda', price: 40 }\" --\u003e\n```\n\n## Contributing\n\n- Any contribution is appreciated\n- If you are planning to add a new pipe (or any new other feature) or make a fix, please open an issue before\n- Follow the [conventional commit message format](https://www.conventionalcommits.org/en/v1.0.0/)\n\n1. Clone the project\n\n```bash\n$ git clone https://github.com/SlyTed/ngx-pipes-toolkit.git\n```\n\n2. Install the dependencies\n\n```bash\n$ npm install\n```\n\n3. Make your changes in a new branch\n\n```bash\n$ git checkout -b \u003cmy-branch\u003e\n```\n\n4. Add appropriate tests (cover all cases) and make sure everything is running properly (don't forget to lint)\n\n```bash\n$ npm run test:coverage\n$ npm run lint\n```\n\n5. Push your branch\n\n6. Make a pull request\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSlyTed%2Fngx-pipes-toolkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSlyTed%2Fngx-pipes-toolkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSlyTed%2Fngx-pipes-toolkit/lists"}