Is it possilbe to introspect/reflect of the model in Angular app, where you can change the scope and traverse it? Something like batarang have but that will allow to change the values.
If not is it possilbe to monkey patch Angular code (by including another script on the page) that will make it possilbe?
1. Accessing/Modyfing scope properties
Angular's $scope
objects are plain old JS objects, so thay can be manipulated the standard way.
E.g. someScope.someProp
retrieves the value of a property, while someScope.someProp = someValue
sets the value of a property.
2. Letting Angular know
Modifying the object's properties is one thing - making Angular aware of the change is another.
Angular will not know about our modifications, until it runs a $digest
cycle. If we want to apply the changes right away, we can explicitely trigger a $digest
cycle, by using someScope.$apply()
.
3. Getting hold of a scope
In order to get a reference to the scope associated with a DOM element, we need to have a reference to the corresponding DOM Node object, wrap it in angular.element
and execute its scope()
method.
Something like this:
<body class="ng-scope">
var someScope = angular.element(document.body).scope();
Furthermore, if we want to access the $rootScope
(the parent scope of all scopes), we can use the injector to inject the $rootScope
service:
<html ng-app="myApp">
var injector = angular.element(document.documentElement).injector();
var rootScope = injector.get('$rootScope');
4. Traversing the scope-tree
Once we get hold of a scope object, we might want to traverse the scope-tree. Every scope has the following properties (among others):
$parent
: The parent scope of this scope (if any).$$nextSibling
: The next sibling scope of this scope (if any).$parent
)$$childHead
: The first child scope of this scope (if any).In order to traverse the branch of the scope-tree with someScope
as its root:
var scopes = [someScope];
while (scopes.length) {
var scope = scopes.shift();
console.log(scope);
if (scope.$$nextSibling) { scopes.unshift(scope.$$nextSibling); }
if (scope.$$childHead) { scopes.unshift(scope.$$childHead); }
}
E.g. to traverse the whole scope-tree, you can use the following snippet:
var injector = angular.element(document.body).injector();
var rootScope = injector.get('$rootScope');
var scopes = [rootScope];
while (scopes.length) {
var scope = scopes.shift();
report(scope);
if (scope.$$nextSibling) { scopes.unshift(scope.$$nextSibling); }
if (scope.$$childHead) { scopes.unshift(scope.$$childHead); }
}
function report(scope) {
var str = '' + scope.$id;
while (scope.$parent) {
str = scope.$parent.$id + ' => ' + str;
scope = scope.$parent;
}
console.log(str);
}