Skip to content

Instantly share code, notes, and snippets.

@Heydon
Created July 23, 2018 14:09
Show Gist options
  • Star 41 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save Heydon/9de1a8b55dd1448281fad013503a5b7a to your computer and use it in GitHub Desktop.
Save Heydon/9de1a8b55dd1448281fad013503a5b7a to your computer and use it in GitHub Desktop.
function Mutilator(data, name, context) {
this.n = name || `mutilation-${+new Date()}`;
this.d = data;
this.c = context || window;
this.isArr = function(p) {
return this.d[p].constructor == Array;
};
this.dispatch = function(p, v, t) {
this.c.dispatchEvent(
new CustomEvent(this.n, {
detail: {
prop: p,
val: v,
type: t
}
})
);
};
}
Mutilator.prototype = {
change: function(p, v) {
this.d[p] = v;
this.dispatch(p, v, "change");
},
add: function(p, v) {
this.isArr(p) ? this.d[p].push(v) : (this.d[p] = [this.d[p], v]);
this.dispatch(p, v, "add");
},
remove: function(p, v) {
!this.isArr(p) ? delete this.d[p] : this.d[p].splice(v, 1);
this.dispatch(p, p[v], "remove");
},
recoil: function(f, r) {
this.c.addEventListener(this.n, e => {
if (!r || r.some(p => e.detail.prop.indexOf(p) > -1)) {
return f(e, this.d);
}
});
}
};
export default Mutilator;
@Heydon
Copy link
Author

Heydon commented Jul 23, 2018

Working on a small 1D object reactive store, with array methods. Uses CustomEvent.

You mutilate the data, then recoil in horror.

For recoil functions, you can set which property changes are relevant. E.g. you can listen to just the list and string properties:

const mutilator = new Mutilator({
  string: 'foo',
  list: [1,2,3],
  ignored: 'bla'
})

mutilator.recoil((e, d) => {
   console.log(e.detail.type) // the type of mutilation (change, add, or remove)
   console.log(e.detail.prop) // which property was changed
   console.log(e.detail.val) // the new value for the changed property
}, ['list', 'string'])

@Heydon
Copy link
Author

Heydon commented Jul 24, 2018

Here's a version that just uses getters/setters:

function mutilator(obj, name = "mutilated", context = window) {
  const mutilated = {};
  for (let prop in obj) {
    let ref = `m-${prop}`;
    mutilated[ref] = obj[prop];
    Object.defineProperty(mutilated, prop, {
      set: function(v) {
        this[ref] = v;
        context.dispatchEvent(
          new CustomEvent(`${name}:${prop}`, {
            detail: { prop: prop, value: v }
          })
        );
      },
      get: function() {
        return this[ref];
      }
    });
  }
  return mutilated;
}

Initialize

const mutable = mutilator({
  string: 'foo'
  num: 6
})

Listening to events

If you set mutable.string = 'bar', the event mutilated:string is emitted (on window by default).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment