Reputation: 10021
I'm trying to figure out how controller inheritance works. I have three controllers:
var myApp = angular.module('app', []);
myApp.controller('MainController', ['$scope', function($scope) {
$scope.name = 'main';
$scope.getName = function() {
return $scope.name;
};
}]);
myApp.controller('Child1', ['$scope', function($scope) {
$scope.name = 'child1';
}]);
myApp.controller('Child2', ['$scope', function($scope) {
$scope.name = 'child2';
}]);
and my view
<div ng-app='app'>
<div ng-controller='MainController'>
<div ng-bind='getName()'></div>
<div ng-controller='Child1'>
<div ng-bind='getName()'></div>
<div ng-controller='Child2'>
<div ng-bind='getName()'></div>
</div>
</div>
</div>
</div>
but they're all showing "main". How do I fix this?
here's a fiddle http://jsfiddle.net/g3xzh4ov/3/
Upvotes: 1
Views: 243
Reputation: 3825
If you want to overwrite name property in child scopes ,convert your primitive name property into object.
$scope.user = {};
$scope.user.name='main';
$scope.getName = function() {
return $scope.user.name;
};
And you should read https://github.com/angular/angular.js/wiki/Understanding-Scopes for detailed information.
Upvotes: 0
Reputation: 222548
Here's an example of how controllers can be extended in Angular.
myApp.service('baseCtrl', function () {
this.name = 'base';
this.getName = function() {
return this.name;
};
});
myApp.controller('MainController', ['baseCtrl', function (baseCtrl) {
angular.extend(this, baseCtrl);
this.name = 'main';
}]);
myApp.controller('Child1', ['baseCtrl', function (baseCtrl) {
angular.extend(this, baseCtrl);
this.name = 'child1';
}]);
myApp.controller('Child2', ['baseCtrl', function (baseCtrl) {
angular.extend(this, baseCtrl);
this.name = 'child2';
}]);
It obliges to use controllerAs
, which replaces $scope
with this
, it is especially good for such cases.
Notice the usage of service
instead of other Angular service types, it uses new
under the hood, so this...
statements can be brought right from a controller to separate service.
There are several ways of doing controller inheritance. Here is another approach.
Regarding the original code, there is no 'controller iheritance' in Angular. And $scope
prototypical inheritance assumes that
$scope.getName = function() {
return $scope.name;
};
returns $scope.name
from the context where it was defined, it is MainController
function in your case.
Upvotes: 2
Reputation: 4471
The problem that you're facing is actually based on core Javascript functionality.
You see, the confusion that you're facing stems from the mix of scoping, and prototypical inheritance. The properties are copied over, but the scoping remains the same, preventing you from accessing the variables that you expect to be able to access. To understand this better, perhaps instead of $scope
, we can look at a simpler variable:
myApp.controller('MainController', ['$scope', function($scope) {
var a = 1;
$scope.getName = function() {
console.log(a); // -> 1
console.log(b); // Error! `Uncaught ReferenceError: b is not defined`
};
}]);
myApp.controller('Child1', ['$scope', function($scope) {
var b = 2;
}]);
Obviously, MainController
doesn't know that Child1
defined some variable called b
, so it errors. That variable is strictly out of lexical scope.
Likewise, if we renamed b
to a
, it won't turn the value in MainController
to 2. This demonstrates exactly what's happening for you: you have three things called $scope
, and only one is in the lexical scope.
Two options to fix it:
1) use this
:
$scope.getName = function() {
return this.name;
};
The this
solution works because of how Javascript determines "this" based on context. Basically, since it's attached to a given $scope
Object, that Object's a good candidate. But Mozilla can explain this better than I can, so view their page on the topic here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
2) Otherwise, you can simply pass the $scope
:
$scope.getName = function(item) {
return item.name;
};
Upvotes: 1