{"id":582,"date":"2016-04-18T13:44:53","date_gmt":"2016-04-18T19:44:53","guid":{"rendered":"http:\/\/blog.the-erm.com\/?p=582"},"modified":"2016-04-18T13:49:01","modified_gmt":"2016-04-18T19:49:01","slug":"dirty-detection-of-a-multi-dimentional-javascript-object","status":"publish","type":"post","link":"https:\/\/blog.the-erm.com\/?p=582","title":{"rendered":"Dirty detection of a multi-dimentional javascript object"},"content":{"rendered":"<p>I&#8217;m not sure what to call this.\u00c2\u00a0 It&#8217;s a proxy handler that watches the <code>dirty<\/code> state of an object.\u00c2\u00a0 I don&#8217;t know why, but I&#8217;m kinda proud of this.\u00c2\u00a0 It also has the ability to ignore fields.\u00c2\u00a0 The main goal is to have a mechanism to indicate if you should save an object or not.\u00c2\u00a0 In other words:<\/p>\n<p><code>if (obj.dirty) { save(obj); }<\/code><\/p>\n<pre>window.objHandler = {\r\n    dirty: false,\r\n    ignore: [],\r\n    get: function(target, name) {\r\n        if (name != \"dirty\" &amp;&amp; name != \"ignore\") {\r\n            return name in target ? target[name] : undefined;\r\n        }\r\n        if (name == \"ignore\") {\r\n            return this.ignore;\r\n        }\r\n        if (name == \"dirty\") {\r\n            \/\/ console.log(\"get dirty:\", target);\r\n            if (this.dirty) {\r\n                return true;\r\n            }\r\n            if (typeof target == \"object\") {\r\n                if (target.dirty) {\r\n                    return true;\r\n                }\r\n                for (k in target) {\r\n                  if (typeof target[k] == \"object\" &amp;&amp; target[k].dirty) {\r\n                      return true;\r\n                  }\r\n                }\r\n            }\r\n            return this.dirty;\r\n        }\r\n        return undefined;\r\n    },\r\n    set: function(target, name, value) {\r\n        if (name == \"dirty\") {\r\n            this.dirty = value;\r\n            if (typeof target == \"object\") {\r\n                for (k in target) {\r\n                    if (typeof target[k] == \"object\") {\r\n                        target[k].dirty = value;\r\n                    }\r\n                }\r\n            }\r\n            return;\r\n        }\r\n        if (name == \"ignore\") {\r\n            this.ignore = value;\r\n            return;\r\n        }\r\n        if (angular.equals(target[name], value)) {\r\n            return;\r\n        }\r\n        if (this.ignore.indexOf(name) == -1) {\r\n            this.dirty = true;\r\n        }\r\n        var _type = typeof value;\r\n        if (_type == \"object\") {\r\n            \/\/ console.log(\"making proxy:\", value);\r\n            value = new Proxy(value, window.objHandler);\r\n            value.dirty = true;\r\n        }\r\n        target[name] = value;\r\n    }\r\n};\r\n\r\nvar p = new Proxy({}, window.objHandler);\r\np.obj = {\"foo\":\"bar\"};\r\nif (!p.dirty) {\r\n    console.log(\"FAIL\", \"!p.dirty\", \"p should be dirty because obj was set\");\r\n}\r\nif (!p.obj.dirty) {\r\n    console.log(\"FAIL\", \"!p.obj.dirty\", \"p.obj should be dirty because it's new?\");\r\n}\r\np.obj.dirty = false;\r\nif (p.obj.dirty) {\r\n    console.log(\"FAIL\", \"p.obj.dirty\", \"Shouldn't be dirty because p.obj.dirty = false;\");\r\n}\r\nif (p.dirty) {\r\n    console.log(\"FAIL\", \"p.dirty\", \"Should still be dirty p.obj.dirty = false;\");\r\n}\r\np.dirty = false;\r\nif (p.dirty) {\r\n    console.log(\"FAIL\", \"p.dirty\", \"Should be clean\");\r\n}\r\np.obj.foo = \"baz\";\r\nif(!p.dirty) {\r\n    console.log(\"FAIL\", \"p.dirty should be true\");\r\n}\r\n\r\nif (!p.obj.dirty) {\r\n    console.log(\"FAIL\", \"p.obj.dirty should be true\");\r\n}\r\np.dirty = false;\r\nif(p.obj.dirty) {\r\n    console.log(\"FAIL\", \"p.obj.dirty should not be dirty\");\r\n}\r\n\r\n\r\n\r\nconsole.log(\"p.dirty:\",p.dirty);\r\nconsole.log(\"p.obj.dirty\", p.obj.dirty);\r\np.str = \"string value\";\r\np.integer = 1;\r\np.dec = 1.1;\r\nconsole.log(JSON.stringify(p,null, \"\\t\"));\r\nconsole.log(\"p.dirty\", p.dirty);\r\np.dirty = false;\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h1>Output:<\/h1>\n<div class=\"logRow logRow-log \">\n<div class=\" \">\n<pre class=\"objectBox inline objectBox-text \"><span class=\"objectBox objectBox-text \">p.dirty:<\/span> <span class=\"objectBox objectBox-number \">false\r\n<\/span><span class=\"objectBox objectBox-text \">p.obj.dirty<\/span> <span class=\"objectBox objectBox-number \">false\r\n<\/span>{\r\n\t\"obj\": {\r\n\t\t\"foo\": \"baz\"\r\n\t},\r\n\t\"str\": \"string value\",\r\n\t\"integer\": 1,\r\n\t\"dec\": 1.1\r\n}\r\n<span class=\"objectBox objectBox-text \">p.dirty<\/span> <span class=\"objectBox objectBox-number \">true<\/span><\/pre>\n<\/div>\n<\/div>\n<div class=\"logRow \"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;m not sure what to call this.\u00c2\u00a0 It&#8217;s a proxy handler that watches the dirty state of an object.\u00c2\u00a0 I don&#8217;t know why, but I&#8217;m kinda proud of this.\u00c2\u00a0 It also has the ability to ignore fields.\u00c2\u00a0 The main goal is to have a mechanism to indicate if you should save an object or not.\u00c2\u00a0 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[119],"tags":[],"class_list":["post-582","post","type-post","status-publish","format-standard","hentry","category-dev"],"_links":{"self":[{"href":"https:\/\/blog.the-erm.com\/index.php?rest_route=\/wp\/v2\/posts\/582","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.the-erm.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.the-erm.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.the-erm.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.the-erm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=582"}],"version-history":[{"count":2,"href":"https:\/\/blog.the-erm.com\/index.php?rest_route=\/wp\/v2\/posts\/582\/revisions"}],"predecessor-version":[{"id":584,"href":"https:\/\/blog.the-erm.com\/index.php?rest_route=\/wp\/v2\/posts\/582\/revisions\/584"}],"wp:attachment":[{"href":"https:\/\/blog.the-erm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=582"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.the-erm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=582"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.the-erm.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=582"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}