function on $scope vs function on $window - angularjs

We can create functions at scope level. If i have a controller todoCtrl then if i define a function inside the controller scope that method will reside inside the controller scope.
For example,
$scope.scopeMet = function() {}
We can also define methods at window level using $window service of angular.
For example,
$window.onSignIn = function() {}
Google Sign in callback is captured at window level, hence, i was curious to know what is the meaning and the difference between the two illustrations given above ?

Related

What is the disadvantage of using the $scope as variable in angularjs, to share $scope of a controller inside the app.run?

What is the disadvantage of using the $scope as variable in AngularJS, to share $scope of a controller inside the app.run()?
Actually I am doing that to make code generic to be called from all the controllers with same function in app.run().
The function I am using is with the
$rootScope.getUserInfo = function($scope){
$scope.userinfo = '---------';
}
where $scope is the variable that I am passing from every controller like that
$rootScope.getUserInfo($scope);
I don't think there's inherently something wrong with passing around a scope. People do this a lot in AngularJS services and it's internally done a lot, too: your created controller is passed a scope to work with.
However, I would say it's not necessary in your example to have getUserInfo to depend on a scope being passed. Why not return the user information and have the caller put it on the scope? That way, you can use it in parts of your app that don't have a scope.
Instead of using $scope, you can use var vm = this; and define everything in that controller with vm.variablename_or_funcname instead of $scope.variablename_or_funcname
And you can attach that controller in html like ng-controller = "mycontroller as vm"
More info:
https://johnpapa.net/angularjss-controller-as-and-the-vm-variable/

Pure Controller objects

In AngularJS, a Controller itself is an object defined by a Javascript constructor function and this constructor function is a callback to .controller method.
var myapp=angular.module('scopeExample', []);
myapp.controller('MyController',function MyController($scope){
$scope.name="john";
this.num=700;
});
In the above example, MyController is the constructor function which creates the Controller object with one property (num). I have three queries upon that:
Actually, what is the use of the Controller object in that case?
Does it have some more properties not visible and is it accessible from outside Angular?
How it is interconnected to its scope which in turn is another object?
I came upon the following queries because of the controller as syntax which creates a controller object that is a property of controller's scope and therefore easily accessible, e.g.
<div ng-app="scopeExample" ng-controller="MyController as ctrl">
<input id="box" ng-model="ctrl.num"> equals {{ ctrl.num }}
</div>
<script>
angular.module('scopeExample', [])
.controller('MyController', [function () {
this.num=12;
}]);
</script>
var x=angular.element('#box').scope().ctrl; //x is the controller object itself
1.a. What is the use of the Controller object in that case?
There is nothing special about this example, angular is an MVC framework(or any other buzz word you wish to use that describes almost the same thing), the controller's responsibility is to response to view events, update the model accordingly and execute business logic tasks (you can choose where to actually implement the logic, wheres in the controller itself or use services).
Of course that in this example the controller is pretty useless, because you have no logic, and only 2 proprieties.
1.b. Specking of ctrl-as syntax, in your example you injected 'scope' into the controller and added property ($scope.name), when you're using controller as it is recommended for you to avoid using scope unless you are obligated to do so. (e.g. $watch, parent...)
2.a. Does it have some more properties not visible?
No it doesn't have any invisible properties, you can check it easily by your self with the following code:
.controller('MyController', function () {
window.DoesThisControllerHaveInvisibleProps = this;
});
2.b. is it accessible from outside Angular?
I'm not sure that I fully understood what you've meant with "outside Angular", if so here is an example that the controller obj can be accessible from "outside":
class MyController {
static foo() {
console.log('hello!');
}
}
myapp.controller('MyController', MyController);
// maybe somewhere else in that module
MyController.foo();
3.How it is interconnected to its scope which in turn is another object?
As you said, when using controller as syntax angular is initializing the controller and put it on the $scope so it will be accessible in the template.
$scope is just an unnecessary glow and you should avoid using it. my way of seeing it is like it was angular implantation details, when migrating to ng-2 you will see that there is no more scope.
If you're interested in more detailed info about how exactly $scope and controllers in angular are working I suggest you have a look at

