I am trying to use the controllerAs
property on a $routeProvider
route without any success.
Here is the sample code:
var app = angular.module('app', ['ngRoute']);
app.config(['$routeProvider', '$locationProvider',
function($routeProvider) {
$routeProvider
.when('/', {
template:'<div>This should be visible:{{ ctrl.one }}</div><div>This should not:{{ one }}</div>',
controller: 'Ctrl',
controllerAs: 'ctrl',
});
}]);
app.controller('Ctrl', function($scope) {
$scope.one = 'actual';
});
Not sure if this is a bug or I am doing something wrong, This is a plnkr that demonstrates the issue
Actual problem:
You seem to be using controllerAs
(assigning a value of 'ctrl'
) originally, but then later not making use of it in the rest of your code. (you used $scope
)
Solution:
Working demo as per your sample
When I've been using the controllerAs
syntax you need to use one of the following pattern(s) to get access to the instance of the controller:
As opposed to appending the property to $scope
, you have to bind to the controller scope. Note this is different to $scope
. For lack of a better term, you need to bind controller itself (think of it as its context). As we're dealing with the display layer or view model, I tend to use var vm = this;
as a convention, but this personal preference.
[A]: Preferred Solution
app.controller('Ctrl', function() {
this.one = 'actual';
});
//or using 'vm' convention
app.controller('Ctrl', function() {
var vm = this;
vm.one = 'actual';
});
[B]
app.controller('Ctrl', function() {
var vm = {};
vm.one = 'actual';
return vm;
});
Explanation:
When I first started using Angular, [B] was the approach that I used, purely coming from a Knockout background. I was used to binding to a "container" object then binding the object to the view. That being said, I prefer to use [A], or append directly to $scope
and forgo the alias completely. Reasons:
Just as a visual:
Demo
app.controller('Ctrl', function($scope) {
var vm = this;
vm.one = 'actual';
console.log($scope)
});
Passing in the $scope
object and further inspecting it, you'll see a new ctrl
child object containing all your public properties and functions that was bound to vm
inside the controller code. This is because you've assigned var vm = this
. Meaning the vm
object in the code is referencing the controller's own scope, which ultimately gets bound to the view. controllerAs
basically groups all properties and functions contained internal to the controller to a new object named after the alias that you've provided.
To be clear--because I don't think the accepted answer was explicit--the problem with your example is that even though you are assigning a value to controllerAs
you are bypassing it by still using $scope
.
The "vm" approach stands for view-model which is just a convention, but IMO is far more representative of what is actually going on than "$scope". All we're really trying to do here is bind the view to the view model.
That being said you can technically use both controllerAs AND normal $scope at the same time plunk.
Additionally, the difference between Rohan's examples A and B is that A is the way you should be doing it because you are able to leverage JavaScript's prototypal inheritance which is conducive to better perf. It's also worth noting that because you are now using controllerAs and this you no longer need to inject $scope.
// Functioning Example
var app = angular.module('app', ['ngRoute']);
app.config(['$routeProvider', '$locationProvider',
function($routeProvider) {
$routeProvider
.when('/', {
template:'<div>This should be visible:{{ vm.one }}</div><div>This should not:{{ one }}</div>',
controller: 'Ctrl',
controllerAs: 'vm',
});
}]);
app.controller('Ctrl', function() {
this.one = 'actual';
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With