Losing scope when using ng-include
Solution 1
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.
Solution 2
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
});
};
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.
Solution 3
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
Solution 4
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
Related videos on Youtube
Shlomi Schwartz
Updated on September 07, 2020Comments
-
Shlomi Schwartz over 3 years
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
isundefined
, this can be resolved by addingng-controller="HomeCtrl"
topartial1.html
, however it causes the controller to be called twice. What am I missing here? -
Jess over 10 yearsI used objects, but they scope was still masked. I tried
$parent.
and it worked great. Why do you consider it a hack? (I can see it would add maintenance if you refactored your html) -
qbert65536 over 10 yearsSame question @Jess had , why is this considered a hack ?
-
Mark Rajcok over 10 years@qbert65536, it is essentially a hack/fragile because if you restructure your HTML, it might not work anymore. E.g., you might then need to use
$parent.$parent...
to get it to work. Put another way, using$parent
makes assumptions about the DOM structure. -
Chris Yeung about 10 yearsI was having the same problem! Thanks for the detailed explanation
-
mraaroncruz almost 10 years@Jess' link above has been changed to this Understanding Scopes ngInclude. Read the whole page, it's great.
-
grammar over 9 yearsThank you for this. I think this should be the accepted answer. Using
this
feels like a hack in Angular terms -
Sebastialonso about 9 yearsFor any reader, he means
$scope.$parent
instead of$parent
is undefined according to Angular. -
Derek Webb almost 9 yearsThis answer saves the day for me! Thanks so much for pointing out the use of $parent.
-
OMGPOP almost 9 yearsis $scope.$parent pass by reference? or it's just a copy of parent?
-
OMGPOP almost 9 years@Sebastiallonso is wrong. $scope.$parent.lineText is undefined. $parent.lineText is working, this.lineText or simply just lineText are also working
-
Isaias Soares almost 9 yearsI has going crazy about this. Thank for the detailed explanation @MarkRajcok! +1
-
radtek about 8 yearsIts
$scope.$parent
that works for me in angular 1.3.20 -
Zargold about 8 years@Sebastialonso is right and so is OMGPOP: in the directive or html $scope.$parent is $parent if you are referring to it inside a controller it is $scope (or in a directive typically 'scope').$parent... Inside html $scope is already passed so it would make it look like $parent is right but officially it is $scope.$parent
-
zahra about 8 yearsThis is a great detailed answer, but I tried all of them without any success. I have a form with some input to a controller and the result of a controller should be viewed on another div. Once I enter any input the synchronicity will be lost and I will have a constant 0.00 value on the view div while the app is running.
-
iSpithash over 4 yearsI'm using this approach for a similar issue but it's not proper for all cases. Especially when you want the included element to never get hidden...