Reputation: 33
I have recently started to learn and use AngularJS and I'm still unclear about some concept.
My question is this: in my app I have a controller which uses $http
to retrieve data from my back-end as soon as it is initialised. Following the excellent tutorial from CodeSchool on Angular I came up with this:
app.controller("agentController", function ($http) {
var agentsCtrl = this;
agentsCtrl.agents = [];
$http.get("getAgents").success(function (data) {
agentsCtrl.agents = data;
});
...
HTML:
<div ng-controller="agentController as agentCtrl">
<div ng-repeat="agent in agentCtrl.agents">
...
This works fine, but I'm unclear on why I would need to declare the controller as a variable within itself using this
. From what I understand it's because by doing this I can then call it within the $http
service, where the this
keyword would return the wrong scope. Is this correct?
I found that this also works:
app.controller("agentController", function ($http, $scope) {
$scope.agents = [];
$http.get("getAgents").success(function (data) {
$scope.agents = data;
});
HTML:
<div ng-controller="agentController as agentCtrl">
<div ng-repeat="agent in agents">
...
I guess this works because I explicitly inject the scope and use it within the service. Also, the HTML is now slightly different. In the first case I need to explicitly call agentCtrl.agents
, while with scope simply call on agents
. This is still because the variable is now declared on the scope rather than the controller? Is this correct?
What is the best practice to use in similar cases?
Thank you!
Upvotes: 3
Views: 171
Reputation: 6968
This is for answering your comment to Ben Diamant's answer.
The less traditional alias syntax (as Alias
) simplifies your code and probably makes clearer what you're trying to do to somebody reading your code.
From ng-controller spec:
Using
controller as
makes it obvious which controller you are accessing in the template when multiple controllers apply to an element.
If you are writing your controllers as classes you have easier access to the properties and methods, which will appear on the scope, from inside the controller code.
- Since there is always a . in the bindings, you don't have to worry about prototypal inheritance masking primitives.
Check out also this awesome explanation of the advantages of alias syntax.
Among those advantages one the most important is that the alias syntax allows you to
refer to the controller we wish to refer to and stop worrying about the subtleties of scope inheritance.
I hope it helps.
Upvotes: 1
Reputation: 7958
The this keyword is contextual and when used within a function inside a controller may change its context. Capturing the context of this avoids encountering this problem.
Eg:
app.controller('MainCtrl', function() {
this.test = 'test';
angular.forEach(testArray, function (item) {
console.debug(this.test);
});
});
this.test is undefined as the scope of this has changed.
Using a variable fixes it:
app.controller('MainCtrl', function() {
var vm = this;
vm.test = 'test';
var testArray = [
1, 2, 3, 4
];
angular.forEach(testArray, function (item) {
console.debug(vm.test);
});
});
Original statement taken from John Papa's style guide
Upvotes: 1
Reputation: 6770
Question 1:
You have to save the reference to scope var agentsCtrl = this
because your are creating a anonymous function to be used as a callback. When you do it the context variable (this
) will be window.
app.controller("agentController", function ($http) {
// this == your controller
var agentsCtrl = this;
$http.get("getAgents").success(function (data) {
// Anonymous function
// this == Window Object
});
});
Question 2:
$scope is the glue between application controller and the view. you can reference it as a global variable that you can have access both from view and from controllers.
$scope.agents = []; // From controller
And
{{ agents }} // From view (you don't need to specify the $scope variable)
I prefer to give an alias for the controler and use it in my HTML as you did in
<div ng-controller="agentController as agentCtrl">
<div ng-repeat="agent in agents">
...
But both ways are correct and will work fine.
Upvotes: 1
Reputation: 6206
You are asking regard 2 different approach - "Controller as" or "$scope".
Original usage for scope binding would be:
<div ng-controller="MainController">
{{ someObj.someProp }}
</div>
app.controller('MainController', function ($scope) {
$scope.someObj = {
someProp: 'Some value.'
};
});
Using this technique you can use the bind as follows:
<div ng-controller="MainController as main">
{{ main.someProp }}
</div>
app.controller('MainController', function () {
this.someProp = 'Some value.'
});
Both work and, both fine. The major difference is preference.
Still, most of the community prefers 'Controller as', why?
Upvotes: 2