How to add a function to all scopes.. - angularjs

I have a function on rootScope that I defined.
I later use it in controllers on the controller's scope - as it inherits the function from the rootScope.
now, I would like to do the same in directives with isolatedScopes.
since they don't prototypically inherit from rootScope, I need to find a another way to place that function on each isolated scope.
is there a way to customize isolated scope on creation, or some other hook?
update
Clarification: i need the function on the scope - not rootScope.
the reason is that we use this.$on('$destroy'...). so we basically want to execute code each time my scope is destroyed.
Current implementation: currently i override $rootScope.$new and check, if isolated i simply add the function on the scope. however this feels hackish and i would like to find a better solution.
here is my current code
$rootScope.registerTask = function(){
....
this.$on("$destroy", function() {
...
});
};
$rootScope.origNew = $rootScope.$new;
$rootScope.$new = function(isolate, parent ){
var newScope = this.origNew(isolate, parent );
if ( isolate ){
newScope.unregisterTask = ...;
newScope.registerTask = $rootScope.registerTask;
}
return newScope;
};
$rootScope.unregisterTask = ...;

Ahh.. the answer has been in front of me all along.. because the question was wrong!
All I wanted to do is assign functions on each and every scope (including isolated).
Well, scopes have prototypical inheritance, then just use that!
var Scope = Object.getPrototypeOf($rootScope);
Scope.registerTask = function(){
....
this.$on("$destroy", function() {
...
});
};
Scope.unregisterTask = ...;
should do the charm.. anywhere on load..
just goes to show - don't write code under pressure, you will work harder and get crappy results.. :)

I think you can inject the $rootScope in to the directive as,
app.directive('testDirective', ['$rootScope', function($rootScope) {
return {
scope : {},
link : function() {
},
controller : ['$scope', function($scope) {
$rootScope.rootScopeFunc();
}]
}
}]);
here is a DEMO

Related

AngularJs 1.x: Remove dynamically created scope and de-register controller

I created a scope and controller dynamically from my code (usually from a provider) as given below
var controllerFn = function ($scope) {
/* scope functions and variables */
$scope.$on('custom_ng_event', function (evt) {
console.log('Custom evt listened in dynamic scope');
});
$scope.$on('$destroy', function () {
console.log('Dynamically created scope destroyed');
});
}
var $scope = $rootScope.$new();
var ctrlInstance = $controller(controllerFn, {$scope: $scope});
I want to remove the scope and de-register the controller at a certain point. I thought that $scope.$destroy() would do the task, but I think I'm missing something as it is not giving the expected result. Like, any broadcast to the $rootScope is still being reflected in the dynamically created scope listener.
Please help me to understand what I have done wrong.
Additional Info:
I preference is to have my dynamically created scope to be a child scope of root scope (directly) because it is meant to be used for the whole application (similar to that of a modal).
Thanks in advance
Balu

What is the difference between two scopes in the same controller (one from a service) to a directive?

I've got the below controller with two scope variables and only one passes through to my directive?
.controller('newsController', ['$scope', 'gasPrices',
function($scope, gasPrices) {
gasPrices.success(function(data) {
$scope.gasFeed = data.series[0];
});
$scope.myData02 = [2.095,2.079,2.036,1.988,1.882,1.817,1.767,1.747];
}])
;
I've got a directive that accepts one scope but not the other?
This works
<line-chart chart-data="myData02"></line-chart>
This doesn't
<line-chart chart-data="gasFeed"></line-chart>
Do you know why?
You have to delay instantiating the directive until the data from your async service is available. Something like:
<line-chart ng-if="gasFeed" chart-data="gasFeed"></line-chart>
This should not instantiate the directive until the gasFeed scope property has data.
Try this:
.controller('newsController', ['$scope', 'gasPrices',
function($scope, gasPrices) {
//Create a object that will be pass in the directive, then when this variable
//it's loaded, the value in the directive (if the scope of the directive uses the '=' binding) will be updated
$scope.gasFeed = {};
gasPrices.success(function(data) {
$scope.gasFeed = data.series[0];
});
$scope.myData02 = [2.095,2.079,2.036,1.988,1.882,1.817,1.767,1.747];
}]);
Yes.
Here, in your example you can access gasFeed scope only when when there is a success callback from the service. Hence, till then myData02 scope will be loaded.
If you want to access both. Then try this :
.controller('newsController', ['$scope', 'gasPrices',
function($scope, gasPrices) {
gasPrices.success(function(data) {
$scope.gasFeed = data.series[0];
$scope.myData02 = [2.095,2.079,2.036,1.988,1.882,1.817,1.767,1.747];
});
}]);

