Scope of a function inside an Angular JS Controller - javascript

What scope is a function defined inside an angular js controller, part of?
.controller('MyCtrl', ['$scope', '$location', function($scope, $location) {
function log() {
console.log('Vanakkam Ulagam');
}
var functionToCall = 'log';
????????[functionToCall]();
}])
I tried MyCtrl, this and $window. I can access the function by namespacing it like so functions.print = function() and then using functions[functionToCall]().
I am more interested in accessing the function without namespacing it. Is it possible? If not, why?

i think this is solution for this question
var f;
var a = angular.module('MyApp',[]);
a.controller('MyCtrl', ['$scope', function ($scope) {
$scope.log=function(){
console.log('test');
}
f=$scope.log;
});
and this function useable to element html for example
<button ng-click='log()'></button>
or
<button onclick='f()'></button>

If you're just trying to access global functions in your controller code, window (or $window if it's properly injected) should work fine:
$scope.alert = function(text) { window.alert(text) }
To be extra sure this works in other environments you could manually bind it in a self-invoking anonymous function:
(function(global){ //make the global scope assigned to the variable global
app.controller('MyCtrl',['$scope',function($scope){
$scope.alert = global.alert;
}]);
)(this); //this is the global object when this is evaluated
If you want to do anything inside an expression on a DOM element (such as ng-click), it's important to realise that angular expressions are evaluated by Angular's own expression evaluator (namely through $scope.$eval). So if something is not attached to a scope, it cannot be used in an angular expression.
However, if you were to do something like attach the global object to the scope, then everything is fair game. This really isn't recommended (I think there's no real reason to do this, and its better to manually define functions you need), but :
$scope.global = window
Inside your controller definition should work. You can then do things like ng-click="global.alert('Yo SO!')" in your DOM without issues.
For better testability you could use $window (you said you tried it and it didn't work... are you sure you injected it properly? Look at the example in the documentation carefully). But like I said, if you're attaching the global object to the scope you're opening Pandora's Box.

Related

Differnce between $scope.Variable and $scope.Function in Angular?

$scope.some_random_variable = "random_value";
$scope.some_random_function = function(random_param){
console.log("randomness");
}
I want to know the difference in the context of digest cycle.
As far as I can understand scope_function changes the visibility of Angular Function.
basically, in your html, or whatever that interacts with your $scope, a $scope.something that is declared as a function will be launched when it is called, just like how a javascript function works, same as a variable, only difference between a $scope and a var would be that $scope is a global call.

AngularJS and IIFE

I have started learning AngularJS and while going through some code samples I came across the following:
(function(app) {
'use strict';
app.directive('sideBar', sideBar);
function sideBar() {
return {
restrict: 'E',
replace: true,
templateUrl: '/scripts/spa/layout/mypage.html'
}
}
})(angular.module('common.ui'));
The above code creates a custom directive using IIFE. I am very confused about the last line of the code. It is passing a module named common.ui. Can someone explain me how this way of passing a parameter works and how this can be rewritten in a different way?
angular.module('common.ui') becomes referenced by app. See What is the (function() { } )() construct in JavaScript?.
You can declare it normally
(function() {
var app = angular.module('common.ui');
})();
Without the final parens (passing the angular.module) it would just be a function that was defined but didn't do anything and it wouldn't be callable without a name. The parens are invoking it immediately.
As far as rewriting it could be defined with a name and then called. Because it would be called only once there is no need to give it a name. Instead it is just run.
There are other reasons to use IIFE (like closures for encapsulating data or getting around async code) but in this case it is really just avoiding naming and then calling.
the upper function isn't in the scope or being seen untile this () exist
which you are defining parameter to the upper function and call it .

Integrating non-Angular code?

I'm developing a Cordova/PhoneGap app, and I'm using the $cordovaPush plugin (wrapped for PushPlugin) to handle push notifications.
The code looks something like this:
var androidConfig = {
"senderID" : "mysenderID",
"ecb" : "onNotification"
}
$cordovaPush.register(androidConfig).then(function(result) {
console.log('Cordova Push Reg Success');
console.log(result);
}, function(error) {
console.log('Cordova push reg error');
console.log(error);
});
The "ecb" function must be defined with window scope, ie:
window.onNotification = function onNotification(e)...
This function handles incoming events. I'd obviously like to handle incoming events in my angular code - how can I integrate the two so that my onNotification function can access my scope/rootScope variables?
Usually, you'll wrap your 3rd party library in a service or a factory, but in the spirit of answering your particular scenario...
Here's one possibility:
angular.module('myApp').
controller('myController', function($scope, $window) {
$window.onNotification = function() {
$scope.apply(function() {
$scope.myVar = ...updates...
});
};
});
A couple of things to notice:
Try to use $window, not window. It's a good habit to get into as it will help you with testability down the line. Because of the internals of Cordova, you might actually need to use window, but I doubt it.
The function that does all of the work is buried inside of $scope.apply. If you forget to do this, then any variables you update will not be reflected in the view until the digest cycle runs again (if ever).
Although I put my example in a controller, you might put yours inside of a handler. If its an angular handler (ng-click, for example), you might think that because the ng-click has an implicit $apply wrapping the callback, your onNotification function is not called at that time, so you still need to do the $apply, as above.
...seriously... don't forget the apply. :-) When I'm debugging people's code, it's the number one reason why external libraries are not working. We all get bit at least once by this.
Define a kind of a mail controller in body and inside that controller use the $window service.
HTML:
<body ng-controller="MainController">
<!-- other markup .-->
</body>
JS:
yourApp.controller("BaseController", ["$scope", "$window", function($scope, $window) {
$window.onNotification = function(e) {
// Use $scope or any Angular stuff
}
}]);

Define Permanent $scope variables

So if in a lot of my controllers I have this:
$scope.error = false;
$scope.errorData = {};
$scope.working = false;
$scope.workingMessage = "Doing something, please wait..."; // best UI message ever
Is there a way of having these permanently defined on every $scope given to my controllers?
So I do need inheritence, so where can apply these scope variables to the $rootScope so that it will be picked up in all my controllers?
Update
So after much reading of the documentation, it appears that use ngApp auto bootstraps the angular app which is when the $injector service runs. I need to have the variables put on before this service runs, so I'm guessing that I need to manually bootstrap the application.
More Work
.run()
This runs after all the modules have been initialised. So here I can inject the $rootScope and put my variables on that. Then they can be used on my all my $scopes, obviously if you data bind to it then you can simply use the property names because the binder will first look at the $scope then all subsequent parent scopes until it finds the property.
.run(['$rootScope', rootScopeConfigure]);
function rootScopeConfigure($rootScope) {
$rootScope.myCustomProperty = "Hey There";
}
As per a comment on my question, this can get dangerous if you are adding properties randomly. But as I have only a few properties, it doesn't really matter or add that much overhead. (I hope).
However, all this poses one problem, if I want to modify this custom property in the controller then I have to inject $rootScope. I don't particularly want to do this, I want to be able to access these on the $scope
In response to my above paragraph, I should be able to do $scope.$root.myCustomProperty because I'm guessing that the $rootScope is the root of all $scopes.
Dirty Answer
$rootScope.$oldNew = $rootScope.$new;
$rootScope.$new = function () {
var childScope = $rootScope.$oldNew();
childScope.myCustomerProp = "Hey There";
return childScope;
}
Do this in the run() function. Basically overriding the factory to return a new child scope that has my property on it :).
Yes, scopes can be inherited from parents. You can create a parent controller for your controllers.
A scope can inherit from a parent scope, as in this example:
var parent = $rootScope;
var child = parent.$new();
parent.salutation = "Hello";
child.name = "World";
expect(child.salutation).toEqual('Hello');
child.salutation = "Welcome";
expect(child.salutation).toEqual('Welcome');
expect(parent.salutation).toEqual('Hello');
https://docs.angularjs.org/api/ng/type/$rootScope.Scope
I recommend not using scope but instead using $cacheFactory or a service/factory of your own to persist this type of state.
So I have the answer now.
.run()
This runs after all the modules have been initialised. So here I can inject the $rootScope override is $new function that I believe is just a simple scope factory.
Then any properties or methods put on that new scope can be used on my all my $scopes.
.run(['$rootScope', runtimeConfigure]);
function runtimeConfigure() {
$rootScope.$oldNew = $rootScope.$new;
$rootScope.$new = function(isolate, parent) {
var child = $rootScope.$oldNew(isolate, parent);
child.title = "Hey There";
return child;
}
}
I believe there to be no issues with doing this.
Firstly, I'm merely ghosting the original scope factory $new
Secondly, I'm just adding properties to the new scope.

Can't access to injected AngularJS services within a function in a controller

Cannot access to $scope and Food inside destroy function.
foodProject.controller('FoodsCtrl', function($scope, Food) {
$scope.foods = Food.index();
$scope.destroy = function(food){
debugger;
console.log(Food, $scope);
food.$destroy();
};
});
The local scope variables are only
food: Resource
this: $get.e.$new.a
I can't find $scope and Food
http://jsfiddle.net/fW2EA/1/
http://jsfiddle.net/wizztjh/fW2EA/3/
Include this line in your destroy function (it is missing from your fiddle):
console.log(Food, $scope);
Then in your debugger, check the Closure section of Scope Variables (I was using Chrome), when stopped on your break point. Food and $scope are in there (as one would expect!).
this in the context of the destroy function is a new scope within the ng-repeat so is not the same as $scope, although both are scopes.
Within your function, this is the scope, e.g. this.foods.
I believe if you want Food to be accessible add it to the scope, i.e., $scope.Food = Food;.
I'm still a noob and am not sure if adding Food to $scope is the right thing to do.

Categories

Resources