From 1aa1f457d15efb0ffefffca223ec0a395eaf4ce5 Mon Sep 17 00:00:00 2001 From: danrevah Date: Thu, 9 Mar 2017 17:53:59 +0200 Subject: [PATCH] feat(Object): Add diffObj Pipe --- README.md | 14 +++++++++++++ package.json | 2 +- src/app/pipes/helpers/helpers.spec.ts | 12 ++++++++++- src/app/pipes/helpers/helpers.ts | 21 +++++++++++++++++++ src/app/pipes/object/diff-obj.spec.ts | 30 +++++++++++++++++++++++++++ src/app/pipes/object/diff-obj.ts | 16 ++++++++++++++ src/app/pipes/object/index.ts | 7 ++++--- 7 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 src/app/pipes/object/diff-obj.spec.ts create mode 100644 src/app/pipes/object/diff-obj.ts diff --git a/README.md b/README.md index cc42c758..6fd4449f 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ - [omit](#omit) - [invert](#invert) - [invertBy](#invertby) + - [diffObj](#diffobj) - [Math](#math) - [min](#min) - [max](#max) @@ -771,6 +772,19 @@ this.cb = (value): string => {

{{ {a: 1, b: 2, c: 1, d: 2} | invertBy }}

``` +### diffObj + +Returns a diff object of two objects + +**Usage:** `object | diffObj: Object` + +```html +

{{ {a: 1} | diffObj: {a: 1} }}

+

{{ {a: 1} | diffObj: {a: 2} }}

+

{{ {a: 1, b: 2} | diffObj: {a: 1, b: 1} }}

+

{{ {a: 1, b: 2, c: {d: 3} } | diffObj: {a: 1, b: 1, c: {d: 1} } }}

+``` + ## Math ### min diff --git a/package.json b/package.json index c98c126b..fcbd2ef6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ngx-pipes", - "version": "1.4.5", + "version": "1.4.6", "author": "Dan Revah", "description": "Useful angular2 pipes", "license": "MIT", diff --git a/src/app/pipes/helpers/helpers.spec.ts b/src/app/pipes/helpers/helpers.spec.ts index 6c55b09f..356f9bd9 100644 --- a/src/app/pipes/helpers/helpers.spec.ts +++ b/src/app/pipes/helpers/helpers.spec.ts @@ -1,5 +1,5 @@ -import {extractDeepPropertyByMapKey} from './helpers'; +import {extractDeepPropertyByMapKey, isDeepEqual} from './helpers'; describe('Utils Tests', () => { @@ -32,4 +32,14 @@ describe('Utils Tests', () => { expect(extractDeepPropertyByMapKey(obj, 'f.i.j.k.l')).toEqual(6); expect(extractDeepPropertyByMapKey(obj, 'f.i.j.k.l.')).toEqual(undefined); }); + + it('should deep equal properly', () => { + expect(isDeepEqual({a: 1}, {a: 1})).toBeTruthy(); + expect(isDeepEqual({a: 1}, {b: 1})).toBeFalsy(); + expect(isDeepEqual({a: 1}, {a: 1, b: 1})).toBeFalsy(); + expect(isDeepEqual({a: 1, b: 2}, {a: 1, b: 2})).toBeTruthy(); + expect(isDeepEqual({a: 1, b: 2}, {a: 1, b: 1})).toBeFalsy(); + expect(isDeepEqual({a: 1, b: 2, c: {d: 3}}, {a: 1, b: 2, c: {d: 1}})).toBeFalsy(); + expect(isDeepEqual({a: 1, b: 2, c: {d: 3}}, {a: 1, b: 2, c: {d: 3}})).toBeTruthy(); + }); }); diff --git a/src/app/pipes/helpers/helpers.ts b/src/app/pipes/helpers/helpers.ts index c33a0778..d75e640a 100644 --- a/src/app/pipes/helpers/helpers.ts +++ b/src/app/pipes/helpers/helpers.ts @@ -38,3 +38,24 @@ export function extractDeepPropertyByMapKey(obj: any, map: string): any { : undefined; }, obj[key || '']); } + +export function getKeysTwoObjects(obj: any, other: any): any { + return [...Object.keys(obj), ...Object.keys(other)] + .filter((key, index, array) => array.indexOf(key) === index); +} + +export function isDeepEqual(obj: any, other: any): any { + if (!isObject(obj) || !isObject(other)) { + return obj === other; + } + + return getKeysTwoObjects(obj, other).every((key: any): boolean => { + if (!isObject(obj[key]) && !isObject(other[key])) { + return obj[key] === other[key]; + } + if (!isObject(obj[key]) || !isObject(other[key])) { + return false; + } + return isDeepEqual(obj[key], other[key]); + }); +} diff --git a/src/app/pipes/object/diff-obj.spec.ts b/src/app/pipes/object/diff-obj.spec.ts new file mode 100644 index 00000000..43deb137 --- /dev/null +++ b/src/app/pipes/object/diff-obj.spec.ts @@ -0,0 +1,30 @@ +import {DiffObjPipe} from './diff-obj'; + +describe('DiffObj Pipe', () => { + let pipe: DiffObjPipe; + + beforeEach(() => { + pipe = new DiffObjPipe(); + }); + + it('should keep the element the same way if its not an object', () => { + expect(pipe.transform([1, 2, 3], {})).toEqual({}); + expect(pipe.transform([], {})).toEqual({}); + expect(pipe.transform('foo', {})).toEqual({}); + expect(pipe.transform(null, {})).toEqual({}); + expect(pipe.transform(undefined, {})).toEqual({}); + }); + + it('should return an empty object when there is no difference', () => { + expect(pipe.transform({}, {})).toEqual({}); + expect(pipe.transform({a: 1}, {a: 1})).toEqual({}); + expect(pipe.transform({a: {b: 1}, c: 3}, {a: {b: 1}, c: 3})).toEqual({}); + }); + + it('should return a diff object', () => { + expect(pipe.transform({a: 1}, {a: 2})).toEqual({a: 1}); + expect(pipe.transform({a: 1, b: 1}, {a: 1, b: 2})).toEqual({b: 1}); + expect(pipe.transform({a: 1, b: true}, {a: 1, b: 2})).toEqual({b: true}); + expect(pipe.transform({a: 1, b: {c: 1}}, {a: 1, b: {c: 2}})).toEqual({b: {c: 1}}); + }); +}); diff --git a/src/app/pipes/object/diff-obj.ts b/src/app/pipes/object/diff-obj.ts new file mode 100644 index 00000000..bec02815 --- /dev/null +++ b/src/app/pipes/object/diff-obj.ts @@ -0,0 +1,16 @@ +import {PipeTransform, Pipe} from '@angular/core'; +import {isObject, getKeysTwoObjects, isDeepEqual} from '../helpers/helpers'; + +@Pipe({name: 'diffObj'}) +export class DiffObjPipe implements PipeTransform { + + transform(obj: any, original: any = {}): any { + if (Array.isArray(obj) || Array.isArray(original) || !isObject(obj) || !isObject(original)) { + return {}; + } + + return getKeysTwoObjects(obj, original).reduce((diff: any, key: any) => { + return (!isDeepEqual(original[key], obj[key]) ? diff[key] = obj[key] : {}), diff; + }, {}); + } +} diff --git a/src/app/pipes/object/index.ts b/src/app/pipes/object/index.ts index bdc31e99..7093456f 100644 --- a/src/app/pipes/object/index.ts +++ b/src/app/pipes/object/index.ts @@ -5,11 +5,12 @@ import {PickPipe} from './pick'; import {OmitPipe} from './omit'; import {InvertPipe} from './invert'; import {InvertByPipe} from './invert-by'; +import {DiffObjPipe} from './diff-obj'; import {NgModule} from '@angular/core'; const OBJECT_PIPES = [ KeysPipe, ValuesPipe, PairsPipe, PickPipe, InvertPipe, InvertByPipe, - OmitPipe + OmitPipe, DiffObjPipe ]; @NgModule({ @@ -17,8 +18,7 @@ const OBJECT_PIPES = [ imports: [], exports: OBJECT_PIPES }) -export class NgObjectPipesModule { -} +export class NgObjectPipesModule {} export {KeysPipe} from './keys'; export {ValuesPipe} from './values'; @@ -27,3 +27,4 @@ export {PickPipe} from './pick'; export {OmitPipe} from './omit'; export {InvertPipe} from './invert'; export {InvertByPipe} from './invert-by'; +export {DiffObjPipe} from './diff-obj';