diff --git a/README.md b/README.md index 0baa25db..b5018e10 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,9 @@ - [every](#every) - [some](#some) - [sample](#sample) + - [groupBy](#groupBy) + - [keys](#keys) + - [values](#values) - [Math](#Math) - [min](#min) - [max](#max) @@ -519,6 +522,48 @@ API: `array | sample: [amount | default = 1]`

{{ [1, 2, 3, 4] | sample: 2 }}

``` +### groupBy + +Returns object of grouped by items by discriminator + +API: `array | groupBy: [string | Function]` + +```javascript +import {GroupByPipe} from 'ng2-pipes/src/app/pipes/array/group-by'; + +@Component({ + // ... + providers: [GroupByPipe] +}) +export class AppComponent { + constructor(private groupByPipe: GroupByPipe) { + // .. + const arrayObject = [{elm: 'foo', value: 0}, {elm: 'bar', value: 1}, {elm: 'foo', value: 2}]; + const groupedObject = groupByPipe.transform(arrayObject, 'elm')); + // `groupedObject` -> Contains: {foo: [{elm: 'foo', value: 0}, {elm: 'foo', value: 2}], bar: [{elm: 'bar', value: 1}]} + } +``` + +### keys + +Returns array of object keys + +API: `object | keys` + +```html +

{{ {foo: 1, bar: 2} | keys }}

+``` + +### values + +Returns array of object values + +API: `object | values` + +```html +

{{ {foo: 1, bar: 2} | values }}

+``` + ## Math ### min diff --git a/src/app/pipes/array/group-by.spec.ts b/src/app/pipes/array/group-by.spec.ts new file mode 100644 index 00000000..c768598f --- /dev/null +++ b/src/app/pipes/array/group-by.spec.ts @@ -0,0 +1,39 @@ +import {GroupByPipe} from './group-by'; + +describe('GroupByPipe', () => { + let pipe: GroupByPipe; + + beforeEach(() => { + pipe = new GroupByPipe(); + }); + + + it('should create an instance', () => { + expect(pipe).toBeTruthy(); + }); + + it('should not change anything if not array', () => { + expect(pipe.transform('foo')).toEqual('foo'); + expect(pipe.transform(null)).toEqual(null); + expect(pipe.transform(undefined)).toEqual(undefined); + expect(pipe.transform(42)).toEqual(42); + expect(pipe.transform({foo: 1, bar: 2})).toEqual({foo: 1, bar: 2}); + }); + + it('group on discriminator', () => { + const arrayWithDiscriminator = [{key: 'foo'}, {key: 'bar'}, {key: 'foo'}, {key: 'bar'}]; + const result = pipe.transform(arrayWithDiscriminator, 'key'); + expect(result).toEqual({ + foo: [{key: 'foo'}, {key: 'foo'}], + bar: [{key: 'bar'}, {key: 'bar'}] + }); + }); + it('allow function to be used as discriminator', () => { + const arrayWithDiscriminator = [{key: 'foo'}, {key: 'bar'}, {key: 'foo'}, {key: 'bar'}]; + const result = pipe.transform(arrayWithDiscriminator, _ => _['key']); + expect(result).toEqual({ + foo: [{key: 'foo'}, {key: 'foo'}], + bar: [{key: 'bar'}, {key: 'bar'}] + }); + }); +}); diff --git a/src/app/pipes/array/group-by.ts b/src/app/pipes/array/group-by.ts new file mode 100644 index 00000000..6bb37f2c --- /dev/null +++ b/src/app/pipes/array/group-by.ts @@ -0,0 +1,26 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import GeneralHelper from '../helpers/helpers'; + +@Pipe({name: 'groupBy'}) +export class GroupByPipe implements PipeTransform { + + transform(arr: any, ...args: any[]): any { + if (!Array.isArray(arr)) { + return arr; + } + + return this.groupBy(arr, args[0]); + } + + private groupBy(list: any[], discriminator: Function | string) { + return list.reduce((acc, payload) => { + const key = GeneralHelper.isFunction(discriminator) + ? (discriminator)(payload) + : payload[discriminator]; + + return acc[key] = Array.isArray(acc[key]) + ? acc[key].concat([payload]) + : [payload], acc; + }, {}); + } +} diff --git a/src/app/pipes/array/groupBy.spec.ts b/src/app/pipes/array/groupBy.spec.ts deleted file mode 100644 index 3616f220..00000000 --- a/src/app/pipes/array/groupBy.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { GroupByPipe } from './groupBy'; - -describe('Pipe: GroupBy', () => { - it('create an instance', () => { - let pipe = new GroupByPipe(); - expect(pipe).toBeTruthy(); - }); - -}); -describe('GroupByPipe', () => { - let pipe: GroupByPipe; - - beforeEach(() => { - pipe = new GroupByPipe(); - }); - - it('should not change anything if not array', () => { - expect(pipe.transform('foo')).toEqual('foo'); - expect(pipe.transform(null)).toEqual(null); - expect(pipe.transform(undefined)).toEqual(undefined); - expect(pipe.transform(42)).toEqual(42); - expect(pipe.transform({ foo: 1, bar: 2 })).toEqual({ foo: 1, bar: 2 }); - }); - - it('group on discriminator', () => { - let arrayWithDiscriminator = [ - { - key: 'value0' - }, - { - key: 'value1' - }, - { - key: 'value0' - }, - { - key: 'value1' - } - ]; - let result = pipe.transform(arrayWithDiscriminator, 'key'); - expect(result).toEqual([ [ 'value0', [ { key: 'value0' }, { key: 'value0' }] ], [ 'value1', [ { key: 'value1' }, { key: 'value1' }] ] ]); - }); - it('allow function to be used as discriminator', () => { - let arrayWithDiscriminator = [ - { - key: 'value0' - }, - { - key: 'value1' - }, - { - key: 'value0' - }, - { - key: 'value1' - } - ]; - let result = pipe.transform(arrayWithDiscriminator, (instance: any) => { return instance[ 'key' ] }); - expect(result).toEqual([ [ 'value0', [ { key: 'value0' }, { key: 'value0' }] ], [ 'value1', [ { key: 'value1' }, { key: 'value1' }] ] ]); - }); -}); diff --git a/src/app/pipes/array/groupBy.ts b/src/app/pipes/array/groupBy.ts deleted file mode 100644 index 99ca52f6..00000000 --- a/src/app/pipes/array/groupBy.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'groupBy' -}) -export class GroupByPipe implements PipeTransform { - groupBy = (list: any[], discriminator: Function | string) => { - let map = list.reduce((acc, payload, i) => { - let key = discriminator instanceof Function ? discriminator(payload) : payload[ discriminator ]; - return Object.assign({}, acc, { - [ key ]: acc[ key ] instanceof Array ? acc[ key ].concat([ payload ]) : [ payload ] - }); - }, {}); - return Object.keys(map).map((key: string) => [ key, map[ key ] ]); - } - transform(arr: any, ...args: any[]): any { - if (!Array.isArray(arr)) { - return arr; - } - return this.groupBy(arr, args[ 0 ]); - } - -} \ No newline at end of file diff --git a/src/app/pipes/array/index.ts b/src/app/pipes/array/index.ts index 6fc10c08..60cad2d2 100644 --- a/src/app/pipes/array/index.ts +++ b/src/app/pipes/array/index.ts @@ -13,13 +13,15 @@ import { ShufflePipe } from './shuffle'; import { EveryPipe } from './every'; import { SomePipe } from './some'; import { SamplePipe } from './sample'; -import { GroupByPipe } from './groupBy'; +import { GroupByPipe } from './group-by'; +import { KeysPipe } from './keys'; +import { ValuesPipe } from './values'; import { NgModule } from '@angular/core'; const ARRAY_PIPES = [ DiffPipe, FlattenPipe, InitialPipe, IntersectionPipe, ReversePipe, TailPipe, TrurthifyPipe, UnionPipe, UniquePipe, WithoutPipe, PluckPipe, ShufflePipe, - EveryPipe, SomePipe, SamplePipe, GroupByPipe + EveryPipe, SomePipe, SamplePipe, GroupByPipe, KeysPipe, ValuesPipe ]; @NgModule({ @@ -44,4 +46,6 @@ export * from './shuffle'; export * from './every'; export * from './some'; export * from './sample'; -export * from './groupBy'; +export * from './keys'; +export * from './values'; +export * from './group-by'; diff --git a/src/app/pipes/array/keys.spec.ts b/src/app/pipes/array/keys.spec.ts new file mode 100644 index 00000000..4674d7b4 --- /dev/null +++ b/src/app/pipes/array/keys.spec.ts @@ -0,0 +1,23 @@ +import {KeysPipe} from './keys'; + +describe('Keys Pipe', () => { + let pipe: KeysPipe; + + beforeEach(() => { + pipe = new KeysPipe(); + }); + + it('should keep the element the same way if its not an object', () => { + expect(pipe.transform([1, 2, 3])).toEqual([1, 2, 3]); + expect(pipe.transform([])).toEqual([]); + expect(pipe.transform('foo')).toEqual('foo'); + expect(pipe.transform(null)).toEqual(null); + expect(pipe.transform(undefined)).toEqual(undefined); + }); + + it('should return array of keys', () => { + expect(pipe.transform({})).toEqual([]); + expect(pipe.transform({foo: 'bar'})).toEqual(['foo']); + expect(pipe.transform({foo: 1, bar: 42})).toEqual(['foo', 'bar']); + }); +}); diff --git a/src/app/pipes/array/keys.ts b/src/app/pipes/array/keys.ts new file mode 100644 index 00000000..c52a3b1c --- /dev/null +++ b/src/app/pipes/array/keys.ts @@ -0,0 +1,14 @@ +import {PipeTransform, Pipe} from '@angular/core'; +import GeneralHelper from '../helpers/helpers'; + +@Pipe({name: 'keys'}) +export class KeysPipe implements PipeTransform { + + transform(obj: any): any[] { + if (Array.isArray(obj) || !GeneralHelper.isObject(obj)) { + return obj; + } + + return Object.keys(obj); + } +} diff --git a/src/app/pipes/array/values.spec.ts b/src/app/pipes/array/values.spec.ts new file mode 100644 index 00000000..6a53f242 --- /dev/null +++ b/src/app/pipes/array/values.spec.ts @@ -0,0 +1,23 @@ +import {ValuesPipe} from './values'; + +describe('Values Pipe', () => { + let pipe: ValuesPipe; + + beforeEach(() => { + pipe = new ValuesPipe(); + }); + + it('should keep the element the same way if its not an object', () => { + expect(pipe.transform([1, 2, 3])).toEqual([1, 2, 3]); + expect(pipe.transform([])).toEqual([]); + expect(pipe.transform('foo')).toEqual('foo'); + expect(pipe.transform(null)).toEqual(null); + expect(pipe.transform(undefined)).toEqual(undefined); + }); + + it('should return array of values', () => { + expect(pipe.transform({})).toEqual([]); + expect(pipe.transform({foo: 'bar'})).toEqual(['bar']); + expect(pipe.transform({foo: 1, bar: 42})).toEqual([1, 42]); + }); +}); diff --git a/src/app/pipes/array/values.ts b/src/app/pipes/array/values.ts new file mode 100644 index 00000000..5ef9feb4 --- /dev/null +++ b/src/app/pipes/array/values.ts @@ -0,0 +1,14 @@ +import {PipeTransform, Pipe} from '@angular/core'; +import GeneralHelper from '../helpers/helpers'; + +@Pipe({name: 'values'}) +export class ValuesPipe implements PipeTransform { + + transform(obj: any): any[] { + if (Array.isArray(obj) || !GeneralHelper.isObject(obj)) { + return obj; + } + + return Object.keys(obj).map(k => obj[k]); + } +} diff --git a/src/app/pipes/helpers/helpers.ts b/src/app/pipes/helpers/helpers.ts index 3b2e6f87..ef659e72 100644 --- a/src/app/pipes/helpers/helpers.ts +++ b/src/app/pipes/helpers/helpers.ts @@ -1,9 +1,13 @@ export default class GeneralHelper { - static isUndefined(value) { + static isUndefined(value: any) { return typeof value === 'undefined'; } + static isFunction(value: any) { + return typeof value === 'function'; + } + static isNumber(value: any) { return typeof value === 'number'; } @@ -12,6 +16,10 @@ export default class GeneralHelper { return typeof value === 'string'; } + static isObject(value: any) { + return value !== null && typeof value === 'object'; + } + static isNumberFinite(value: any) { return GeneralHelper.isNumber(value) && isFinite(value); }