Pasvaz/bindonce

Add another way - unbind

ivan1986 opened this issue · 4 comments

I can't entirely understand the article because I don't speak russian, however I think the directive is quite esplicative and I've got the point.
The scope destruction is a cool idea, I use a similar approach somtime but you must be aware of the drawbacks or you'll run in some scope issues.
If you destroy the scope everything is associated with it stops working, for instance inside a repeater you might use ng-click or other directive that rely on the scope created by the repeater, if you destroy it these directives stop working.
There could be also some performance issues when you run a long list of scope destruction that I would like to check before of implementing a solution like this, I'll investigate more on how to mitigate these issue and eventually I could add a 'destroyOnce' plugin.
Thank you for bringing this to my attention Ivan.

It be cool, If you add this derective into you library.
Sorry, but my english is bad, and i think way "let me show code" is good way for bringing you attention.
Of couse need find good name for derective and write in doc about all derectives.

Yes it would be cool, let's work together on this thing then. The next week I should be able to work on it, if you already have something feel free to submit a PR.
Ps. don't worry about your english, mine is bad as well :)

Working prototype for change binding in runtime - good solution for ajax load.
I try do normal code on weekend

<!DOCTYPE html>
<html>
<head><title></title>
<script>
function Main($scope) {
    $scope.a = 'zzz';
    $scope.items = [
        'a',
        'b',
        'c',
        'd',
    ];
    setTimeout(function() {
        $scope.items.push('e');
        $scope.$apply();
    }, 1000);
}
</script>
<script src="angular.js"></script>
<script>

var scopesList = {};
function rebund() {
    for(var i in scopesList) {
        var item = scopesList[i];
        item.scope.$$listeners = item.listeners;
        item.scope.$$watchers = item.watchers;
        item.scope.$$asyncQueue = item.asyncQueue;
        item.scope.$$postDigestQueue = item.postDigestQueue;
    }
}
function unbund() {
    for(var i in scopesList) {
        var item = scopesList[i];
        scopesList[i].listeners = item.scope.$$listeners;
        scopesList[i].watchers = item.scope.$$watchers;
        scopesList[i].asyncQueue = item.scope.$$asyncQueue;
        scopesList[i].postDigestQueue = item.scope.$$postDigestQueue;
        item.scope.$$listeners = {};
        item.scope.$$watchers = item.scope.$$asyncQueue = item.scope.$$postDigestQueue = [];
    }
}

angular.module('App', [])
  .directive('bindOnce', function() {
    return {
        scope: true,
        link: function( $scope, $element ) {
            function findChild(scope) {
                //console.log(scope);
                if (typeof scope.$stopUnbind != 'undefined') {
                    return {
                        toDel: [],
                        toAttache: [scope]
                    }
                }
                scopesList[scope.$id] = {
                    listeners: scope.$$listeners,
                    watchers: scope.$$watchers,
                    asyncQueue: scope.$$asyncQueue,
                    postDigestQueue: scope.$$postDigestQueue,
                    scope: scope
                };
                scope.$$listeners = {};
                scope.$$watchers = scope.$$asyncQueue = scope.$$postDigestQueue = [];
                var data = {
                    toDel: [scope],
                    toAttache: []
                }
                for(var cs = scope.$$childHead; cs; cs = cs.$$nextSibling) {
                    var add = findChild(cs);
                    data.toDel = data.toDel.concat(add.toDel);
                    data.toAttache = data.toAttache.concat(add.toAttache);
                }
                return data;
            }
            setTimeout(function() {
                var scopes = findChild($scope);
                console.log(scopesList);
                //TODO: need destroy scopes?
            }, 0);
        }
    }
  })
  .directive('sc', function() {
    return {
        scope: true,
        link: function( $scope, $element ) {
        }
    }
  })
  .directive('bindFull', function() {
    return {
        scope: true,
        link: function( $scope, $element ) {
            $scope.$stopUnbind = true;
        }
    }
  })
;

</script>
</head>
<body ng-app="App">
  <div ng-controller="Main">
    <input ng-model="a" />
    {{ a }}
        <ul><li ng-repeat="item in items">{{ item }}</li></ul>
    <div bind-once>
        {{ a }}
        <ul><li ng-repeat="item in items">{{ item }}</li></ul>
        <span sc>{{ a }}</span>
        <div bind-full>{{ a }}
            <span sc>{{ a }}</span>
        </div>
    </div>
  </div>
  <input type="button" value="rebind" onclick="rebund()" />
  <input type="button" value="unbind" onclick="unbund()" />
</body>
</html>