I have this module routes:
var mainModule = angular.module(\'lpConnect\', []).
config([\'$routeProvider\', function ($routeProvider) {
$routeProvider.
when(\'/home\', {template:\'views/home.html\', controller:HomeCtrl}).
when(\'/admin\', {template:\'views/admin.html\', controller:AdminCtrl}).
otherwise({redirectTo:\'/connect\'});
}]);
Home HTML:
<div ng-include src=\"views.partial1\"></div>
partial1
HTML:
<form ng-submit=\"addLine()\">
<input type=\"text\" ng-model=\"lineText\" size=\"30\" placeholder=\"Type your message here\">
</form>
HomeCtrl
:
function HomeCtrl($scope, $location, $window, $http, Common) {
...
$scope.views = {
partial1:\"views/partial1.html\"
};
$scope.addLine = function () {
$scope.chat.addLine($scope.lineText);
$scope.lines.push({text:$scope.lineText});
$scope.lineText = \"\";
};
...
}
In the addLine
function $scope.lineText
is undefined
, this can be resolved by adding ng-controller=\"HomeCtrl\"
to partial1.html
, however it causes the controller to be called twice. What am I missing here?
This is because of ng-include
which creates a new child scope, so $scope.lineText
isn’t changed. I think that this
refers to the current scope, so this.lineText
should be set.
As @Renan mentioned, ng-include creates a new child scope. This scope prototypically inherits (see dashed lines below) from the HomeCtrl scope. ng-model=\"lineText\"
actually creates a primitive scope property on the child scope, not HomeCtrl\'s scope. This child scope is not accessible to the parent/HomeCtrl scope:
To store what the user typed into HomeCtrl\'s $scope.lines array, I suggest you pass the value to the addLine function:
<form ng-submit=\"addLine(lineText)\">
In addition, since lineText is owned by the ngInclude scope/partial, I feel it should be responsible for clearing it:
<form ng-submit=\"addLine(lineText); lineText=\'\'\">
Function addLine() would thus become:
$scope.addLine = function(lineText) {
$scope.chat.addLine(lineText);
$scope.lines.push({
text: lineText
});
};
Fiddle.
Alternatives:
- define an object property on HomeCtrl\'s $scope, and use that in the partial:
ng-model=\"someObj.lineText
; fiddle
- not recommended, this is more of a hack: use $parent in the partial to create/access a
lineText
property on the HomeCtrl $scope: ng-model=\"$parent.lineText\"
; fiddle
It is a bit involved to explain why the above two alternatives work, but it is fully explained here: What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
I don\'t recommend using this
in the addLine() function. It becomes much less clear which scope is being accessed/manipulated.
Instead of using this
as the accepted answer suggests, use $parent
instead. So in your partial1.html
you\'ll have:
<form ng-submit=\"$parent.addLine()\">
<input type=\"text\" ng-model=\"$parent.lineText\" size=\"30\" placeholder=\"Type your message here\">
</form>
If you want to learn more about the scope in ng-include
or other directives, check this out: https://github.com/angular/angular.js/wiki/Understanding-Scopes#ng-include
I\'ve figured out how to work around this issue without mixing parent and sub scope data.
Set a ng-if
on the the ng-include
element and set it to a scope variable.
For example :
<div ng-include=\"{{ template }}\" ng-if=\"show\"/>
In your controller, when you have set all the data you need in your sub scope, then set show to true
. The ng-include
will copy at this moment the data set in your scope and set it in your sub scope.
The rule of thumb is to reduce scope data deeper the scope are, else you have this situation.
Max