Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Losing scope when using ng-include

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?

like image 754
Shlomi Schwartz Avatar asked Jul 10 '12 11:07

Shlomi Schwartz


People also ask

Does Ng-include create a new scope?

In this case, where you need to load templates from other domains or other protocols, then you can add them to your trusted resource URL list, which will set the url as a trusted url in your application. The ng-include directive is executed at priority level -400 and creates new scope every time it is invoked.

What is required with Ng-include directive?

The ng-include directive includes HTML from an external file. The included content will be included as childnodes of the specified element. The value of the ng-include attribute can also be an expression, returning a filename. By default, the included file must be located on the same domain as the document.

What does ng scope do?

$scope is a child object that is used to bind the HTML(view) & Javascript(Controller) in a webpage. It is created with the ng-app directive. It is created with the ng-controller directive. It is available globally for all the controllers, i.e, the property assigned with “$rootscope” can be used anywhere.


2 Answers

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:

ng-include 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.

like image 169
Mark Rajcok Avatar answered Oct 01 '22 06:10

Mark Rajcok


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.

like image 45
Renan Tomal Fernandes Avatar answered Oct 01 '22 07:10

Renan Tomal Fernandes