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

Bugfix for removeAfterUpdate #115

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Bugfix for removeAfterUpdate #115

wants to merge 2 commits into from

Conversation

levjj
Copy link
Contributor

@levjj levjj commented Mar 5, 2013

The removeAfterUpdate property of a connection is used to make a connection fire only once. The problem is that the current implementation remove the attribute connection for that source/target combination regardless of whether this connection was changed or re-connected during the update.

One solution would be to introduce a new property called removeBeforeUpdate but this patch implements a simpler approach that uses a flag to check whether a connection needs to be removed or not.

@rksm
Copy link
Member

rksm commented Mar 6, 2013

Actually, a simple solution for your problem that does not require any changes
in the bindings implementation would be (code adapted from your test)

var obj2 = {y: function(v) {
     this.z = v;
     if (v < 5) {
         connect(connection, 'disconnect', connection, 'connect', {removeAfterUpdate: true});
     }
 }};

connection can be a ref from when you created the conenction or from
obj1.attributeConnection. You might want to do that in an updater/converter
to make storing a ref unnecessary and keep the removeAfterUpdate/reconnect
logic together:

connect(obj1, 'x', obj2, 'y', {removeAfterUpdate: true, updater: function($upd, val) {
    if (val < 5) connect(this, 'disconnect', this, 'connect', {removeAfterUpdate: true});
    $upd(val);
}});

Please consider one of those solutions as introducing new state to a
connection requires more than changing just #resetSpec

@levjj
Copy link
Contributor Author

levjj commented Mar 6, 2013

Your workaround would work for the test but when I discovered the bug the situation was a little bit more complicated. The code for creating the new connection was conceptually unrelated to the old connection but was sometimes executed as callback in the dynamic scope of the old connection update. Just because it was executed as callback caused the new connection (which has a completely different converter/updater) to get removed.

Consider the following example. Executing the callback asynchronously works fine but calling it directly causes the new connection to get removed, so the counter always stops at 4.

Object.subclass('AsyncCounter', {
    initialize: function() { this.c = 0; },
    doInc: function() { this.c++; },
    inc: function() {
        if (this.c === 4) {
            this.doInc();                    // increment 4 directly
        } else {
            this.doInc.bind(this).delay(1);  // increment counter with a delay
        }
    }
});

var txt = new lively.morphic.Text(rect(0,0,99,20));
txt.counter = new AsyncCounter();
txt.addScript(function showAndInc() {
    this.textString = this.counter.c;
    connect(this.counter, 'c', this, 'showAndInc', {removeAfterUpdate: true});
    this.counter.inc();
});
txt.openInWorld();
txt.showAndInc(); // increments the counter but stops at 4

Of course, you can also use some kind of workaround to detect whether or not a similar connection is currently active and connect the disconnect method in that case but I would still argue that this is a bug and not intended behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants