Can we use only this in controllers, without $scope?
In some cases of course yes, i know... But...
If we need $emit, $broadcast and some other angular features, which we can find only in scope? Can we get it in this may be, or some other ways to get it?
As far as I'm aware there are some special cases like $emit etc which you have to use $scope and can't use this.
When you create a controller in this format :
angular.module('myModule').controller('myController',['$scope',function($scope){
//controller code here
}]);
the function that you are passing is basically a constructor for the controller object
so when you write a code like this :
angular.module('myModule').controller('myController',['$scope',function($scope){
this.myObject = { key : value};
}]);
you are basically making myObject a property of the myController object
Controllers are basically used in angular.js to fascillitate communication between your view( which are handled by directives ) and services( which take care of the buisness logic )
To enable that you can use the dependency injection angular provides and insert the $scope object into your controller as shown above
when you instantiate a controller using ng-controller="myController" a new scope object is created to be used with your controller object. the $scope object that you have passed as an argument to the constructor function of the controller has the newly created scope.
Here is an excerpt from angular documentation :
The properties contain the view model (the model that will be presented by the view). All the $scope properties will be available to the template at the point in the DOM where the Controller is registered.
so basically whatever properties you attach to the $scope object only will be avalaible to be manipulated in DOM
any property you attach to this wont be available in the DOM. for example :
this is you angular configuration :
angular.module('myModule').controller('myController',['$scope',function($scope){
$scope.name = 'kiran'
this.message = 'hello world';
}]);
This is your html :
<p>{{name}}</p>
Output will be : kiran.
if you had tried : <p>{{message}}</p> instead it will throw an error.
only the scope object contains properties like $$watchers which is a list of all the variables that are watched on the current scope, $watch API,$on API for event handling and so on.
so you cannot use this to leverage those properties.Hope this clears stuff up.
Related
I have a controller name as string and I want to get constructor of it.
My current method is using $controller as below:
$scope.myControllerConstructor= $controller( "myControllerName" , {$scope: $scope.$new()}).constructor;
Later on, I use this constructor in the html like this:
<div ng-controller="myControllerConstructor">
The issue is my controller runs two time, one time when I get the constructor (which is wrong) and one time when my html gets compiled (which is correct)
The question is how to get the controller constructor without running it?
Update about use-case: In our application we have many pages with 60% similarities and 40% different activities. I created a directive for those pages and other developers in the team are using my directive to create their page.
The directive accepts a template and a controller (I get them as string) and later on I include the provided template and controller as below:
<div ng-include="myTemplate" ng-controller="myControllerConstructor"></div>
Please take a look at this jsfiddle for a simple example of issue.
The structure of your code looks ok but the issue is $controller( "myControllerName" , {$scope: $scope.$new()}) already instantiate the controller with the given scope for you.
It is true that you can access the controller constructor with .constructor but it is too late as you already created an instance of the controller.
ng-controller does the exact same thing as $controller( "myControllerName" , {$scope: $scope.$new()})
When a Controller is attached to the DOM via the ng-controller
directive, AngularJS will instantiate a new Controller object, using
the specified Controller's constructor function. A new child scope
will be created and made available as an injectable parameter to the
Controller's constructor function as $scope.
To solve this issue you should pass the controller constructor function to pageDirectiveTemplate instead of the controller name.
The working fiddle
There is a different way we can achieve this. In directive, while using isolated scope (like you are doing here in fiddle), you could have a property controller that has value "#" and have another name property having the value of "myController" or whatever your controller name you are passing as.
So, your directive could look something like this:
app.directive('pageDirective', function() {
return {
restrict: "A",
templateUrl: "pageDirectiveTemplate",
scope: {
myTemplate: "#"
},
controller: "#",
name: "myController"
}
});
Notice that, only change in HTML would be to have the directive as an attribute instead of an element. So,
<div page-directive my-template="templateA" my-controller="controllerA">
</div>
<div page-directive my-template="templateA" my-controller="controllerB">
</div>
This would give you exactly what you are looking for. Now you can have same template pointing different controllers and vice-versa.
working fiddle | Note that it works for two different controllers having same template. Also, check the console to see how it logs only once from each controller.
I am registering a controller on the state object by giving it a function. However the controller depends on things like $scope,$rootScope, and a couple of other services. How can I make the notation work if I am passing it a function? The solution should also work if the code is minified.
Here is my code
var mod = angular.module('myApp',['ui.router']);
mod.config(['$urlRouterProvider','$stateProvider',function(u,$stateP){
$stateP.state('myState',{
controller : controllerFunction //this is the controller that has dependencies.
})
}]);
As a side note -- I know there exist a resolve property that can be used to pass dependencies, but how can I pass $scope when it isn't defined, etc.
Even though the documentation states otherwise (look at the controller property) the controller property will happily take an inline array of dependencies with the controller function being the last index like so.
{
controller : ['$scope','$http',...,controllerFunction];
}
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
I am following this best practice style guide for angular development and I can't seem to get this one part working cleanly.
Best Practice Style Guide:
https://github.com/johnpapa/angular-styleguide
It recommends to declare controllers by the following:
angular
.module('app')
.controller('feedController', FeedController);
function feedController(){
var vm = this; //My $scope variable
}
The problem is I am trying to use $on to add an event listener but it gives me an undefined error for vm.$on. A temporary solution I found was to inject $scope into the controller by the following:
FeedController.$inject = ['apiservice', '$scope'];
and call $scope.$on which works but I feel its inconsistent now. Is there a way to still use vm in a clean way.
You can see the full controller here https://github.com/bliitzkrieg/TrailerFeed/blob/master/app/components/feed/FeedController.js
this/vm refers to the instance of the controller, not the scope that is associated with that controller.
Events only exist on scopes, so to use the event system it is correct to inject $scope to get a reference to the controller's scope where $on is available.
angular
.module('app')
.controller('feedController', FeedController);
function feedController($scope){
var vm = this; // the instance of the controller
$scope.on(...) // the controller's scope
}
I have a MainController and a PageController. The MainController manages data and gets a $scope,$http as a parameter. I use it like ng-controller="MainController"
I use PageController to manage the tabs on the website, so it has like this.setTab and this.isTabSelected and I use it like ng-controller="PageController as pager".
if I use the alias 'as XXY' I can't seem to access $scope, can I only use $scope WHILE using as and referring to as pager.setTab?
My Goal is to $emit a notification when the page changes, but I can not use $scope and not refer pager, because pager is the global controller (root scope basically) so it is like this:
... ng-controller="PageController as pager" ...
.......ng-controller="MainController" .........
Any clearance on $scope in combination with 'as XXY' and this. Thanks
The controllerAs syntax is the preferred syntax for AngularJS. When you use this syntax you do not bind controllers to templates using the $scope directly. Instead use instance methods and properties of the controller.
The $scope is still used within the controller to bind and emit events, watchers, and call $apply().