Skip to content

Instantly share code, notes, and snippets.

@jhunken
Created December 11, 2014 04:00
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save jhunken/767cdf62ecc9f31c56da to your computer and use it in GitHub Desktop.
Save jhunken/767cdf62ecc9f31c56da to your computer and use it in GitHub Desktop.
angular.module('lib.decorators', [])
.config(['$provide', function($provide){
$provide.decorator('$rootScope', ['$delegate', function($rootScope) {
var _proto
, _new
, nextUid = function() {
return ++$rootScope.$id;
}
, Scope = function() {
this.$id = nextUid();
this.$$phase = this.$parent = this.$$watchers = this.$$nextSibling = this.$$prevSibling = this.$$childHead = this.$$childTail = null;
this.$root = this;
this.$$destroyed = false;
this.$$listeners = {};
this.$$listenerCount = {};
this.$$isolateBindings = null;
};
_proto = Object.create(Object.getPrototypeOf($rootScope));
Scope.prototype = _proto;
_new = function(isolate, parent) {
var child;
parent = parent || this;
if (isolate) {
child = new Scope();
child.$root = this.$root;
} else {
// Only create a child scope class if somebody asks for one,
// but cache it to allow the VM to optimize lookups.
if(!this.$$ChildScope) {
this.$$ChildScope = function ChildScope() {
this['$$watchers'] = this['$$nextSibling'] = this['$$childHead'] = this['$$childTail'] = null;
this['$$listeners'] = {};
this['$$listenerCount'] = {};
this['$id'] = nextUid();
this['$$ChildScope'] = null;
};
this['$$ChildScope'].prototype = this;
}
child = new this.$$ChildScope();
}
child['$parent'] = parent;
child['$$prevSibling'] = parent.$$childTail;
if (parent.$$childHead) {
parent.$$childTail.$$nextSibling = child;
parent.$$childTail = child;
} else {
parent.$$childHead = parent.$$childTail = child;
}
// When the new scope is not isolated or we inherit from `this`, and
// the parent scope is destroyed, the property `$$destroyed` is inherited
// prototypically. In all other cases, this property needs to be set
// when the parent scope is destroyed.
// The listener needs to be added after the parent is set
if (isolate || parent != this) {
child.$on('$destroy', destroyChild);
}
return child;
function destroyChild() {
child.$$destroyed = true;
}
};
$rootScope.$new = _new;
return $rootScope;
}]);
}]);
@beckyconning
Copy link

Hi! Would it be okay if I put this patch in a GitHub repo and added a bower package so that it can be installed with bower?

@beckyconning
Copy link

Hi! Hope its okay that I forked this here: https://gist.github.com/beckyconning/9fe5450046cabfa5d104

You can now install this using bower using bower install https://gist.github.com/beckyconning/9fe5450046cabfa5d104 --save and adding <script src="bower_components/angular-issue-9128-patch/angular-issue-9128-patch.js"></script> or similar to your index.html.

@return-none
Copy link

@beckyconning you've missed '.git' in repo path

proper way to install:

bower install https://gist.github.com/beckyconning/9fe5450046cabfa5d104.git --save

@kswin
Copy link

kswin commented Mar 6, 2015

I was wondering if you could help me with an Angular 1.2.25 compatible decorator for this issue. When I add the following "$new" changes directly into the 1.2.25 code, the error does go away.

this['$$watchers'] = this['$$nextSibling'] = this['$$childHead'] = this['$$childTail'] = null;
this['$$listeners'] = {};
this['$$listenerCount'] = {};
this['$id'] = nextUid();
this['$$childScopeClass'] = null;
child['$parent'] = this;
child['$$prevSibling'] = this.$$childTail;

However, the decorator that I've re-written for 1.2.25 doesn't work. Specifically, when I set breakpoints in the code, I see that the decorated rootScope is returned, but the _new function itself is not used in iOS8 (in chrome _new does get called):

angular.module('lib.decorators', [])
    .config(['$provide', function($provide) {

        $provide.decorator('$rootScope', ['$delegate', function($rootScope) {
            var _proto,
                _new,
                nextUid = function() {
                    return ++$rootScope.$id;
                },
                Scope = function() {
                    this.$id = nextUid();
                    this.$$phase = this.$parent = this.$$watchers =
                        this.$$nextSibling = this.$$prevSibling =
                        this.$$childHead = this.$$childTail = null;
                    this['this'] = this.$root = this;
                    this.$$destroyed = false;
                    this.$$asyncQueue = [];
                    this.$$postDigestQueue = [];
                    this.$$listeners = {};
                    this.$$listenerCount = {};
                    this.$$isolateBindings = {};
                };

            _proto = Object.create(Object.getPrototypeOf($rootScope));
            Scope.prototype = _proto;

            _new = function(isolate) {
                var ChildScope,
                    child;

                if (isolate) {
                    child = new Scope();
                    child.$root = this.$root;
                    // ensure that there is just one async queue per $rootScope and its children
                    child.$$asyncQueue = this.$$asyncQueue;
                    child.$$postDigestQueue = this.$$postDigestQueue;
                } else {
                    // Only create a child scope class if somebody asks for one,
                    // but cache it to allow the VM to optimize lookups.
                    if (!this.$$childScopeClass) {
                        this.$$childScopeClass = function() {
                            this['$$watchers'] = this['$$nextSibling'] =
                                this['$$childHead'] = this['$$childTail'] = null;
                            this['$$listeners'] = {};
                            this['$$listenerCount'] = {};
                            this['$id'] = nextUid();
                            this['$$childScopeClass'] = null;
                        };
                        this.$$childScopeClass.prototype = this;
                    }
                    child = new this.$$childScopeClass();
                }
                child['this'] = child;
                child['$parent'] = this;
                child['$$prevSibling'] = this.$$childTail;
                if (this.$$childHead) {
                    this.$$childTail.$$nextSibling = child;
                    this.$$childTail = child;
                } else {
                    this.$$childHead = this.$$childTail = child;
                }
                return child;
            };

            $rootScope.$new = _new;

            return $rootScope;
        }]);
    }]);

I would greatly appreciate your feedback.

@markhaja
Copy link

kswin, I'm attempting to do the same thing with 1.2.23. I've altered the angular.js file directly, and the problem goes away. I've created a provider very similar to yours, and am not seeing the _new function invoked.
As with all the other posts about this problem, I've attempted to isolate/recreate, but its pretty unpredictable.
If you've made any progress please pass it along.

@markhaja
Copy link

kswin: I was able to get this working in anglarJS 1.2.23, by specifically adding it to our module:

SampleModule.config(['$provide', function ($provide) {
        $provide.decorator('$rootScope', ['$delegate', function ($rootScope) {

@brauliodiez
Copy link

@beckyconning thanks for the patch, just one more step for dummies like me 😄 do not forget as well to add it as a reference to your main module..

var myApp = angular.module('myApp', ['ngRoute','...', 'issue-9128-patch'])

This patch, is working fine except sometimes getting some "undefined" text in the middle of the markup, any clue why this happens?

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