Angular get scope by scope.$id - angularjs

I want to know, how to get scope by scope.$id. I know that I can get all scopes in page and then I can find that one scope, but I looking for simpler implementation.
For instance:
1. I want to get scope which id is 100 from $rootScope:
$rootScope.$getScope(100)
2. From current $scope or variable angular
$scope.$getScope(100)
angular.scope(100)
Can I get specified scope in that way?

Answer form comments is using jQuery. If you want plain javascript, more functional approach, you could do:
function getScope(scopeId){
return Array.from(document.querySelectorAll(".ng-scope"))
.map(el => angular.element(el).scope())
.filter(scope => scope.$id == scopeId)[0]
}
$rootScope.getScope = getScope;
As far as I know there is no other way to find all scopes on page than just query for .ng-scope.

Related

Is there a way to get a scope of a DOM element when debug info is disabled?

I'm writing an directive which need to retrieve a scope of current DOM element. using the non public api angular.element().scope();
It works well until angular 1.3 introduces a new feature $compileProvider.debugInfoEnabled(false); which mainly aims to improve performance to avoid bind data in DOM element. But when debugInfoEnabled() is set to false, angular.element().scope() will return undefined. So I must find another way to get the scope of an DOM element or I have to redesign my code logic.
Is there a way to make this possible?
I just faced a similar problem in our application after compiling our app with $compileProvider.debugInfoEnabled(false);. I needed to later access some of our directive's isolate scope but couldn't use the isolateScope() method. To get around the problem, I created a helper function in a Utils service that looks like this:
this.setElementIsolateScope = function(element, scope) {
element[0].isolateScope = function() {
return scope;
};
};
Then inside any directive where I needed to be able to later access the isolate scope I called this function inside the link() function: Since element is a jqLite object, you need to set the isolateScope() function on element[0]. You should already have the jqLite wrapped element and scope already passed into your link function, which you then just pass to your service method.
Utils.setElementIsolateScope(element, scope);
To then access the isolate scope later, you would get a reference to your element and then do this (assuming child_element is the reference to your element/directive):
var child_iso_scope = _.isFunction(child_element.isolateScope) && child_element.isolateScope();
Depending on how you are getting the reference to your element, you may need to wrap it a jqLite wrapper like this:
child_element = angular.element(child_element);
And then just use the same way as above to get the isolate scope. Hope this helps!

Passing parameters in ons-sliding-menu

I am wondering if it is possible to open an ons-page as the main page in a ons-sliding-menu and passing it some parameters.
myMenu.setMainPage('somePage.html', [parameter1:'whatever'])
Then, once inside the page, recover them.
I know this can be done in the ons-navigator component. I didn't find any information about this issue.
In case this mechanism would not be available for sliding menu, can anyone recommend me a suitable one?
I am thinking in binding to the $rootScope the parameters I need:
$rootScope.parameter1 = 'whatever'
is this correct? Is there a better option?
Thanks for your help.
You don't need to use the root scope as long as the variable you're setting belongs to a scope that is a parent to that of the new page.
So in your controller you can do something like
$scope.params = {};
And in the ngClick directive:
params.parameter1 = something; myMenu.setMainPage('somePage.html');
I made a simple example on Codepen: http://codepen.io/argelius/pen/GgQVRa
However, a cleaner way would probably be to create a simple service to save the parameter. Then you inject the service in both controllers. If you do it this way you don't have to pollute the scope.

$watchCollection on an array of js objects in an Angular Controller requires an anonymous function?

I have a simple js array being retrieved by an angular factory, injected into a control, watched, then displayed in a table using ng-repeat from within a view state managed by ui-router.
Initially I attempted to subscribe to this array using $watchCollection...
self.$watchCollection( self.Data, function(newData, oldData){
self.total = newData.length;
});
However this was only running when I initially load the app. I found that the only way to subscribe to the running collection was to use an anonymous function returning the array in question.
self.$watchCollection( function() { return self.Data }, function(newData, oldData){
self.totalWatchedWithAnonFunc = newData.length;
})
View this all in http://plnkr.co/edit/L7mycl
From everything I read, all I should have needed to do for a valid subscription was to pass in the array itself and not an anonymous function that returns the array.
The reason I included ui-router is because my actual application is using it heavily and I wanted to mock up my environment as closely as possible to how I've got things set up.
What am I not understanding? Could I be doing something differently?
Thanks.
Are you looking for self.$watchCollection("Data", ...) instead of self.$watchCollection(self.Data, ...)? Try it out! See the docs to see why: the first argument is a string evaluated on the scope, or a function taking a scope that returns something you want to watch.

AngularJS - Access Model Property Without Controller

I have been following some of the introductory AngularJS tutorials and they start off by showing how easy it is to get started.
They say all you have to do is define ng-app and then use the example of an input with ng-model="name" and then show that string as you type using {{name}}.
My question is, is it possible to access and read the 'name' property without having to define a controller and read it using $scope.name?
For example..
$(function () {
var name = ?.name;
});
Well as it turns out, setting ng-model without a ng-controller defined at any parent level creates the item on the $rootScope.
What it also means that whereever $rootScope dependency can be injected you can get access to variable you define in the view.
See my fiddle here
Update: Based on the question update. You can access the scope outside from angular using something like
angular.element(domElement).scope()
and the access the variable. See this answer. But please avoid as much as possible.

Modify scope within link function in AngularJS

Normally in all examples/source code of AngularJS modifications of scope is done in controllers. In my directive I need to get some information from another directive (or it's scope) and put it into scope (so visible in template of directive). As this information is common for all instances of this directive, using scope binding does not sound good for me.
So the only solution I found is to modify instance scope in linking function:
link: function(scope, element, attr, parentCtrl) {
scope.data = parentCtrl.someData;
}
This solution works. Plnkr example
The question: Is it ok according to AngularJS philosophy/style to modify scope in linking function or there is another solution?
Since you are creating isolate scopes in your directives (in your example plnkr), and you want to allow for parents to be 'somewhere' in the scope hierarchy (according to your comment to #MathewBerg), I believe your only option is to use the linking function to modify the scope.
(I suppose you could define methods on your MainCtrl that only the child directives should call, but enforcing that would be messy and break encapsulation).
So, to echo what #MathewBerg already said, yes, modify the scope in the directive/linking function.
Modifying scope in directives is fine. As for sharing information between directives there are a few methods. One is the way you described, where you access the parents controller and get it's data, another very similar method would be to have
scope.data = scope.$parent.data;
Instead of
scope.data = parentCtrl.someData;
The general way to share stuff between directives though is to use a service. This would allow you to inject the service into each directive and they can share the values. The problem with your initial method (and the one that I've described) is that if you ever move the element around so that the hierarchy of scopes change, your code will break. This is why I would recommend using a service over both. I suggest reading up on the service docs. There's also plenty of videos out there describing how to set them up: http://www.youtube.com/watch?v=1OALSkJGsRw

Resources