ngMock injecting $scope local into controller

This is a continuation of another question I asked that was successfully answered.
I'm learning how to unit test AngularJS applications with Karma, Jasmine, and ngMock. Here's the code I have a question about:
describe('myController function', function() {
describe('myController', function() {
var scope;
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $controller) {
// These are the 2 lines I'm a bit confused about:
scope = $rootScope.$new();
$controller('MyController', {$scope: scope});
}));
it("...");
});
});
Question 1: Why do we create a new scope and include it in the locals injection area in this line: $controller('MyController', {$scope: scope});? It seems to work just fine (as in, scope now represents the $scope object from that controller and has all the properties and functions it's supposed to), but the code seems to imply that we're resetting the controller's $scope with our newly-created (and empty) scope (from the line scope = $rootScope.$new();). So I think I'm just not fully understanding the purpose/inner-workings of those locals.
Question 2: I also have seen from my searching that new scope gets created in 2 common ways, either the way shown above with $rootScope.$new(), or by simply declaring scope = {}. Even the Angular docs do it both ways, as seen here (using $rootScope.$new()) and here (using $scope = {}. Why do this one way over another? Is there a difference?
Why do we create a new scope
There are a couple of reasons that come to mind, but the short answer is that you don't have to if you don't want to. You can just as easily pass in $rootScope and your tests will still work. It is also just typically done because it is more in line with what actually happens in angular - the $scope that the controller is injected with is likely a descendent of $rootScope.
What is $controller('MyController', {$scope: scope}); doing?
The ngMock module provides the $controller function as a sort of constructor for creating your controller - well, technically it's a decorator to the $controller function in the ng module, but that's not important. The first argument is typically a string, but can be a function.
If called with a function then it's considered to be the controller constructor function. Otherwise it's considered to be a string which is used to retrieve the controller constructor...
The second argument are the "locals" to be injected into the controller during creation.
So, in your example, you are saying you want to create the "MyController" controller, and you want to inject your scope variable as the argument named $scope in the controllers function.
The whole point of this is to inject your own version of the scope into the controller, but a version that you created in your test, so that you can assert the different things that happen to the scope because of the controller.
This is one of the benefits of dependency injection.
Examples
If the following makes sense:
var scope = {};
scope.add = function(){};
expect(typeof scope.add).toBe('function');
then let's take it one step further and move the adding of the function into another function:
var addFunctionToScope = function(scope) {
scope.add = function(){};
};
var scope = {};
addFunctionToScope(scope);
expect(typeof scope.add).toBe('function');
Now just pretend your new function to add the function to the scope is really just called $controller, instead of "addFunctionToScope".
var scope = {};
$controller('SomeController', {$scope: scope});
expect(typeof scope.add).toBe('function');
Why use $rootScope.$new() over {}
Again, you can use either. However, if you plan on using some of the scope specific functions, like $on, or $new, or $watch, etc - you will want to inject an actual scope object, created using the $new function on an existing scope.
Docs
scope
ngMock $controller
ng $controller

controllers are created using a factory function?

I am new to angularJS and going through angular docs.I came across this line controllers are created using a factory function
I tried to find what that means and found what is factory and service and providers but that does not fit here.
How controllers are created using a factory function?
Please explain what is the meaning of factory in this context.
The key quote you are missing from the previous section you are referring to is this:
"First, there is a new JavaScript file that contains a so-called "controller". More exactly, the file contains a constructor function that creates the actual controller instance. "
If this were an actual angular factory, it would make more sense. But, controllers are instances just like Angular factories, services, and providers.
A factory, is actually a Javascript design pattern, maybe reading here it will make more sense.
For the controller to work, the instance must exist for the two-way binding to be able to take place. So basically, an instance of the controller is created. The angular controller page explains it well with:
"When a Controller is attached to the DOM via the ng-controller directive, Angular will instantiate a new Controller object, using the specified Controller's constructor function. A new child scope will be available as an injectable parameter to the Controller's constructor function as $scope." Here's the link.
In the event of controllers though, you would most likely store items on the $scope and not 'this'. So they separate controllers from factories this way as they do not return an accessible instance of themselves and instead bind their properties to the view through $scope or 'this'.
TO BE CLEAR, I'm not saying that they are referring to Angular factories. I believe the reason for this phrasing is tied to the same wording for the service factory function:
"Application developers are free to define their own services by registering the service's name and service factory function, with an Angular module.
The service factory function generates the single object or function that represents the service to the rest of the application. The object or function returned by the service is injected into any component (controller, service, filter or directive) that specifies a dependency on the service."
They give this example:
var myModule = angular.module('myModule', []);
myModule.factory('serviceId', function() {
var shinyNewServiceInstance;
// factory function body that constructs shinyNewServiceInstance
return shinyNewServiceInstance;
});
So when you see them say created from a factory function, they are just saying using the following pattern:
.controller('PersonCtrl', [
'PersonFactory'
function(PersonFactory) {
this.name = 'Tom';
console.log(PersonFactory.name); //would print 'Tom'
}]);
.factory("PersonFactory", [
function () {
return {
name: 'Tom'
};
}]);
I hope that helps, or maybe someone could be more concise in my explanation and edit this description.
What this means is that you provide AngularJS with a function that it can execute as many times as it needs to produce instances of your controller. So to take the example from the page you linked to:
angular.module('invoice3', ['finance3'])
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
this.qty = 1;
this.cost = 2;
this.inCurr = 'EUR';
this.currencies = currencyConverter.currencies;
this.total = function total(outCurr) {
return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
};
this.pay = function pay() {
window.alert("Thanks!");
};
}]);
That function that starts on line 2 with function(currencyConverter) { is the factory function.
Whenever the page has a location that uses an InvoiceController, AngularJS will (essentially) do the following with that factory function, passing in any dependencies that it has:
var currencyConverter = ...; // obtain a currency converter from the factory
var theController = new thatFactoryFunction(currencyConverter);
and then it will use the value that is returned as your controller. It will do this separately for each InvoiceController indicagted the page, creating a separate instance for each one.
(I stress that the code above is purely an illustration of what AngularJS is doing and not an actual representation of the code that it uses.)
The creation of a controller instance is interesting. One would expect that it is created with new InvoiceController(...), and it's also suggested by the sentence More exactly, the file contains a constructor function that creates the actual controller instance, but that's not the case. Actually it's created like this:
instance = Object.create(controllerPrototype);
and later the constructor function is called as function:
return fn.apply(self, args); //self == instance
To be honest, we can only guess what the author meant by factory function. It could be the fact that controllers are not created by new. Maybe the the constructor function is therefore referred to as factory or it's the internal factory function. It could also just be bad wording or even a mistake.

angular.js on-keyup doesn't work

I would like to make a javascript alert/call a function onkeyup.
But it doesn't work. see Plunker
Simply:
<input ng-keyup="alert('hi')">
What's wrong?
The ngKeyup exprssion will be evaluated in the context of the current $scope, so everything you refer to needs to be declared on the $scope.
E.g.:
.controller('someCtrl', function ($scope, $window) {
$scope.alert = $window.alert.bind($window);
// Or
// $scope.alert = function (msg) { $window.alert(msg); }
});
See, also, this short demo.
Angular does not use JavaScript's eval() to evaluate expressions. Instead Angular's $parse service processes these expressions.
Angular expressions do not have access to global variables like window, document or location. This restriction is intentional. It prevents accidental access to the global state – a common source of subtle bugs.
Instead use services like $window and $location in functions called from expressions. Such services provide mockable access to globals.
that means you should write function alert in your controller , or inject $window service and reference from it
angular.module('test',[]).controller('testCtrl',function($scope){
$scope.alert = function(text){
alert(text)
}
})
here is updated example
from docs

Resources