How to access another scope with controller?

I know that you can create binding with a directive but is it possible with a controller? Maybe this is stupidly simple but I couldn't figure out.
For example I would like to click on a text in x scope's view and execute a function in another scope.
function firstCtrl() {
var vm = this;
vm.data = 'First scope stuff!';
}
function secondCtrl() {
var vm = this;
vm.data = 'Second scope stuff!';
}
vm.clicked = function() {
alert('firstScope is clicked!');
};
Here is what I have: http://plnkr.co/edit/CpPKsEGPZWzufB2K1FK3
There are multiple ways how to communicate between controllers.
One way is emitting an event on scope:
function FirstCtrl($scope)
{
$scope.$on('someEvent', function(event, args) {});
// another controller or even directive
}
function SecondCtrl($scope)
{
$scope.$emit('someEvent', args);
}
Another way sharing a service.
Hope it helps. Also check this https://stackoverflow.com/a/9407953/4782034

Is there a way I can share a function that I have attached to my scope between controllers?

I have a function that I will attach to my scope like this. It's attached to the scope as I use this function in my HTML pages Presently I am doing this in more than one controller. Note that my controllers are all top level controllers so I cannot really put this in a higher up controller and have it inherited.
$scope.isNotString = function (str) {
return (typeof str !== "string");
}
I asked how I could share this functionality and was given the following
example:
app.service('myService',function(){
this.sharedFunction = function() {
//do some stuff
};
});
myCntrl1($scope,myService) {
$scope.doSomething = function() {
myService.sharedFunction();
}
}
myCntrl2($scope,myService) {
$scope.doSomething = function() {
myService.sharedFunction();
}
}
Is there a way that I could more directly share it by passing
in $scope to the service and in that way eliminating the need for:
$scope.doSomething = function() {
myService.sharedFunction();
}
In each controller.
You can attach the function to the parent (root) scope, but using a service is the preferred way of sharing code between controllers.
You could call myService.init($scope) in the controller and that function could append properties to the scope but more likely you would want to use a parent controller from which you inherit.
You either declare a shared function in a top level "controller" or in a "service" like you mentioned in your example. There's no other better way so far.
You can assign the scope to a global variable, that will expose that scope globally, but will behave the same way like "service", except you don't have to inject it like service, rather can call by globalVar.dosomething().

Decorator for Scope

Is it possible, and if so how, to decorate $scope so all scopes have some extra function / property?
I'm trying to do this:
$provide.decorator('$scope', function($scope)
{
$scope.cakes = true;
return $scope;
});
But it explodes with:
Unknown provider: $scopeProvider from App.
I know I can add properties and functions to the $rootScope and it will prototypically inherit, but I want isolated scopes in directives to also have access to these added things.
I had the same problem.
Just extend $rootScope prototype.
Then isolated scopes will also have this method.
This is my attempt to use lodash debounce function as native scope method:
angular.module('Test', [])
.config(function($provide) {
$provide.decorator('$rootScope', function ($delegate) {
$delegate.__proto__.$$busy = 0;
$delegate.__proto__.$watchDebounce = function (watchExpression, listener, objectEquality){
var _scope = this;
var debouncedListener = _.debounce(function (newValue, oldValue, scope){
listener(newValue, oldValue, scope);
_scope.$$busy = 0;
scope.$digest();
}, 1000);
var wrappedListener = function (newValue, oldValue, scope){
_scope.$$busy = 1;
debouncedListener(newValue, oldValue, scope);
}
return this.$watch(watchExpression, wrappedListener, objectEquality);
}
return $delegate;
})
})
Working example here http://jsfiddle.net/3ncct/
It doesn't seem possible, but I'd say that's the whole point of an isolate scope.
What you can do is access decorated stuff via scope.$root, however for many use cases it will defeat the purpose because the added functions will still only access the $rootScope instead of your isolated one.

Resources