Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Listen for changes to specific paths #18

Closed
torgeir opened this issue Dec 19, 2014 · 7 comments
Closed

Listen for changes to specific paths #18

torgeir opened this issue Dec 19, 2014 · 7 comments

Comments

@torgeir
Copy link
Member

torgeir commented Dec 19, 2014

We can easily add listeners to when specific pieces of data inside a structure changes.

Of course, you can aldready do

structure.on('change', (path, _, _) => {
  if (path === 'this.path') doThis();
  else if (path == 'something.else') doSomethingElse();
});

But something along the lines of this would be nice

structure.on('change', 'this.path', doThis);
structure.on('change', 'something.else', doSomethingElse);
@dashed
Copy link
Contributor

dashed commented Dec 19, 2014

I did some work regarding this on a library that would "decorate" immstruct, by providing utilities to make flux/isomorphic easier by focusing on immutable structures as the central store.

Some caveats I faced was that any element of the keyPath array can be of any type. So you can't use express-style routing as suggested in immutable-js/immutable-js#237, nor can you use various amazing routing utilities like https://github.com/aaronblohowiak/routes.js, https://github.com/Matt-Esch/http-hash, or https://github.com/pillarjs/path-to-regexp.

I don't have much code to show yet, since it's still in heavy development. Here is how I would fetch or create node paths that reflect the keyPath:

var rootNode = new Structure();

function fetchNode(rootNode, keyPath, create) {
    var
    current = rootNode,
    i = 0;

    for(i = 0; i < keyPath.length; i++) {

        var children = current.get('children', NOT_SET);
        if(children === NOT_SET) {
            if(create) {
                children = current.set('children', Immutable.Map()).get('children');
            } else {
                current = null;
                break;
            }
        }

        var key = keyPath[i];
        var current = children.get(key, NOT_SET);
        if(current === NOT_SET) {
            if(create) {
                current = children.set(key, Immutable.Map()).get(key);
            } else {
                current = null;
                break;
            }
        }
    }

    return current;
}

@dashed
Copy link
Contributor

dashed commented Dec 19, 2014

Since we can't do something like matching '/foo/:bar' paths as in express. I'm mulling over the idea of listening via the bubbling and capture event model as is done in DOM.

@torgeir
Copy link
Member Author

torgeir commented Dec 19, 2014

immstruct already knows the path of .update()s, can't we simply (in pseudo code)

function on (ev, key, fn) {
  structure.on(ev, function (path, old, neww) {
    if (path === key)
      fn.apply(null, arguments);
  });
}

@dashed
Copy link
Contributor

dashed commented Dec 19, 2014

I was thinking something similar, but I decided to go with a structure similar to a trie tree to be efficient on space complexity in the long term.

@dashed
Copy link
Contributor

dashed commented Dec 24, 2014

I've been experimenting with implementing immstruct.listenTo, and I've run into some interesting issues:

// some promise returning function
var a_listener = co.wrap(function*(results){

    // Input:
    // results = {
    //     event: 'change',
    //     newValue: ...,
    //     oldValue: ...
    // };


    // update to execute another listener
    struct.cursor('b').update(function(m) {
        return m.set('foo', 'bar');
    });

    // suggestion: wait until listener for ['b'] finishes?
    yield immstruct.waitFor(struct, 'b');

    // update keypath with no listener
    struct.cursor('c').update(function(m) {
        return m.set('foo', 'bar');
    });

});

var b_listener = co.wrap(function*(results){

    // how to handle cycles?
    struct.cursor('a').update(function(m) {
        return m.set('foo', 'bar');
    });

});

var struct = immstruct({ a: {}, b: {}, c: {} });

immstruct.listenTo(struct, ['a'], a_listener);
immstruct.listenTo(struct, ['b'], b_listener);

struct.cursor('a').update(function(m) {
    return m.set('foo', 0);
});

// how to handle case when modifying cursor while listener for ['a'] executes?
struct.cursor('a').update(function(m) {
    return m.set('foo', 1);
});

@mikaelbr
Copy link
Member

mikaelbr commented Feb 8, 2015

Reference cursors should cover this part, no? #30

@dashed
Copy link
Contributor

dashed commented Feb 8, 2015

Yep. This should be closed.

@mikaelbr mikaelbr closed this as completed Feb 8, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants