Last active
September 8, 2019 14:33
-
-
Save tohagan/9d44d39dc4e9538aec4aa0c49404fae8 to your computer and use it in GitHub Desktop.
Get / Set / Delete / Toggle / Increment Object Properties - VueJS Reactive Objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Vue from "vue"; | |
function getProp(obj, props) { | |
let val = obj; | |
let i = 0; | |
for (i = 0; i < props.length - 1; i++) { | |
val = val[props[i]]; | |
if (typeof val !== "object") return undefined; | |
} | |
return val[props[i]]; | |
} | |
function setProp(obj, props, value) { | |
let val = obj; | |
let i = 0; | |
for (i = 0; i < props.length - 1; i++) { | |
if (typeof val[props[i]] !== "object") { | |
Vue.set(val, props[i], {}); | |
} | |
val = val[props[i]]; | |
} | |
Vue.set(val, props[i], value); | |
} | |
function deleteProp(obj, props) { | |
let val = obj; | |
let i = 0; | |
for (i = 0; i < props.length - 1; i++) { | |
val = val[props[i]]; | |
if (typeof val !== "object") return; | |
} | |
Vue.delete(val, props[i]); | |
} | |
function toggleProp(obj, props, defaultValue = true) { | |
if (getProp(obj, props)) { | |
deleteProp(obj, props); | |
} else { | |
setProp(obj, props, defaultValue); | |
} | |
} | |
// Warning - Unsafe if you need this to be transational | |
function incrementProp(obj, props) { | |
const num = getProp(obj, props) || 0; | |
setProp(obj, props, num + 1); | |
} | |
export { getProp, setProp, deleteProp, toggleProp, incrementProp }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import "jest"; | |
import { getProp, setProp, deleteProp, toggleProp, incrementProp } from "src/util/props"; | |
describe("props.", () => { | |
let objJson = JSON.stringify({ a: { b: 1, d: { e: 4 } }, c: 2 }); | |
let obj1, obj2; | |
beforeEach(() => { | |
obj1 = JSON.parse(objJson); | |
obj2 = JSON.parse(objJson); | |
}); | |
describe("getProp", () => { | |
it("should return undefined when path is undefined", () => { | |
expect(getProp(obj1, ["b"])).toBeUndefined(); | |
expect(getProp(obj1, ["a", "c"])).toBeUndefined(); | |
}); | |
it("should return value when path is defined", () => { | |
expect(getProp(obj1, ["c"])).toBe(2); | |
expect(getProp(obj1, ["a", "b"])).toBe(1); | |
}); | |
it("should not alter object when all of path is undefined", () => { | |
expect(getProp(obj1, ["b"])).toBeUndefined(); | |
expect(obj1).toEqual(obj2); | |
}); | |
it("should not alter object when some of path is undefined", () => { | |
expect(getProp(obj1, ["a", "c"])).toBeUndefined(); | |
expect(obj1).toEqual(obj2); | |
}); | |
it("getProp should not alter path array", () => { | |
const path = ["a", "c"]; | |
const pathCopy = [...path]; | |
expect(getProp(obj1, path)).toBeUndefined(); | |
expect(path).toEqual(pathCopy); | |
}); | |
}); | |
describe("setProp", () => { | |
it("should updated an existing property", () => { | |
setProp(obj1, ["a", "b"], 12); | |
obj2.a.b = 12; | |
expect(obj1).toEqual(obj2); | |
}); | |
it("should add a missing property", () => { | |
setProp(obj1, ["b"], 12); | |
obj2.b = 12; | |
expect(obj1).toEqual(obj2); | |
}); | |
it("should add missing partial path and property", () => { | |
setProp(obj1, ["a", "d", "f", "g", "h"], 12); | |
obj2.a.d.f = { g: { h: 12 } }; | |
// console.log(JSON.stringify(obj1)); | |
expect(obj1).toEqual(obj2); | |
}); | |
it("setProp should not alter path array", () => { | |
const path = ["a", "c"]; | |
const pathCopy = [...path]; | |
expect(setProp(obj1, path, "xx")).toBeUndefined(); | |
expect(path).toEqual(pathCopy); | |
}); | |
}); | |
describe("deleteProp", () => { | |
it("should remove an existing property", () => { | |
expect(getProp(obj1, ["a", "b"])).toBeDefined(); | |
deleteProp(obj1, ["a", "b"]); | |
expect(getProp(obj1, ["a", "b"])).toBeUndefined(); | |
delete obj2.a.b; | |
expect(obj1).toEqual(obj2); | |
}); | |
it("should no change for a missing property", () => { | |
deleteProp(obj1, ["b"]); | |
expect(obj1).toEqual(obj2); | |
}); | |
it("should no change deep missing", () => { | |
deleteProp(obj1, ["a", "d", "f", "g", "h"]); | |
expect(obj1).toEqual(obj2); | |
}); | |
it("deleteProp should not alter path array", () => { | |
const path = ["a", "c"]; | |
const pathCopy = [...path]; | |
expect(deleteProp(obj1, path, "xx")).toBeUndefined(); | |
expect(path).toEqual(pathCopy); | |
}); | |
}); | |
// { a: { b: 1, d: { e: 4 } }, c: 2 } | |
describe("toggleProp", () => { | |
it("toggle existing prop", () => { | |
expect(getProp(obj1, ["a", "b"])).toBeDefined(); | |
toggleProp(obj1, ["a", "b"]); | |
delete obj2.a.b; | |
expect(obj1).toEqual(obj2); | |
expect(getProp(obj1, ["a", "b"])).toBeUndefined(); | |
toggleProp(obj1, ["a", "b"]); | |
expect(getProp(obj1, ["a", "b"])).toBeDefined(); | |
}); | |
it("should toggle missing partial path and property", () => { | |
const path = ["a", "d", "f", "g", "h"]; | |
expect(getProp(obj1, path)).toBeUndefined(); | |
toggleProp(obj1, path); | |
obj2.a.d.f = { g: { h: true } }; | |
expect(obj1).toEqual(obj2); | |
expect(getProp(obj1, path)).toBeDefined(); | |
toggleProp(obj1, path); | |
expect(getProp(obj1, path)).toBeUndefined(); | |
// won't completely reset back to obj1 | |
obj2 = JSON.parse(objJson); | |
obj2.a.d.f = { g: {} }; | |
expect(obj1).toEqual(obj2); | |
}); | |
it("toggleProp should not alter path array", () => { | |
const path = ["a", "c"]; | |
const pathCopy = [...path]; | |
expect(toggleProp(obj1, path, "xx")).toBeUndefined(); | |
expect(path).toEqual(pathCopy); | |
}); | |
}); | |
describe('incrementProp', () => { | |
it('should increment existing prop', () => { | |
expect(getProp(obj1, ["a", "b"])).toBe(1); | |
incrementProp(obj1, ["a", "b"]); | |
expect(getProp(obj1, ["a", "b"])).toBe(2); | |
incrementProp(obj1, ["a", "b"]); | |
expect(getProp(obj1, ["a", "b"])).toBe(3); | |
obj2.a.b = 3; | |
expect(obj1).toEqual(obj2); | |
}); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Revised to ensure
props
path is isomorphic. Add Jest test suite